更新情報
2022/1/1 : CUDAに対応しました。動作確認はできていないですが、Ar-Rayさんのdarknet_rosがコンパイルできました。( https://github.com/Ar-Ray-code/darknet_ros_fp16.git )
はじめに
今回は前回の記事の応用で、QEMUを使わない純粋なROSのクロスコンパイル環境を構築することを目指します。基本的には、今回の方法でかなりのパッケージでクロスコンパイルができると思います。
今回の方法は、Raspberry Pi用などで公式で書かれているROSのベースパッケージのクロスコンパイルとは異なり、ユーザーが自前のROSパッケージをあたかもx86_64のPCで開発しているかのようにJetson用のaarch64のクロスコンパイルを行うことを目指しています。
環境の準備
環境の構築は前回の記事と途中まではほとんど同じです。
前回も書きましたが、純粋なクロスコンパイルを行う場合においても基本的に実機のrootfsがないとコンパイルすることはできません。
ですので、ROSをクロスコンパイルする際には、rootfs内に必要なパッケージをインストールしておく必要があるため、ここまではほとんど前回の手順と変わりません。
まず、Hostの環境でJetpackの中身をコピーしておきます。
SDカードのイメージをダブルクリックしてマウントしてコピーをしていきます。
mkdir ~/jetpack
cd <SDカードイメージのマウント先>
sudo cp -raf ./* ~/jetpack/
SDイメージのマウントなどを自動化したい人は、以下のようにするとマウントできます。
mkdir ~/sd
sudo mount -t ext4 -o loop,offset=<offset*512> sd-blob.img ~/sd/
オフセットを調べるには以下のコマンドでSDのイメージのパーティションのStartのセクタを調べて、512をかけたものをoffsetに設定します。
fdisk -l sd-blob.img
Device Start End Sectors Size Type
sd-blob.img1 1187840 35266559 34078720 16.3G Linux filesystem
sd-blob.img2 2048 133119 131072 64M Linux filesystem
......
続いて、Dockerの環境でクロスコンパイル環境を構築するため、前回も使用した以下のコンテナ作成と使用をすることができるスクリプト等の一式を使用します。
cd ~
git clone https://github.com/tatsuyai713/jetson_cross_docker.git
cd jetson_cross_docker
コンテナのセットアップを行います。
./launch_container.sh setup
セットアップが完了すると、自動でコンテナ内に入っている状態となります。
コンテナ内であるかどうかはBashで表示されているhostnameがhostname-Dockerとなっていることから判断できます。
exitで出た後に2回目に入る時は
./launch_container.sh
コミットする時は
./launch_container.sh commit
でコミットできます。
また、このコンテナでは、HOSTのHomeディレクトリをhost_homeというフォルダの以下にマウントします。
コンテナ内での環境構築1
それでは、コンテナ内で以下の作業を継続していきます。
HomeフォルダにQEMU関連のセットアップのスクリプトがあるので実行します。
./configure.sh
続いて、JetPackの中身の環境を構築するために、chrootを用いて、設定していきます。
まずは、展開したフォルダに移動し、必要なフォルダをマウントします。
cd ~/host_home/jetpack/
sudo cp /usr/bin/qemu-aarch64-static usr/bin
sudo cp -b /etc/resolv.conf etc
sudo mount -o bind /dev dev
sudo mount -o bind /proc proc
sudo mount -o bind /sys sys
続いて、chrootでJetPack内に入ります。
sudo LC_ALL=C chroot .
ここでは、あたかもJetPackの中にいるように操作することができますが、rootでしか操作できません。それによる警告等表示されますが、無視して問題ありません。
まずは、aptが正しく実行できるように、以下のファイルを編集し、となっているところをt194に変更します。
vi /etc/apt/sources.list.d/nvidia-l4t-apt-source.list
deb https://repo.download.nvidia.com/jetson/t194 r32.6 main
それでは、ここからはROSの環境のセットアップになります。
開発しているパッケージに依存関係のあるROSのパッケージなどはこのタイミングでインストールしておきましょう。また、この作業は後でもう一度行うこともできますので、新しいパッケージを作成する際に、ros-melodic-xxxというパッケージが必要になった場合は、またrootfsでchrootを使ってインストールしましょう。ここでは、ros-melodic-desktop-fullだけをインストールしておきます。
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt install -y curl
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
sudo apt update
sudo apt install -y ros-melodic-desktop-full
sudo apt install -y python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential python-catkin-tools
source /opt/ros/melodic/setup.bash
sudo rosdep init
rosdep update
これでrootfsの準備は完了です。exitで抜けて以下のコマンドを実行しておきましょう。
sudo umount sys proc dev
sudo rm usr/bin/qemu-aarch64-static
sudo mv etc/resolv.conf~ etc/resolv.conf
コンテナ内での環境構築2
まだもう少しコンテナ内の準備が必要なので、環境構築を続けていきます。
まず、先ほどのDockerコンテナ作成用のgitリポジトリにクロスコンパイル用のcmakeの設定ファイルが入っていますので、コピーしておきます。
cp ~/host_home/jetson_cross_docker/Toolchain-L4T.cmake ~/
続いて、クロスコンパイル用のgccを以下から取得し、展開しておきます。
cd ~
wget http://releases.linaro.org/components/toolchain/binaries/7.3-2018.05/aarch64-linux-gnu/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
tar xf gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
mv gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu l4t-gcc
今回こちらを使用すると#include_nextでコンパイルエラーが発生することがあるので、以下のコマンドで修正をしておきます(これでよいかはよくわからないですが)
sed -i -e 's/include_next/include/' ~/l4t-gcc/aarch64-linux-gnu/include/c++/7.3.1/cmath
sed -i -e 's/include_next/include/' ~/l4t-gcc/aarch64-linux-gnu/include/c++/7.3.1/cstdlib
sed -i -e 's/include_next/include/' ~/l4t-gcc/aarch64-linux-gnu/include/c++/7.3.1/bits/std_abs.h
続いて、コンテナ環境にcatkin関連のパッケージをインストールしていきます。この際にrosのパッケージは特にインストールする必要はありません。(この作業はいらないようにするかもしれません)
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt install curl
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
sudo apt update
sudo apt install -y python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential python-catkin-tools python-vcstool cmake python-empy
ここまでの作業が完了しましたら、ROS用のクロスコンパイル環境にしていくための作業を進めていきます。作業内容から分かると思いますが、このコンテナ内で以下の設定を行うと、今後このコンテナではaarch64でのコンパイルしかできなくなるので、ご注意ください。
まず、JetPack内のシンボリックリンクが切れてしまっているので、シンボリックリンクを作り直します。今回はlibrtのみのシンボリックリンクの修正のみになっていますが、他のlibファイルでも起こる可能性が高いですので、No such fileが出た場合はこのシンボリックリンクの修正を行うようにしてください。
cd ~/jetpack/etc/alternatives
ls -al ./ | awk '{print "sudo ln -nfs ~/host_home/jetpack" $11 " " $9}' | xargs -i bash -c 'eval {}'
cd ~/jetpack/usr/lib/aarch64-linux-gnu
ls -al | grep alternatives | awk '{print "sudo ln -nfs ~/host_home/jetpack" $11 " " $9}' | xargs -i bash -c 'eval {}'
sudo rm ~/host_home/jetpack/usr/lib/aarch64-linux-gnu/librt.so
sudo ln -s ~/host_home/jetpack/lib/aarch64-linux-gnu/librt.so.1 ~/host_home/jetpack/usr/lib/aarch64-linux-gnu/librt.so
続いて、JetPack内のaarch64のlibファイルをコンテナ内で呼べるようにシンボリックリンクを作成します。
sudo ln -s ~/host_home/jetpack/usr/lib/aarch64-linux-gnu /usr/lib/aarch64-linux-gnu
sudo ln -s ~/host_home/jetpack/lib/aarch64-linux-gnu /lib/aarch64-linux-gnu
sudo ln -s ~/host_home/jetpack/lib/ld-linux-aarch64.so.1 /lib/ld-linux-aarch64.so.1
ライブラリによっては、/usr/libに直接配置されてしまうものもあるため、soファイルがないというエラーが出た場合は以下のように手動でシンボリックを張っておきます。
sudo ln -s ~/host_home/jetpack/usr/lib/libPocoFoundation.so /usr/lib/libPocoFoundation.so
続いて、/opt/ros以下についてもJetPack内のものを参照するように、以下の通りシンボリックリンクを張ります。
sudo mv /opt/ros /opt/ros_x86_64
sudo ln -s ~/host_home/jetpack/opt/ros /opt/ros
自前開発のROSパッケージをクロスコンパイルする
それではいつも通り、以下のようにワークスペースを作成しsrcフォルダ以下に自前のパッケージを配置します。
今回は、私の作ったROSでSocketCANを使うものを例に挙げて進めます。
mkdir -p ./catkin_ws/src
cd catkin_ws/src
source /opt/ros/melodic/setup.bash
catkin_init_workspace
git clone https://github.com/tatsuyai713/ros_socket_can_driver.git
cd ..
続いて、ビルド用のスクリプトを作成します。
vi ./build.sh
#!/bin/bash
PWD=$(pwd)
export LANG=C
source /opt/ros/melodic/setup.bash
catkin build \
--cmake-args \
-DCMAKE_TOOLCHAIN_FILE=${PWD}/../Toolchain-L4T.cmake \
-DCMAKE_CROSS_COMPILE_PREFIX=${PWD}
実行権限を与えて、
chmod +x ./build.sh
./build.sh
これで、クロスコンパイル完了です。あとはこのフォルダごと丸々tarballでかためてscpで実機にデプロイするなり煮るなり焼くなりしていただければと思います。
また、catkin_makeな方は以下のコマンドでもビルドできますので、こちらでも良いです。
source /opt/ros/melodic/setup.bash
export CMAKE_CROSS_COMPILE_PREFIX=$PWD
catkin_make DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=~/Toolchain-L4T.cmake
まとめ
ということで、今回はJetson用のROSパッケージの作成を純粋なクロスコンパイル環境で実現する方法について書きました。では、また。