ROS2用のラズパイ環境構築 2022

これは東工大ロボット技術研究会のアドベントカレンダー [rogy Advent Calendar 2022](https://adventar.org/calendars/7915) 22日目の記事です。
ラズパイの環境構築に関する知見がそれなりにまとまったので共有します。

::: note warn

この記事では[ROS2 Humble](https://docs.ros.org/en/humble/index.html)のインストール方法を紹介していますが、将来の変更でこの方法は使えなくなる可能性があります。

:::

---

## やることの詳細

- Raspberry Pi (4B)を使う
- Ubuntu Server 22.04 64-bitをインストールする
    - ヘッドレス、つまりラズパイをディスプレイに繋げないでやる
- そのUbuntu Server上にROS2 Humbleを入れる

## OSを焼く

microSDの容量は16~64GBあたりが好ましいです。

### Raspberry Pi Imagerを入手

microSDに色々と設定済みのOSを焼けるRaspberry Pi Imagerを使います。

- https://www.raspberrypi.com/software/

OS | インストール方法
--- | ---
Windows | ↑のサイトからダウンロードして開く
macOS | [`brew install --cask raspberry-pi-imager`](https://formulae.brew.sh/cask/raspberry-pi-imager)
Ubuntu | `sudo snap install rpi-imager`

:::note warn

以降のRaspberry Pi Imagerのスクリーンショットは古いバージョンで撮影したものです。現在は異なるウィンドウが表示される可能性があります。

:::

### フォーマット

microSDに重要なデータが存在しないことを確認してからmicroSDをフォーマットします。Raspberry Pi Imagerを開き、OS選択画面で「削除」、書き込み先選択画面で適切なmicroSDを選び、「書き込む」ボタンを押すことでフォーマットが始まります。

![rpi-imager-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497362/c401fe8f-8cd4-dbb2-9c06-491cff3867a9.png)

### Ubuntu Serverをインストール

Raspberry Pi Imagerを開き、OS選択画面で*Other general-purpose OS → Ubuntu*と進み、"Ubuntu Server 22.04.1 LTS (64-bit)"を選びます。

:::note warn
↓の3点が少し紛らわしいので気をつけてください。

- Desktopを選んでいないか
- バージョンは22.10になっていないか(22.04になっているか)
- 64-bitのものを選んでいるか
:::

書き込みを始める前に、初期ユーザー等の基本設定をします。Raspberry Pi Imagerのウィンドウ右下にある歯車:gear:ボタンを押して、↓の5つを設定します。

項目 | 内容
--- | ---
ホスト名 | チェックを入れてよしなに設定する
SSH | パスワード認証を選択する
ユーザー名とパスワード | チェックを入れてよしなに
Wi-Fi | **チェックを入れない**(後で設定する)
ロケール設定 | タイムゾーンはAsia/Tokyo, キーボードはjp

:::note
Wi-Fiにチェックを入れないのは複数Wi-Fiの登録を容易にするためです。
:::

ここで設定したホスト名、ユーザー名、パスワードは後で使用するので覚えておきましょう。

![rpi-imager-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497362/809321d2-2efa-d5a2-6a6f-def048be31a9.png)

設定が完了したらmicroSDにイメージを書き込んでください。

### Wi-Fi設定

書き込みが完了したらmicroSDをパソコンに差し直す。`system-boot`という名前でマウントされるはずなので、その中の`network-config`というファイルを↓のように編集します。

```yaml:network-config
# long-long-comments

version: 2
ethernets:
  eth0:
    dhcp4: true
    optional: true
wifis:
  wlan0:
    dhcp4: true
    optional: true
    access-points:
      "wifi-ssid":
        password: "raw-wifi-password"
```

設定例がコメントアウトされて示されているはずなので、そのコメントを外して自分のWi-Fi設定に書き換えましょう。

:::note
`wifi-ssid`に登録したいWi-FiのSSID, `raw-wifi-password`に登録したいWi-Fiのパスワードを(そのまま)入れてください。コメントアウトには複数のWi-Fi設定が書かれているはずなので、登録したいWi-Fiが複数ある場合も設定例に従えばうまく行きます。
:::

![network-config.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497362/5ce0ece5-c23c-61c2-189e-cc18777dea6c.png)

:::note
ここではVimで編集している画面を出しましたが、VSCodeなどお好みのエディタで編集しましょう。
:::

## SSH接続

### 起動確認

ラズパイに電源を入れて、数分経ってから`ssh user@hostname.local`を実行して接続します。`user`, `hostname`はイメージを焼くときに設定したユーザー名、ホスト名に置き換えてください。

:::note
以前に同じホスト名でラズパイを起動した経験がある場合は`ssh-keygen -R hostname.local`を実行することで以前のホストの情報を消せます
:::

パスワード入力を求められるが、**キーボードを叩いてもシェルに反映されない**ので注意が必要です。SSHでログインしたシェルは`exit`で閉じられます。

### 接続先省略

接続のたびに`user@hostname.local`で接続先を指定するのは面倒なので、接続先を省略できるように設定しましょう。`~/.ssh/config`に次のように記述することで`user@hostname.local`を`hoge`に省略することが可能になります。

```ssh:~/.ssh/config
Host hoge
    Hostname hostname.local
    User user
```

### 鍵登録

SSH接続するたびにパスワードを入力するのは面倒なので、SSH公開鍵を登録することでパスワード入力を省略できるようにします。

:::note
以前にSSHのRSA鍵を生成していない場合は`ssh-keygen -t rsa`を実行して生成してください。このコマンドを実行すると鍵の場所、パスワードが聞かれるが全てデフォルト(場所は`~/.ssh/id_rsa`、パスワードはなし)でいいです。コマンドを実行してからエンターを3回押したら鍵生成が完了します。

また、ここではローカルの鍵をラズパイに渡す方針を取っていますが、GitHubに鍵を公開している場合は`ssh user@hostname.local`でラズパイに(パスワード)ログインしてから次のコマンドで鍵を与えることができます。

```bash
curl -sSL https://github.com/me.keys >> ~/.ssh/authorized_keys
```

(`me`は自分のGitHub IDで置き換えてください)
:::

`scp ~/.ssh/id_rsa.pub user@hostname.local:/home/user/`を実行してSSH公開鍵をラズパイに送信します。(前述の省略設定を施している場合は`user@hostname.local`を`hoge`に省略できます)

:::note warn
Windowsではこのコマンドでエラーが出るかもしれません。その場合は`cd $HOME`を実行してから、または新しくターミナルを開き直してから`scp ./.ssh/id_rsa.pub user@hostname.local:/home/user/`を実行するといいです。
:::

`ssh hoge`でラズパイにログインして、次のコマンドを順に実行します。これでラズパイにSSH公開鍵が登録され、SSH接続のたびにパスワードを入力する必要がなくなります。

```bash
$ mkdir -p ~/.ssh
$ cat ~/id_rsa.pub >> ~/.ssh/authorized_keys
$ rm ~/id_rsa.pub
```

![first-ssh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497362/cc821860-c112-0457-562c-44b426036f66.png)

↑の画像では左側でラズパイにログインして公開鍵の登録、右側で手元のmacの`~/.ssh/config`の表示、および`scp`を用いた鍵送信を行なっています。

## apt関連

aptとは、インストールされているパッケージの管理を行なってくれるソフトウェア、いわゆるパッケージマネージャーです。Ubuntuで何かソフトウェアを追加する際には**ほぼ必ず**aptを使用します。

### パッケージ更新

**これはラズパイを起動するたびに行いましょう。**

```bash
$ sudo apt update
$ sudo apt upgrade  # アップグレード可能なパッケージがある場合
```

### 必須のパッケージ群

これは最初に一回やればいいです。

```bash
$ sudo apt install build-essential cmake git locales curl wget gnupg lsb-release python3 python3-pip vim
```

## ROS2インストール

### ロケール設定

`UTF-8`をサポートしているものであればなんでもいいらしいので`ja_JP.UTF-8`でも良さそうですが、避けられるエラーは極力避けたいので`en_US.UTF-8`に設定します。

```bash
$ sudo locale-gen en_US.UTF-8
$ sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
$ export LANG=en_US.UTF-8
$ locale  # verify settings
```

### リポジトリ追加

`apt-cache policy | grep universe`で次のような文字列が出力に入っていることを確認します。(`jammy`が合っていれば他は気にしなくても多分大丈夫です)

```
500 http://us.archive.ubuntu.com/ubuntu jammy/universe amd64 Packages
    release v=22.04,o=Ubuntu,a=jammy,n=jammy,l=Ubuntu,c=universe,b=amd64
```

:::note
入っていなければ↓のコマンドを実行しましょう。

```bash
$ sudo apt install software-properties-common
$ sudo add-apt-repository universe
```

:::

ROS2のリポジトリをaptに追加します。

```bash
$ sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(source /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
```

### インストール

ついでに[colcon](https://colcon.readthedocs.io/en/released/)も入れてしまいます。

```bash
$ sudo apt-get update && sudo apt-get upgrade
$ sudo apt install ros-humble-desktop python3-colcon-common-extensions
```

### 起動時設定

次の3行を`~/.bashrc`に追加して、シェル起動時にROS2, colcon_cdの設定が読み込まれるようにします。

```bash
source /opt/ros/humble/setup.bash
source /usr/share/colcon_cd/function/colcon_cd.sh
export _colcon_cd_root=/opt/ros/humble/
```

:::note info
追加方法がわからない場合は↓のコマンドを順に実行しましょう。

```bash
$ echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
$ echo "source /usr/share/colcon_cd/function/colcon_cd.sh" >> ~/.bashrc
$ echo "export _colcon_cd_root=/opt/ros/humble/" >> ~/.bashrc
```

:::

### 起動確認

シェル1

```bash
$ ros2 run demo_nodes_cpp talker
```

シェル2

```bash
$ ros2 run demo_nodes_cpp listener
```

シェル3(なくてもいい)

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

↓のように、`talker`での`Hello, world: n`が`listener`側にも出ていたら成功です。

![ros2-demo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497362/bbd47f2f-e921-24c3-5e2b-49416f21b4a6.png)

コマンド停止は`ctrl + C`でできます。

## tips

### ログアウト/再起動/シャットダウン

- SSH接続を閉じる場合: `exit`
- ラズパイを再起動させる場合: `sudo reboot`
- ラズパイをすぐにシャットダウンさせる場合: `sudo shutdown now`

再起動/シャットダウンではSSH接続が急に切れるが(多分)問題はないです。

### X11 Forwarding

SSHでGUI転送ができるようになります。

- [windows標準ssh(openssh)だけを用いてLinuxサーバから画面をX転送する。 - Qiita](https://qiita.com/tama14142356/items/be7b93fcce8978173ffd)
- [X11 ForwardingしてMacにGUI表示する - Qiita](https://qiita.com/loftkun/items/37340745f211ea5d7ece)

Linuxでなければ以下のソフトをインストールする必要があるので注意してください。

- Windows ... [VcxSrv](https://sourceforge.net/projects/vcxsrv/)
- Mac ... [XQuartz](https://www.xquartz.org/)

### tmux

- [tmuxを必要最低限で入門して使う - Qiita](https://qiita.com/shin-ch13/items/9d207a70ccc8467f7bab)
- [tmux - ArchWiki](https://wiki.archlinux.jp/index.php/Tmux)
- [Home · tmux/tmux Wiki](https://github.com/tmux/tmux/wiki)
- [Getting Started · tmux/tmux Wiki](https://github.com/tmux/tmux/wiki/Getting-Started)

1つのウィンドウに複数パネルを配置したり、セッションをバックグラウンドに移せたりする便利なやつです。時間がかかるコマンドはこいつで切り離してあげるのがおすすめです。

### VSCodeのRemote SSH

- [Visual Studio Code で Remote SSH する。 - Qiita](https://qiita.com/nlog2n2/items/1d1358f6913249f3e186)
  SSHの鍵生成、`~/.ssh/config`の編集、接続先への鍵入力はすでにやっているのでそれ以外をやればできます
- [Developing on Remote Machines using SSH and Visual Studio Code](https://code.visualstudio.com/docs/remote/ssh)

パソコン内の環境で開発しているのと同じ感覚でRaspberry Piの環境での開発が可能になります。

## 参考文献

- https://zenn.dev/aruneko/articles/bab667eb3d39cd
- https://rabbit-note.com/2020/06/06/raspberry-pi-ubuntu-headless-install/
- https://www.raspberrypi.com/documentation/computers/getting-started.html#advanced-options
- https://ubuntu.com/tutorials/how-to-install-ubuntu-on-your-raspberry-pi#1-overview
- https://docs.ros.org/en/rolling/Releases/Release-Humble-Hawksbill.html
- https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html
- https://docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Colcon-Tutorial.html