カムロボでROS2するぞ 【環境構築】

ROS2を勉強する時の備忘録です。
何番煎じだという感もありますが残しておきます。
[こちらのRTさんの記事]("https://rt-net.jp/mobility/archives/15692")のままですが残していきます。
更新頻度はかなり遅いと思いますが、頑張って書いていきたいと思います。

流れは以下の感じです。

1. カムロボでROS2するぞ 【環境構築】 ← 本記事
2. カムロボでROS2するぞ 【まずはgpioだけでカムロボを動かす】
3. カムロボでROS2するぞ 【ROS2化してみる】

# 構成

Raspberry PI 3B+
タミヤ カムロボ
ubuntu 20.04.02 64bit

# OSのインストール

以下よりubuntu 20.04 のイメージをダウンロードし、SDに書き込みます。
自分は[Etcher]("https://www.balena.io/etcher/")というソフトで書き込みました。

Raspberry PI にSDカードを挿入し起動するとログインのプロンプトが表示されます。
初期状態は、アカウントもパスワードもともに「ubuntu」です。

アカウント・パスワードを入力すると新しいパスワードの変更を求められるので、パスワードを新しくします。

# ROS2のセットアップ

今入れるならfoxy かなということでfoxyを入れます。
手順は[公式]("https://docs.ros.org/en/foxy/Installation/Linux-Install-Debians.html")に従ってインストールします。
公式に手順だと、rosdepのインストールがされないので、できるように python3-rosdep もインストールしておきます。
なんでなくなったんだろう？入れなくてもいいってこと？

```bash
#set locale
locale  # check for UTF-8

sudo apt update && sudo apt install -y locales
sudo locale-gen en_US 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

#setup sources
sudo apt update && sudo apt install -y curl gnupg2 lsb-release
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
sudo 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'

#install ROS2 foxy package
sudo apt update
sudo apt install -y ros-foxy-desktop python3-rosdep
sudo rosdep init
rosdep update
```

# wifi の設定

こちらの記事を参考にnetplanでwifiの設定をします。
/etc/netplan/50-cloud-init.yaml は人間が触るファイルじゃないらしいです。

https://qiita.com/yas-nyan/items/9033fb1d1037dcf9dba5

上記記事では、指定はしていないですが、systemd-networkd を指定するために
renderer に「networkd」を設定しています。

optinal はnetworkd のみがサポートしているらしいですが、どうも起動時にnetworkdが待たずにすぐに起動することができるようになるらしく、良さそうなのでtrue に設定しています。

https://www.komee.org/entry/2018/06/13/170000#optionalbool

```yaml:99-config.yaml
network:
  version: 2
  renderer: networkd

  wifis:
    wlan0:
      dhcp4: true
      optional: true
      access-points:
        SSID:
          password: "PASSWORD"
```

# gpio 制御用にpigpio の設定 

色々見ると、gpioを操作するにはpigpio が決定版のようです。
からあげ先生おすすめです。

https://karaage.hatenadiary.jp/entry/2017/02/10/073000

上記記事では、apt でインストールできるとのことだったのですが、apt search で出てきたのが
pigpio じゃなかったので、ソースから入れました。

```bash
$ apt search pigpio
Sorting... Done
Full Text Search... Done
libpigpiod-if-dev/focal 1.68-4 arm64
  Development headers for client libraries for Raspberry Pi GPIO control

libpigpiod-if1/focal 1.68-4 arm64
  Client library for Raspberry Pi GPIO control (deprecated)

libpigpiod-if2-1/focal 1.68-4 arm64
  Client library for Raspberry Pi GPIO control

pigpio-tools/focal 1.68-4 arm64
  Client tools for Raspberry Pi GPIO control

python3-pigpio/focal 1.68-4 all
  Python module which talks to the pigpio daemon (Python 3)
```

## pigpio をソースからのインストール

ソースは以下の最新バージョン v79 をインストールしました。

https://github.com/joan2937/pigpio

手順は公式に書いてあるとおりに実施しました。

http://abyz.me.uk/rpi/pigpio/download.html

```bash
$ cd /tmp
$ curl -LO https://github.com/joan2937/pigpio/archive/v79.tar.gz
$ tar -zxvf v79.tar.gz
$ cd pigpio-80
$ make
$ make install
```

動作確認です。

<details><summary>※ 実行結果</summary><div>

```bash
$ pwd
/tmp/pigpio-79
$ sudo ./x_pigpio

Testing pigpio C I/F
pigpio version 79.
Hardware revision 10625154.
Mode/PUD/read/write tests.
TEST  1.1  PASS (set mode, get mode: 0)
TEST  1.2  PASS (set pull up down, read: 1)
TEST  1.3  PASS (set pull up down, read: 0)
TEST  1.4  PASS (write, get mode: 1)
TEST  1.5  PASS (read: 0)
TEST  1.6  PASS (write, read: 1)
PWM dutycycle/range/frequency tests.
TEST  2.1  PASS (set PWM range, set/get PWM frequency: 10)
TEST  2.2  PASS (get PWM dutycycle: 0)
TEST  2.3  PASS (set PWM dutycycle, callback: 0)
TEST  2.4  PASS (get PWM dutycycle: 128)
TEST  2.5  PASS (set PWM dutycycle, callback: 40)
TEST  2.6  PASS (set/get PWM frequency: 100)
TEST  2.7  PASS (callback: 400)
TEST  2.8  PASS (set/get PWM frequency: 1000)
TEST  2.9  PASS (callback: 4000)
TEST  2.10 PASS (get PWM range: 255)
TEST  2.11 PASS (get PWM real range: 200)
TEST  2.12 PASS (set/get PWM range: 2000)
TEST  2.13 PASS (get PWM real range: 200)
PWM/Servo pulse accuracy tests.
TEST  3.1  PASS (get servo pulsewidth: 500)
TEST  3.2  PASS (set servo pulsewidth: 40000)
TEST  3.3  PASS (get servo pulsewidth: 1500)
TEST  3.4  PASS (set servo pulsewidth: 13333)
TEST  3.5  PASS (get servo pulsewidth: 2500)
TEST  3.6  PASS (set servo pulsewidth: 8000)
TEST  3.7  PASS (set/get PWM frequency: 1000)
TEST  3.8  PASS (set PWM range: 200)
TEST  3.9  PASS (get PWM dutycycle: 20)
TEST  3.10 PASS (set PWM dutycycle: 200)
TEST  3.11 PASS (get PWM dutycycle: 40)
TEST  3.12 PASS (set PWM dutycycle: 400)
TEST  3.13 PASS (get PWM dutycycle: 60)
TEST  3.14 PASS (set PWM dutycycle: 600)
TEST  3.15 PASS (get PWM dutycycle: 80)
TEST  3.16 PASS (set PWM dutycycle: 800)
Pipe notification tests.
TEST  4.1  PASS (notify open/begin: 0)
TEST  4.2  PASS (notify pause: 0)
TEST  4.3  PASS (notify close: 0)
TEST  4.4  PASS (sequence numbers ok: 1)
TEST  4.5  PASS (gpio toggled ok: 1)
TEST  4.6  PASS (number of notifications: 80)
Waveforms & serial read/write tests.
TEST  5.1  PASS (callback, set mode, wave clear: 0)
TEST  5.2  PASS (pulse, wave add generic: 4)
TEST  5.3  PASS (wave tx repeat: 9)
TEST  5.4  PASS (callback: 50)
TEST  5.5  PASS (wave tx stop: 0)
TEST  5.6  PASS (serial read open: 0)
TEST  5.7  PASS (wave clear, wave add serial: 3405)
TEST  5.8  PASS (wave tx start: 6811)
TEST  5.9  PASS (NOT APPLICABLE: 0)
TEST  5.10 PASS (NOT APPLICABLE: 0)
TEST  5.11 PASS (wave tx busy, serial read: 0)
TEST  5.12 PASS (serial read close: 0)
TEST  5.13 PASS (wave get micros: 6158148)
TEST  5.14 PASS (wave get high micros: 6158148)
TEST  5.15 PASS (wave get max micros: 1800000000)
TEST  5.16 PASS (wave get pulses: 3405)
TEST  5.17 PASS (wave get high pulses: 3405)
TEST  5.18 PASS (wave get max pulses: 12000)
TEST  5.19 PASS (wave get cbs: 6810)
TEST  5.20 PASS (wave get high cbs: 6810)
TEST  5.21 PASS (wave get max cbs: 25016)
TEST  5.22 PASS (wave create pad, count==1, wid==: 0)
TEST  5.23 PASS (wave create pad, count==2, wid==: 1)
TEST  5.24 PASS (delete wid==0 success: 0)
TEST  5.25 PASS (No more CBs using wave create: -67)
TEST  5.26 PASS (wave create pad, count==3, wid==: 0)
TEST  5.27 PASS (wave chain [1,0]: 0)
TEST  5.28 PASS (callback count==: 5)
Trigger tests
TEST  6.1  PASS (gpio trigger count: 5)
TEST  6.2  PASS (gpio trigger pulse length: 150)
Watchdog tests.
TEST  7.1  PASS (set watchdog on count: 39)
TEST  7.2  PASS (set watchdog off count: 0)
Bank read/write tests.
TEST  8.1  PASS (read bank 1: 0)
TEST  8.2  PASS (read bank 1: 33554432)
TEST  8.3  PASS (clear bank 1: 0)
TEST  8.4  PASS (set bank 1: 1)
TEST  8.5  PASS (read bank 2: 0)
TEST  8.6  PASS (clear bank 2: 0)
TEST  8.7  PASS (NOT APPLICABLE: 0)
TEST  8.8  PASS (set bank 2: 0)
TEST  8.9  PASS (NOT APPLICABLE: 0)
Script store/run/status/stop/delete tests.
TEST  9.1  PASS (store/run script: 100)
TEST  9.2  PASS (run script/script status: 201)
TEST  9.3  PASS (run/stop script/script status: 110)
TEST  9.4  PASS (delete script: 0)
```
</div></details>

大丈夫なようなので、デーモンで動かしてテストします。

<details><summary>※ 実行結果</summary><div>

```bash
$ sudo pigpiod
$ ./x_pigpiod_if2

Testing pigpiod C I/F 2
pigpio version 79.
Hardware revision 10625154.
Mode/PUD/read/write tests.
TEST  1.1  PASS (set mode, get mode: 0)
TEST  1.2  PASS (set pull up down, read: 1)
TEST  1.3  PASS (set pull up down, read: 0)
TEST  1.4  PASS (write, get mode: 1)
TEST  1.5  PASS (read: 0)
TEST  1.6  PASS (write, read: 1)
TEST  1.7  PASS (pigpio_start with non-default arguments: 31)
PWM dutycycle/range/frequency tests.
TEST  2.1  PASS (set PWM range, set/get PWM frequency: 10)
TEST  2.2  PASS (get PWM dutycycle: 0)
TEST  2.3  PASS (set PWM dutycycle, callback: 0)
TEST  2.4  PASS (get PWM dutycycle: 128)
TEST  2.5  PASS (set PWM dutycycle, callback: 40)
TEST  2.6  PASS (set/get PWM frequency: 100)
TEST  2.7  PASS (callback: 400)
TEST  2.8  PASS (set/get PWM frequency: 1000)
TEST  2.9  PASS (callback: 4000)
TEST  2.10 PASS (get PWM range: 255)
TEST  2.11 PASS (get PWM real range: 200)
TEST  2.12 PASS (set/get PWM range: 2000)
TEST  2.13 PASS (get PWM real range: 200)
PWM/Servo pulse accuracy tests.
TEST  3.1  PASS (get servo pulsewidth: 500)
TEST  3.2  PASS (set servo pulsewidth: 40000)
TEST  3.3  PASS (get servo pulsewidth: 1500)
TEST  3.4  PASS (set servo pulsewidth: 13333)
TEST  3.5  PASS (get servo pulsewidth: 2500)
TEST  3.6  PASS (set servo pulsewidth: 8000)
TEST  3.7  PASS (set/get PWM frequency: 1000)
TEST  3.8  PASS (set PWM range: 200)
TEST  3.9  PASS (get PWM dutycycle: 20)
TEST  3.10 PASS (set PWM dutycycle: 200)
TEST  3.11 PASS (get PWM dutycycle: 40)
TEST  3.12 PASS (set PWM dutycycle: 400)
TEST  3.13 PASS (get PWM dutycycle: 60)
TEST  3.14 PASS (set PWM dutycycle: 600)
TEST  3.15 PASS (get PWM dutycycle: 80)
TEST  3.16 PASS (set PWM dutycycle: 800)
Pipe notification tests.
TEST  4.1  PASS (notify open/begin: 0)
TEST  4.2  PASS (notify pause: 0)
TEST  4.3  PASS (notify close: 0)
TEST  4.4  PASS (sequence numbers ok: 1)
TEST  4.5  PASS (gpio toggled ok: 1)
TEST  4.6  PASS (number of notifications: 80)
Waveforms & serial read/write tests.
TEST  5.1  PASS (callback, set mode, wave clear: 0)
TEST  5.2  PASS (pulse, wave add generic: 4)
TEST  5.3  PASS (wave tx repeat: 9)
TEST  5.4  PASS (callback: 50)
TEST  5.5  PASS (wave tx stop: 0)
TEST  5.6  PASS (serial read open: 0)
TEST  5.7  PASS (wave clear, wave add serial: 3405)
TEST  5.8  PASS (wave tx start: 6811)
TEST  5.9  PASS (callback: 0)
TEST  5.10 PASS (wave tx busy, callback: 1702)
TEST  5.11 PASS (wave tx busy, serial read: 0)
TEST  5.12 PASS (serial read close: 0)
TEST  5.13 PASS (wave get micros: 6158148)
TEST  5.14 PASS (wave get high micros: 6158148)
TEST  5.15 PASS (wave get max micros: 1800000000)
TEST  5.16 PASS (wave get pulses: 3405)
TEST  5.17 PASS (wave get high pulses: 3405)
TEST  5.18 PASS (wave get max pulses: 12000)
TEST  5.19 PASS (wave get cbs: 6810)
TEST  5.20 PASS (wave get high cbs: 6810)
TEST  5.21 PASS (wave get max cbs: 25016)
TEST  5.22 PASS (wave create pad, count==1, wid==: 0)
TEST  5.23 PASS (wave create pad, count==2, wid==: 1)
TEST  5.24 PASS (delete wid==0 success: 0)
TEST  5.25 PASS (No more CBs using wave create: -67)
TEST  5.26 PASS (wave create pad, count==3, wid==: 0)
TEST  5.27 PASS (wave chain [1,0]: 0)
TEST  5.28 PASS (callback count==: 5)
Trigger tests.
TEST  6.1  PASS (gpio trigger count: 5)
TEST  6.2  PASS (gpio trigger pulse length: 150)
Watchdog tests.
TEST  7.1  PASS (set watchdog on count: 39)
TEST  7.2  PASS (set watchdog off count: 0)
Bank read/write tests.
TEST  8.1  PASS (read bank 1: 0)
TEST  8.2  PASS (read bank 1: 33554432)
TEST  8.3  PASS (clear bank 1: 0)
TEST  8.4  PASS (set bank 1: 1)
TEST  8.5  PASS (read bank 2: 0)
TEST  8.6  PASS (clear bank 2: 0)
TEST  8.7  PASS (clear bank 2: -42)
TEST  8.8  PASS (set bank 2: 0)
TEST  8.9  PASS (set bank 2: -42)
Script store/run/status/stop/delete tests.
TEST  9.1  PASS (store/run script: 100)
TEST  9.2  PASS (run script/script status: 201)
TEST  9.3  PASS (run/stop script/script status: 410)
TEST  9.4  PASS (delete script: 0)
```

</div></details>

バッチリ動作しています。

## pigpio をsystemdに登録

システムが起動したときに自動的に起動するようにsystemdに登録します。
こちらの記事を参考させていただきました。

https://qiita.com/genshibangou16/items/b577b03fe52d273b328f

以下のようなファイルを生成します。
※ 追記 2021-03-25 pigpiod の引数の -l はlocalhost only で外しました

```/etc/systemd/system/pigpiod.service
[Unit]
Description=Daemon required to control GPIO pins via pigpio
[Service]
#ExecStart=/usr/local/bin/pigpiod -l -m #Disable alerts
ExecStart=/usr/local/bin/pigpiod -m #Disable alerts
ExecStop=/bin/systemctl kill pigpiod
Type=forking

[Install]
WantedBy=multi-user.target
```

ファイルが生成できたら、以下のコマンドを実行しデーモンを起動させます。

```bash
$ sudo systemctl daemon-reload
$ sudo systemctl restart pigpiod
```

デーモンが起動していることを確認します。

```bash
$ sudo systemctl status pigpiod
● pigpiod.service - Daemon required to control GPIO pins via pigpio
     Loaded: loaded (/etc/systemd/system/pigpiod.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2021-03-15 15:21:51 UTC; 3min 23s ago
    Process: 1655 ExecStart=/usr/local/bin/pigpiod -l -m #Disable alerts (code=exited, status=0/SUCCESS)
   Main PID: 1662 (pigpiod)
      Tasks: 3 (limit: 974)
     CGroup: /system.slice/pigpiod.service
             └─1662 /usr/local/bin/pigpiod -l -m #Disable alerts

Mar 15 15:21:51 ubuntu systemd[1]: Starting Daemon required to control GPIO pins via pigpio...
Mar 15 15:21:51 ubuntu systemd[1]: Started Daemon required to control GPIO pins via pigpio.
```

デーモンが起動したことが確認できたところで、自動起動するように下記コマンドを実行します。

```bash
$ sudo systemctl enable pigpiod
```

再起動し、statusを確認し activeになっていれば完了です。
とりあえずはこれで環境は揃ったはずなので、次回よりカムロボを動かすようにしていこうと思います。
長くなりましたが、ここまでお付き合いしていただきありがとうございます。

# 追記 2021-03-25

raspberry pi にubuntuを乗せると、どうもデフォルトで省電力モードがonになっているようです。
そのため、調べごととかしているうちにwifiに接続できなくなってしまうため省電力モードを無効化します。

## 省電力の無効化

以下よりまずパッケージをインストールします。
※ wireless-tools はiwconfigで状態を見るためだけに入れてます。

```bash
$ sudo apt install -y wireless-tools pm-utils
```

無効化する前のwlan0の状態を見ると有効(Power Management:on)になっています。

```bash
$ iwconfig
lo        no wireless extensions.

wlan0     IEEE 802.11  ESSID:""
          Mode:Managed  Frequency:2.442 GHz  Access Point: 
          Bit Rate=72.2 Mb/s   Tx-Power=31 dBm
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Power Management:on
          Link Quality=70/70  Signal level=-28 dBm
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

eth0      no wireless extensions.

```

以下のコマンドで省電力化を無効にします。

```bash

$ sudo pm-powersave false
```


省電力化が無効(Power Management:off) になっていることが確認できます。
これで放っておいてもwifi が切れるということが防止できるはず。。。

```bash
$ iwconfig
lo        no wireless extensions.

wlan0     IEEE 802.11  ESSID:""
          Mode:Managed  Frequency:2.442 GHz  Access Point: 
          Bit Rate=72.2 Mb/s   Tx-Power=31 dBm
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Power Management:off
          Link Quality=70/70  Signal level=-28 dBm
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

eth0      no wireless extensions.
```