Raspberry Pi 3 + Ubuntu 20.04 + ROS2 foxy向けクロスコンパイル環境をDockerで構築する
前回の記事では動作確認用のROS2ノードをPythonで書いていましたが,実はrt-net / raspimouse2のソースをRaspberry Pi 3でビルドしようとするとraspimouseパッケージのビルドが25%で止まってしまっていたからでした。
別の環境ならうまく行くかも,ということでRaspberry Pi のROS2で動作するノードをC++で記述してx86 PCでビルドする環境を作ります。
qemu-user-staticでARM用のバイナリをx86命令へ変換しながら実行する仕組みを利用して,Raspberry Pi用のUbunru 20.04イメージをx86 PCで動作させます。その上にROS2をインストールして,あたかもPC上でRaspberry Pi用のROS2が動いているかのように見せかけます。環境はDockerで構築します。
手順
以下の手順でクロスコンパイル環境を構築します。
- DockerでARM用Ubuntu 20.04を動かす
- イメージをtarに固めてdocker importする
- インポートしたDockerイメージをもとにROS2環境を構築する
DockerでARM用Ubuntu 20.04を動かす
Raspberry PiへUbuntu 20.04 LTSをインストールするときに使用したイメージファイルをホストPCでマウントし,qemu-arm-static
を/usr/binへコピーします。
まずはイメージファイルからループバックデバイスを作成します。
$ sudo losetup -fP ubuntu-20.04.2-preinstalled-server-arm64+raspi.img $ dmesg | grep loop [ 0.113010] Calibrating delay loop (skipped), value calculated using timer frequency.. 5799.77 BogoMIPS (lpj=11599544) [ 0.631321] loop: module loaded [ 1644.919981] EXT4-fs (loop20): mounted filesystem with ordered data mode. Opts: (null) [ 2827.012874] EXT4-fs (loop20): mounted filesystem with ordered data mode. Opts: (null) [14031.188080] loop20: p1 p2
/dev/loop20に作成されたようです。
$ sudo fdisk -l /dev/loop20 ディスク /dev/loop20: 3.4 GiB, 3259499520 バイト, 6366210 セクタ 単位: セクタ (1 * 512 = 512 バイト) セクタサイズ (論理 / 物理): 512 バイト / 512 バイト I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト ディスクラベルのタイプ: dos ディスク識別子: 0x4ec8ea53 デバイス 起動 開始位置 最後から セクタ サイズ Id タイプ /dev/loop20p1 * 2048 526335 524288 256M c W95 FAT32 (LBA) /dev/loop20p2 526336 6366175 5839840 2.8G 83 Linux
loopデバイスが作成されており,ubuntu 20.04のイメージに含まれるLinuxパーティションは/dev/loop20p2
になっています。
ローカル環境に余計なものを入れたくないのでDockerコンテナを立ち上げ,適当なところ(ここでは/mnt)にマウントして作業します。
$ docker run --rm -it --privileged -v $(pwd):/home --name ubuntu ubuntu:20.04 # mount /dev/loop20p2 /mnt
作業用のコンテナ内でqemu-user-static
をインストールします。
# apt update # apt install -y qemu-user-static
qemu-user-staticでインストールされたコンテナ内の/usr/bin/qemu-arm-static
をイメージファイルの/usr/bin
にコピーします。
# cp /usr/bin/qemu-arm-static /mnt/usr/bin
修正したイメージファイルをtarに固めます。
# cd /mnt # tar cf /home/raspi-ubuntu-20.04.tar .
コンテナを終了し,作成したtarファイルのオーナーを変更しておきます。
$ sudo chown ユーザー名:ユーザー名 raspi-ubuntu-20.04.tar
tarファイルをDockerにインポートします。
$ docker import raspi-ubuntu-20.04.tar raspi-ubuntu:20.04
インポートしたイメージを起動します。
$ docker run -it --name raspi-ubuntu raspi-ubuntu:20.04 /bin/bash root@143d831747f9:/# arch aarch64
アーキテクチャはaarch64になっており,ARM用のUbuntu 20.04イメージが実行されています。
standard_init_linux.go:211: exec user process caused "exec format error"
というエラーが出たら以下を実行します。
$ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
ROS2のインストール
raspi-ubuntu:20.04イメージが作成できたら以下のようなDockerfileを作成してビルドします。
FROM raspi-ubuntu:20.04 RUN apt update && apt install -y curl gnupg2 lsb-release RUN curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | apt-key add - RUN sh -c 'echo "deb [arch=$(dpkg --print-architecture)] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/ros2-latest.list' RUN apt update && \ apt install -y ros-foxy-ros-base python3-colcon-common-extensions python3-pip && \ pip3 install -U argcomplete
$ docker build --rm -t raspi-ubuntu-ros2:foxy .
ビルドが完了したらコンテナを起動してみます。
$ docker run --rm -it raspi-ubuntu-ros2:foxy /bin/bash
ROS2のexampleを動かしてみて,ちゃんとROS2がインストールされていることを確認します。
raspimouse2のビルド
前回はできなかったraspimouse2のビルドをしてみます。
ホストPCでrt-net / raspimouse2のソースをcloneします。
$ mkdir -p ros2_ws/src $ cd ros2_ws/src $ git clone https://github.com/rt-net/raspimouse2.git
cloneしたソースをマウントしてコンテナを起動し,colcon build
を実行します。
$ docker run --rm -it -v $(pwd)/ros2_ws:/home raspi-ubuntu-ros2:foxy /bin/bash # source /opt/ros/foxy/setup.bash # cd /home # colcon build Starting >>> raspimouse_msgs Finished <<< raspimouse_msgs [12.2s] Starting >>> raspimouse [Processing: raspimouse] [Processing: raspimouse] [Processing: raspimouse] Finished <<< raspimouse [1min 54s] Summary: 2 packages finished [2min 8s]
正常にビルドできました。
動作確認
rt-net / raspimouse2のREADMEのQuick Startにしたがって動作確認します。
Raspberry Pi MouseにSSH接続し,以下のコマンドを実行します。
$ source ~/ros2_ws/install/setup.bash $ ros2 run raspimouse raspimouse
別のターミナルでRaspberry Pi MouseにSSH接続し,以下のコマンドを実行します。
$ source /opt/ros/foxy/setup.bash $ ros2 lifecycle set raspimouse activate
activateすると冒頭のgifのように光センサのLEDが点滅し始めます。
raspimouse2のソースをx86 PCでビルドして,Raspberry Pi Mouseを動かすことができました。