Raspberry Pi Zero WでROS2を動かす

# はじめに

Rasberry Pi Zero WでROS2を動かす環境構築の手順を整理します。

Raspberry Pi 3/4(と2の一部)は、64bitのAArch64が動作するCortex-A53/A72をCPUコアに持つため、64bit版のLinux(UbuntuやArmbian等)をインストールすることで、aptでパッケージインストールができ導入は比較容易です。

一方、Rasberry Pi Zero Wは初代のRasberry Piと同じARM11という32bitのCPUコアのため、3/4のようなaptの恩恵を受けることができず、ソースコードからのビルドを行う必要があります。

普通なら、この手間と非力なCPUパワーのためにRasberry Pi Zero WでROS2を動かそうとは思わないのですが、とあるLCDデバイスを動かすのにちょうどよく、ROS2のメッセージを電光掲示板のように出すデバイスを作ってみようと思い立ち、やってみようと思いました。
![majo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51272/df261da5-d3e5-e3ae-6665-a84defa5a626.jpeg)
- [マジョカアイリス　ハック　はじめます](https://azuzuzu.hatenablog.com/entry/2021/02/07/222648)

既にdockerでのクロスコンパイル環境を公開されている方がいらっしゃったので、それを使わせていただいてます。いくつか躓いた点があったので、ここでまとめておこうと思います。

# 対象とする環境

今回の対象となるRasberry Piの環境は以下となっています。

|項目|詳細|
|:----|:---|
|ハードウェア| Raspberry Pi Zero W Ver1.1|
|SDカード|16GB|
|イメージ| Raspberry Pi OS Lite(32bit)|
|カーネルバージョン|5.4.83+ #1379 Mon Dec 14 13:06:05 GMT 2020|

ROS2をソースからセルフビルドするにはRasberry Pi Zeroは非力なので、クロスコンパイルすることにします。

dockerでのクロスコンパイル環境構築や必要なソース取得のスクリプト類をGitで公開されいる方がいらっしゃるので、それを使います。

- https://github.com/cyberbotics/epuck_ros2/tree/master/installation/cross_compile

今回試したDockerの環境は以下となっています。自分の環境にあったものを用意ください。（Linuxの場合は、non-root userで動く設定をしておく旨のコメントがあります。）

|項目|詳細|
|:----|:---|
|ハードウェア| MacBook Air(11-inch, Mid 2013)|
|MacOS| Catalina|
|Docker Version|Desktop Community 3.0.1|

# クロスコンパイル環境の構築

基本的には、Gitにある手順に従って進めますので、詳しくはそちらをご覧ください。

- https://github.com/cyberbotics/epuck_ros2/tree/master/installation/cross_compile

ここでは、今回少しつまった点などを中心に整理します。

## Raspberry Pi側の準備

必要なパッケージを入れておきます。特にここでは問題なし。

## Docker環境の構築

まずは、Gitの以下のリポジトリをクローンします。

- https://github.com/cyberbotics/epuck_ros2.git

その後、dockerの構築環境がある以下のフォルダに移動します。

- epuck_ros2/installation/cross_compile/

そのフォルダにある`start_docker.sh`を実行すると、docker環境の構築が行われます。

## Rootfsの準備

クロスコンパイルするのに必要なファイル一式を、Raspberry Piからdocker上に持ってくる必要があります。rsyncとsshfsの２つの方法が書かれています。

最初、sshfsの方を試そうとしたのですが、permissionエラーになってうまく動きませんでした。

ので、rsyncの方法を試しました。

```
$ rsync -rLR --safe-links pi@[Raspberry PiのIPアドレス]:/{lib,usr,opt/vc/lib} /home/develop/rootfs
```

ここでも以下のようなメッセージがでますが、今回のクロスコンパイルには問題ないだろうということで、無視しました。

```
rsync: readlink_stat("/lib/modules/5.4.83+/build") failed: Permission denied (13)
rsync: readlink_stat("/lib/modules/5.4.83+/source") failed: Permission denied (13)
rsync: opendir "/lib/ssl/private" failed: Permission denied (13)
skipping non-regular file "lib/systemd/system/alsa-utils.service"
skipping non-regular file "lib/systemd/system/bootlogd.service"
skipping non-regular file "lib/systemd/system/bootlogs.service"
・・・
```

## ソースの取得とビルドの実施

次にソースの取得ですが、それ用のスクリプトが用意されているので実行しますが、ここで少し注意が必要です。

```
$ cross-initialize
```

で、ソース取得し、ビルドを実施しますが、そのままだとROS2のバージョンはFoxyとなっています。(bashrc.shをご覧あれ)

今回のRaspberry Piの環境ではFoxyでビルドしたものを実行すると、実行時に`undefined symbol: __atomic_load_8`のエラーが発生しました。
（LD_PRELOADを使って強制的に実行することはできましたが。）

Raspberry Pi OS Liteの`debian_version`を確認したところbusterでした。Ubuntuだと18.04になるのでその関係でしょうかね、ここはDashingに変更します。

```
$ export ROS_DISTRO=dashing
```

その後、ソースを取得して、ビルドを実行。

```
$ cross-colcon-build --packages-up-to ros2topic
```

すると、cycloneDDSのビルド時に以下のリンクエラーが発生して、途中でビルドが止まります。

```
・・・
/opt/cross-pi-gcc/lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: warning: libssl.so.1.1, needed by ../../../lib/libddsc.so.0.7.0, not found (try using -rpath or -rpath-link)
/opt/cross-pi-gcc/lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: warning: libcrypto.so.1.1, needed by ../../../lib/libddsc.so.0.7.0, not found (try using -rpath or -rpath-link)
・・・
```

FastRTPSはうまくビルドできるようなので、今回はcycloneDDSのソースを削除することで対処しました。ソースは`~/ros2_ws/src/eclipse-cyclonedds/`なので、そのディレクトリをざっくり消して、再度ビルドします。ビルドは約２時間かかりました。

## ビルド結果をRaspberry Piに戻す

ビルドができたら、`./ros2_ws/install `をRaspberry Piに戻します。

```
$ scp -r install pi@[Raspberry PiのIPアドレス]:/home/pi/ros2
```

コマンドにあるように、`/home/pi/ros2`に環境が構築されますので、

```
$ source ros2/local_setup.bash 
```

を実行することでros2のコマンドが使えるようになります。

## 動作確認

ROS2 Dashingが動く別の環境にて`demo_node_cpp`のtalkerを動かします。

```
$ ros2 run demo_node_cpp talker
```

そのあと、Raspberry Pi Zero Wにて

```
$ ros2 topic echo /chatter
```

とすると、無事トピックが受信されるのを確認できました。

# 最後に

とりあえず動作すること確認できましたので、いろいろ使ってみようと思います。

あと、cycloneDDSのエラーについては回避方法を探ってみようかと思っています。