連載記事

  1. NVIDIA Jetson Nano 2GBプレビューキットのセットアップ

前回までの記事で、Jetson Nano 2GBにJetPackが有効化されたDockerのコンテナランタイムのセットアップが完了しました。

今回はホストPCを使ってJetsonで動かすDockerイメージをビルドし、最新のROS 2ディストリビューションであるROS 2 Foxyの実行環境を整えるところまでをお届けします。

QEMUを使ったDockerイメージのマルチアーキテクチャビルド

前回も少しお伝えしたように、JetsonのOSはUbuntu 18.04をベースとしているため、最新のROS 2 Foxyを使うことができません。 Ubuntu 18.04に対応しているROS 2 Dashingは古くて必要なパッケージが足りませんし、ROS 2 EloquentはもうすぐEOLしてしまいます。

そこで、Dockerコンテナ内でROS 2 Foxyを動かせば、JetsonのOSバージョンに囚われることなく、最新ROS 2を使うことができます。 ただし、JetsonはホストPCに比べれば、CPU性能とRAM容量に課題があるため、Jetson単体でROS 2のDockerイメージを直接ビルドするのは困難です。スワップファイルを用意したり、シングルスレッドビルドにしたり、RAM容量に気を配る必要があります。 さらに、JetsonはARM CPUのARMv8 64ビットアーキテクチャであるため、普段使うホストPCのX86-64ビットアーキテクチャとは異なります。

ホストPCでDockerイメージを別のCPUアーキテクチャのものでビルドするには、QEMUを使ったCPUのエミュレーションが有効です。 QEMUをインストールした後、QEMUを使ってDockerイメージのマルチアーキテクチャビルドを有効化します。

$ sudo apt install qemu binfmt-support qemu-user-static
$ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
Setting /usr/bin/qemu-alpha-static as binfmt interpreter for alpha
Setting /usr/bin/qemu-arm-static as binfmt interpreter for arm
Setting /usr/bin/qemu-armeb-static as binfmt interpreter for armeb
Setting /usr/bin/qemu-sparc-static as binfmt interpreter for sparc
Setting /usr/bin/qemu-sparc32plus-static as binfmt interpreter for sparc32plus
Setting /usr/bin/qemu-sparc64-static as binfmt interpreter for sparc64
Setting /usr/bin/qemu-ppc-static as binfmt interpreter for ppc
Setting /usr/bin/qemu-ppc64-static as binfmt interpreter for ppc64
Setting /usr/bin/qemu-ppc64le-static as binfmt interpreter for ppc64le
Setting /usr/bin/qemu-m68k-static as binfmt interpreter for m68k
Setting /usr/bin/qemu-mips-static as binfmt interpreter for mips
Setting /usr/bin/qemu-mipsel-static as binfmt interpreter for mipsel
Setting /usr/bin/qemu-mipsn32-static as binfmt interpreter for mipsn32
Setting /usr/bin/qemu-mipsn32el-static as binfmt interpreter for mipsn32el
Setting /usr/bin/qemu-mips64-static as binfmt interpreter for mips64
Setting /usr/bin/qemu-mips64el-static as binfmt interpreter for mips64el
Setting /usr/bin/qemu-sh4-static as binfmt interpreter for sh4
Setting /usr/bin/qemu-sh4eb-static as binfmt interpreter for sh4eb
Setting /usr/bin/qemu-s390x-static as binfmt interpreter for s390x
Setting /usr/bin/qemu-aarch64-static as binfmt interpreter for aarch64
Setting /usr/bin/qemu-aarch64_be-static as binfmt interpreter for aarch64_be
Setting /usr/bin/qemu-hppa-static as binfmt interpreter for hppa
Setting /usr/bin/qemu-riscv32-static as binfmt interpreter for riscv32
Setting /usr/bin/qemu-riscv64-static as binfmt interpreter for riscv64
Setting /usr/bin/qemu-xtensa-static as binfmt interpreter for xtensa
Setting /usr/bin/qemu-xtensaeb-static as binfmt interpreter for xtensaeb
Setting /usr/bin/qemu-microblaze-static as binfmt interpreter for microblaze
Setting /usr/bin/qemu-microblazeel-static as binfmt interpreter for microblazeel
Setting /usr/bin/qemu-or1k-static as binfmt interpreter for or1k

docker runのログ出力に、aarch64があることがわかります。これがJetson NanoのCPUアーキテクチャです。 これにより、Dockerのベースイメージにaarch64のものを使ったり、そのベースイメージの上にROS 2をビルドすることができたりするようになります。 また、QEMUがインストールされているので、ホストPC上でそのイメージを実行してコンテナを作成することもできます。Jetson Nanoで動作確認する前に予備実験する際、とても便利です。

L4Tベースイメージ上にROS 2 Foxy環境構築

NVIDIA JetPackが有効化されたDockerイメージは、l4t-baseです。l4tはLinux for Tegraの略です。

https://ngc.nvidia.com/catalog/containers/nvidia:l4t-base

この上にROS 2 Foxy環境を構築することで、JetsonのGPUの恩恵に預かることのできるDockerコンテナが利用できるようになります。

本当は以下のように、Jetsonイメージl4t-baseaarch64用のROSイメージarm64v8/rosをマルチステージビルドで組み合わせて、必要なファイルなどをl4t-baseからコピーしてくれば一番楽です。

FROM nvcr.io/nvidia/l4t-base:r32.4.4 as l4t
FROM arm64v8/ros:foxy-ros-base as ros
...

ですが、どのファイルをコピーしなくてはならないのか把握することが困難だったので、諦めてl4t-base上に以下に沿ってソースコードビルドことを選びました。

https://index.ros.org/doc/ros2/Installation/Foxy/Linux-Development-Setup/

ソースコードビルドのためのDockerfileは、実はすでにNVIDIA Jetsonの開発者Dustin Franklinさんによって公開されており、それをビルドするだけで済みました。ありがたい。

https://github.com/dusty-nv/jetson-containers/blob/master/Dockerfile.ros.foxy

このとき、BASE_IMAGE引数をデフォルトのl4t-baseのものではなく、同じくDustyさんによって公開されているdustynv/jetson-inferenceイメージに変更しました。 これにより、Jetsonの深層学習を用いた推論ソフトウェアも合わせてセットアップされます。

$ docker build -t youtalk/ros:foxy-ros-base-l4t-r32.4.4 --build-arg BASE_IMAGE=dustynv/jetson-inference:r32.4.4 -f Dockerfile.ros.foxy .

ホストPCで16スレッド並列でビルドしても1時間半くらいかかりました。もしJetson Nano 2GBでビルドしていたら、1日以上かかっていたかもしれません。 ビルドしたイメージはDocker Hubにpushしてあるので、ご興味ある方はご利用ください。ビルド時間を省略できます。6GBあるのでディスク容量にご注意ください。

$ docker pull youtalk/ros:foxy-ros-base-l4t-r32.4.4

Jetson Nanoで動作確認をして、今日はお終いです。

$ docker run -it --rm --network host --runtime nvidia youtalk/ros:foxy-ros-base-l4t-r32.4.4 ros2 run demo_nodes_cpp talker
$ docker run -it --rm --network host --runtime nvidia youtalk/ros:foxy-ros-base-l4t-r32.4.4 ros2 run demo_nodes_cpp listener

次はCUDAを使った画像処理ROS 2ノードを実装します。