DockerコンテナからRaspberryPiのGPIO・I2C・シリアル通信を使う

#1.はじめに

Docker を触ったことがなかったので、勉強を兼ねて[ROS on Docker](https://hub.docker.com/_/ros) on Raspberry Piを試してみました。
ここでは、ROSのコンテナからRaspberry Pi 4 （3 B+もOK）のGPIOやI2C、それに関わるライブラリ（RPI.GPIO, WiringPi, Grove.Py, シリアル通信）が使える様にする方法をまとめました。

**20/5/17追記**：コンテナの中から、シリアル通信を使う場合の注意点を追記しました。
**21/1/3追記**：コンテナの中からファイルを生成するときに、rootではなくホスト側の一般ユーザにマッピングする方法を追記しました。


##実行環境

|||
|:--|:--|
|ハード|Raspberry Pi 3B+, Raspberry Pi 4B+|
|OS|Raspbian Buster|

※Raspbianのため、32bit環境(armhf)になります。（ROSの推奨は64bit）

#2.Dockerインストール

##(1)Docker公式の手順
RaspberryPiにDockerをインストールする手順は、こちら[^1]を参考にさせて頂きました。公式のインストールドキュメントはこちら[^2]です。

[^1]: https://qiita.com/soultoru/items/8fe75f70c568a074dbc3
[^2]: https://docs.docker.com/install/linux/docker-ce/debian

```sh:コマンドライン
$ sudo apt update && sudo apt upgrade -y
$ sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y
$ curl -sSL https://get.docker.com | sh
$ docker -v
Docker version 19.03.7, build 7141c19
$ sudo usermod -aG docker pi
```
ユーザ`pi`がグループ`docker`に入ったのを反映するため、一旦ログアウトして、再度ログインします。

動作チェックを行います。

```sh
$ docker run --rm hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
4ee5c797bcd7: Pull complete
Digest: sha256:6a65f928fb91fcfbc963f7aa6d57c8eeb426ad9a20c7ee045538ef34847f44f1
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
（･･･省略･･･）
```

##(2)Raspbianパッケージを使う手順

少し古いですが、Raspbianのパッケージでもインストールできます。（20年5月時点）

```sh
$ sudo apt install docker.io
$ docker -v
Docker version 18.09.1, build 4c52b90
```

##(3)docker-composeビルドとインストール

こちら[^3]を参考にさせて頂きました。

[^3]: https://qiita.com/tkyonezu/items/912fb7cfaab2f59276dd

```sh:コマンドライン
$ mkdir ~/gitwork
$ cd ~/gitwork
$ git clone https://github.com/docker/compose.git
$ cd compose
$ ./script/build/linux
（・・・ビルド、15～30分程度・・・）
$ ./dist/docker-compose-Linux-armv7l version
docker-compose version 1.26.0dev, build 3c89ff84
docker-py version: 4.2.0
CPython version: 3.7.6
OpenSSL version: OpenSSL 1.1.0l  10 Sep 2019
$
```

動作確認できたら、`/usr/local/bin/`に配置します。

```sh:コマンドライン
$ sudo cp ./dist/docker-compose-Linux-armv7l /usr/local/bin/docker-compose
$ sudo chown root:root /usr/local/bin/docker-compose
$ sudo chmod 755 /usr/local/bin/docker-compose
$ which docker-compose
/usr/local/bin/docker-compose
$
```


#3.コンテナを起動

GPIO、I2C、シリアル通信を使う時の引数（とその他）です。

```sh:コマンドライン
$ docker run --name ros2 -h ros2dk -v /home/pi/gitwork:/root/gitwork --device /dev/gpiomem  --device /dev/i2c-1 --device /dev/ttyACM0 --privileged -e TZ=Asia/Tokyo -it ros:eloquent
```

|引数|意味|
|:--|:--|
|-name ros2 |コンテナの名前をROS2にする|
|-h ros2dk|コンテナのホスト名をros2dkにする|
|-v <マウント元>:<マウント先>|ホストのディレクトリ（元）をコンテナ内のディレクトリにマウント（先）|
|--device /dev/gpiomem|GPIOデバイスに接続|
|--device /dev/i2c-1|I2Cデバイスに接続|
|--device /dev/ttyACM0|シリアル通信に接続|
|--privileged|特権モードで実行（表外に注釈） |
|-e TZ=Asia/Tokyo|環境変数を定義してタイムゾーンを日本に変更|
|-it|-i:標準入力を開き続ける、-t:疑似ttyを割りあて→docker runしたあとそのままコンテナに入れます|
|--rm|コンテナ終了時にコンテナを削除（例では指定していません）|
|ros:eloquent|イメージ名（2020年2月現在の最新はeloquent）|

[^4]: http://www.tohoho-web.com/docker/command.html
[^5]: https://qiita.com/curseoff/items/a9e64ad01d673abb6866

###「-v」オプション

Dockerがマウントした先のディレクトリには、ユーザ`root`としてファイルが書き出されます。root以外のユーザにする場合は、下記を参考にしました。

- [コンテナ内にホストと同じユーザを追加](https://qiita.com/yohm/items/047b2e68d008ebb0f001)
- [別のユーザにマッピング](https://qiita.com/kota7175/items/3f8218f5a7a18a8e0962)

またROSのdebugging infoを出力のため、`-v "/home/ubuntu/.ros/:/root/.ros/"`のように、`.ros`ディレクトリも必要に応じてマウントするのが望ましいです。

##「add_event_detect」と「--privileged」オプションについて
privilegedを有効にすると、コンテナならではの安全性がすっぽりなくなってしまうので、使用が推奨されないオプションです。[^10]

[^10]: https://blog.trendmicro.co.jp/archives/23577

ところが、Python3で`RPI.GPIO`を使用する際、GPIOの入力をイベントで取得する設定をする関数`GPIO.add_event_detect`を呼び出すと、下記のエラーが発生して、GPIOの入力をイベントで取得出来ませんでした。

```sh:実行例
GPIO.add_event_detect(PIN, GPIO.BOTH, handle)
 RuntimeError: Failed to add edge detection
```

いろいろ調べる[^2]と、--privilegedを有効にすることでこのエラーを回避出来ました。（add_event_detectを使わない場合は、このオプションは不要です）

[^2]: https://stackoverflow.com/questions/30059784/docker-access-to-raspberry-pi-gpio-pins


#4.コンテナに入って色々インストール

###（参考）コンテナの操作

ホスト側から、以下の操作をします。
コマンド一覧はこちら[^4]を、詳細はこちら[^5]を参考にさせて頂きました。

|やりたいこと|コマンド|
|:--|:--|
|コンテナの起動|$ docker start ros2|
|コンテナのプロセス確認|$ docker ps|
|コンテナの一覧（停止中含む）|$ docker ps -a|
|コンテナに入る|$ docker attach ros2|
|コンテナに入る（別ttyで接続）|$ docker exec -it ros2 bash |
|一時的にコンテナから抜ける（コンテナは動作しっぱなし）|（コンテナの中のシェルから）# [Ctrl-P] [Ctrl-Q]|
|コンテナを停止する|（コンテナの中のシェルから）# exit|
|コンテナを停止する|$ docker stop ros2 |
|コンテナを削除する|$ docker rm <コンテナID> |


##(1)RPI.GPIO

```sh:コマンドライン
# cd /var/gitwork
# apt update
# apt install python3-rpi.gpio -y
# i2cdetect -r -y 1
```

##(2)I2C

```sh:コマンドライン
# apt install i2c-tools python3-smbus -y
# i2cdetect -r -y 1
```

###I2Cの疎通確認

RTC(DS1307+ →0x68)とIOエキスパンダー(MCP23017-E/SP →0x20)が繋がってる例です

```sh:コマンドライン
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
```

##(3)WiringPi

途中、色々ワーニングが出ますが、インストールは出来ます。

> RaspberryPi4であっても、WiringPiを差し替える必要はありません。
[（参考）](https://qiita.com/myasu/items/a4e036a86976e3081a19#raspberry-pi-4-%E3%81%A7gpio%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E4%BD%BF%E3%81%86)

```sh:コマンドライン
# cd /var/gitwork
# git clone https://github.com/WiringPi/WiringPi
# cd WiringPi
# ./build 
wiringPi Build script
=====================
WiringPi Library
[UnInstall]
[Compile] wiringPi.c
[Compile] piHiPri.c
・・・（省略）
```

###GPIOの確認

```sh:コマンドライン
# gpio -v
gpio version: 2.60
Copyright (c) 2012-2018 Gordon Henderson
This is free software with ABSOLUTELY NO WARRANTY.
For details type: gpio -warranty

Raspberry Pi Details:
  Type: Pi 3B+, Revision: 03, Memory: 1024MB, Maker: Sony 
  * This Raspberry Pi supports user-level GPIO access.

# watch -n 1 gpio readall
 +-----+-----+---------+------+---+---Pi 3B+-+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 | ALT0 | 1 |  3 || 4  |   |      | 5v      |     |     |
 |   3 |   9 |   SCL.1 | ALT0 | 1 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 1 | ALT5 | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 1 | ALT5 | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
 |  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
 |  10 |  12 |    MOSI | ALT0 | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO | ALT0 | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK | ALT0 | 0 | 23 || 24 | 1 | OUT  | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 1 | OUT  | CE1     | 11  | 7   |
 |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
 |   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
 |   6 |  22 | GPIO.22 |   IN | 0 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
 |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
 |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
 |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
 |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+---Pi 3B+-+---+------+---------+-----+-----+

#GPIOの出力動作チェック
~ $ gpio -g mode 6 out ; gpio -g mode 13 out ; gpio -g mode 19 out ; gpio -g mode 26 out
~ $ gpio -g write 6 1 ; gpio -g write 13 1 ; gpio -g write 19 1 ; gpio -g write 26 1
~ $ gpio -g write 6 0 ; gpio -g write 13 0 ; gpio -g write 19 0 ; gpio -g write 26 0
```

##(4)Grove.py

Seeed社から販売されている、GROVE規格のコネクタを増設するボードです。
すごく使いやすいので、便利に活用してます。
http://wiki.seeedstudio.com/Grove_Base_Hat_for_Raspberry_Pi/

```sh:コマンドライン
# cd /var/gitwork
# git clone https://github.com/Seeed-Studio/grove.py
Cloning into 'grove.py'...
remote: Enumerating objects: 5, done.
・・・（省略）・・・
```

```sh:コマンドライン
# cd grove.py/
# pip3 install .
Processing /root/download/grove.py
Requirement already satisfied: RPi.GPIO in /usr/lib/python3/dist-packages (from grove.py==0.6)
Collecting rpi_ws281x (from grove.py==0.6)
  Downloading https://files.pythonhosted.org/packages/3b/b3/cdc84887ead3f15b9f3f2b5fe2b48168757a606c6d08feb53536a8afb396/rpi_ws281x-4.2.2.tar.gz (65kB)
    100% |████████████████████████████████| 71kB 1.4MB/s 
Collecting smbus2 (from grove.py==0.6)
・・・（省略）・・・
Successfully built rpi-ws281x smbus2
Installing collected packages: rpi-ws281x, smbus2, grove.py
  Running setup.py install for grove.py ... done
Successfully installed grove.py-0.6 rpi-ws281x-4.2.2 smbus2-0.3.0
```

##(5)USB経由のシリアル通信

RaspberryPiのUSBコネクタにArduinoを接続して、USB経由で通信[^7][^8]することを想定します。

[^7]: https://armadillo.atmark-techno.com/blog/10899/4191
[^8]: https://www.it-swarm.dev/ja/docker/docker%E3%83%9B%E3%82%B9%E3%83%88usb%E3%81%BE%E3%81%9F%E3%81%AF%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%81%B8%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%82%92%E8%A8%B1%E5%8F%AF%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%EF%BC%9F/1047354239/


まずは、ターミナルの`cu`を使って通信してみます。

```sh
root@rosdk:~/# apt install cu -y
root@rosdk:~/# cu -s 115200 -l /dev/ttyACM0
cu: open (/dev/ttyACM0): Permission denied
cu: /dev/ttyACM0: Line in use
```

接続できません。
処置の方法[^aa]を探したところ、コンテナ内の`/dev/ttyACM0`のパーミッションの変更で接続出来るようです。

[^aa]: https://blog.nownabe.com/2018/06/05/1321.html/

```sh
#現状のパーミッションを確認
root@rosdk:~/# ls -l /dev/ttyAC*
crw-rw---- 1 root dialout 166,  0 May 18 01:01 /dev/ttyACM0
#その他ユーザの読み書き権限を追加
root@rosdk:~/# chmod 666 /dev/ttyACM0
#追加後のパーミッションを確認
root@rosdk:~/# ls -l /dev/ttyAC*
crw-rw-rw- 1 root dialout 166,  0 May 18 01:01 /dev/ttyACM0
#cuコマンドを実行
root@rosdk:~/gitwork# cu -s 115200 -l /dev/ttyACM0
Connected.
~[rosdk].
```

※cuコマンドの終了は、"~"を入力してから"."を入力します。

また別の資料[^ab]では、docker内のユーザについての言及がありました。
コンテナ内の`/dev/ttyACM0`のオーナはそもそも`root`なので、問題無いだろうと思ったのですが、
試しにコンテナ内の`dialout`グループに`root`を加えてみました。

[^ab]: https://github.com/node-red/node-red-docker/issues/15


```sh
#その他ユーザの読み書き権限を一旦削除
root@rosdk:~/# chmod 660 /dev/ttyACM0
#dialoutグループにrootを加える
root@rosdk:~/# sudo usermod -aG dialout root
#一旦コンテナを止めてから、もう一度立ち上げる
root@rosdk:~/# exit
exit
pi@raspi4:~ $ docker start ros1
ros1
#コンテナに入る
pi@raspi4:~ $ docker attach ros1 
#ユーザのIDを確認。dialoutグループに入っている。
root@rosdk:~/gitwork# id
uid=0(root) gid=0(root) groups=0(root),20(dialout)
root@rosdk:~/# sudo usermod -aG dialout root
#cuコマンドを実行
root@rosdk:~/# cu -s 115200 -l /dev/ttyACM0
Connected.
~[rosdk].
```

```python
#pyserialを試す
>>> import serial
>>> ser = serial.Serial('/dev/ttyACM0', 115200)
>>> ser.write("w")
1
>>> ser.write("e")
1
>>> [Ctrl-D]
```

というわけで、シリアル通信を使うには、コンテナ内の`root`ユーザを、`dialout`グループに追加する必要があるようです。
（うーん、何でだろう･･･次章のDockerfileには、groupaddを使う方で追記してます）


#5.Dockerfileを試してみる

ここまでの一連の作業を、Dockerfileにまとめて記述して、イメージを作ります。

##(1)Dockerfile

ROS1 melodicでの例です。
python2系列になるので、インストールパッケージを注意して下さい。（python-*, pip）

```sh:コマンドライン
$ mkdir workdir; cd workdir
$ touch Dockerfile
```

### for ROS1
```dockerfile:Dockerfile
# image
FROM ros:melodic

# Set default work directory
WORKDIR /var/workdir

# install packages
# GPIO, I2C, Serial (for Python2.x)
RUN set -x &&\
    apt-get update &&\
    apt-get install \
        python-rpi.gpio i2c-tools python-smbus cu -y
# WiringPi Install
RUN set -x &&\
    git clone https://github.com/WiringPi/WiringPi &&\
    cd WiringPi &&\
    ./build
# grove.py (for Python2.x pip)
RUN set -x &&\
    git clone https://github.com/Seeed-Studio/grove.py &&\
    cd grove.py/ &&\
    pip install .
# Add group
RUN set -x &&\
    usermod -aG dialout root
```

### for ROS2

ROS2系では、python3系列をインストールして下さい。(python3-*, pip3)

```dockerfile:Dockerfile
# image
FROM ros:eloquent

# Set default work directory
WORKDIR /var/workdir

# install packages
# GPIO, I2C, Serial (for Python3.x)
RUN set -x &&\
    apt-get update &&\
    apt-get install \
        python3-rpi.gpio i2c-tools python3-smbus cu -y
# WiringPi Install
RUN set -x &&\
    git clone https://github.com/WiringPi/WiringPi &&\
    cd WiringPi &&\
    ./build
# grove.py (for Python2.x pip)
RUN set -x &&\
    git clone https://github.com/Seeed-Studio/grove.py &&\
    cd grove.py/ &&\
    pip3 install .
# Add group
RUN set -x &&\
    usermod -aG dialout root
```


##(2)イメージをビルド

Dockerfileを置いてあるディレクトリにいる状態で、下記を実行。

```sh:コマンドライン
$ docker build -t rosmine .
```

`-t`の引数（例:`rosmine`）は、自由に付けてOKです。

##(3)コンテナを起動

前述と同じですが、イメージ名が変わります。（例:`rosmine`）
下記のコマンド例では、コンテナ名は`ros1`にしてます。

```sh:コマンドライン
$ docker run --name ros1 -h rosdk -v /home/pi/gitwork:/root/gitwork --device /dev/gpiomem --device /dev/i2c-1 --device /dev/ttyACM0 --privileged --rm -e TZ=Asia/Tokyo -it rosmine
```

#5.ユーザマッピング

コンテナの中から、`-v`オプションで接続したディレクトリに読み書きすると、ファイルのオーナーが`root`になってしまいます。
ここでは、`userns-remap`という仕組みをつかって、生成したファイルがroot→ホスト側の一般ユーザがオーナーになるようにしてみます。

なお、後述の注意書きのとおりの問題がありますので、ros2の関連ファイルを生成するときなどにこの方法を使って下さい。

**注意**
この方法でコンテナをつくると、`--device`や`--privileged`といった、ホスト側でroot権限の必要なオプションを付けることができません。（有効にして立ち上げると、今度はユーザマッピングができなくなります）
ユーザマッピングと両方成り立つような方法を探りましたが、今の所良い方法が無く、コンテナを切り替えながら使う事になります。

くわしくは、[こちらの記事](https://hotch-potch.hatenadiary.jp/entry/2021/01/03/130001)を参考下さい。

##（１）事前の設定

`/etc/docker/daemon.json`に追記。
（ファイルが無ければ新規に作ってOK）

```sh
$ sudo nano /etc/docker/daemon.json
```

```json:/etc/docker/daemon.json
{
    "runtimes": {
        "nvidia": {
            "path": "nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
     ,"userns-remap": "default"    
      ### ↑ここを追記。先頭のコンマは、これより前の行に設定が入っているときに必要です
}
```

ここで一旦、Dockerを再起動します。
再起動によって、この後編集するファイルに、自動的にひな形が追加されます。

```sh:コマンドライン
$ sudo systemctl restart docker.service
```

続いて２つのファイルを編集します。

ユーザID/グループIDを指定の数だけオフセットするので、その数を指定します。

`dockremap～`というキーワードは、`userns-remap`が自動的に参照するので、そのまま使います。

```sh:コマンドライン
$ sudo nano /etc/subuid
```

編集前

```text:/etc/subuid
dockremap:100000:65536
```

編集後

```text:/etc/subuid
dockremap:1000:65536
```

ホストOS側の自分のUIDが1000の筈ですので、その値に修正します。

続いてもう一つのファイル。

```sh
$ sudo nano /etc/subgid
```

編集前

```texttext:/etc/subgid
dockremap:100000:65536
```

編集後

```text:/etc/subgid
dockremap:1000:65536
```

ホストOS側の自分のGIDが1000の筈ですので、その値に修正します。

ここでDockerを再起動します。

```sh:コマンドライン
$ sudo systemctl restart docker.service
```

##（２）コンテナを起動

`ros2user`という名前でコンテナを起動します。
前章で紹介の`--device`や`--privileged`は外しています。

```sh:コマンドライン
$ docker run --name ros2user -h rosdk -v /home/myasu/gitwork:/root/gitwork -w /root/gitwork --rm -e TZ=Asia/Tokyo -it rosmine
```

##（３）プロジェクトを作る

プロジェクトを作ってみます。
手順は、[こちら](https://qiita.com/myasu/items/3a026697f535183e12e8)を参考にしています。

```sh:コマンドライン
#作業ディレクトリを作成
root@rosdk:~/gitwork# mkdir -p ./ros2_ws/src
root@rosdk:~/gitwork# cd !$
cd ./ros2_ws/src

#パッケージを作成
root@rosdk:~/gitwork/ros2_ws/src# ros2 pkg create pubsubpy_mes
going to create a new package
package name: pubsubpy_mes
destination directory: /root/gitwork/ros2_ws/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['root <root@todo.todo>']
licenses: ['TODO: License declaration']
build type: ament_cmake
dependencies: []
creating folder ./pubsubpy_mes
creating ./pubsubpy_mes/package.xml
creating source and include folder
creating folder ./pubsubpy_mes/src
creating folder ./pubsubpy_mes/include/pubsubpy_mes
creating ./pubsubpy_mes/CMakeLists.txt
```

コンテナの中から見たオーナーを確認してみます。

```sh:コマンドライン
root@rosdk:~/gitwork/ros2_ws/src# la -la
total 12
drwxr-xr-x 3 root root 4096 Jan  3 14:10 .
drwxr-xr-x 3 root root 4096 Jan  3 14:09 ..
drwxr-xr-x 4 root root 4096 Jan  3 14:10 pubsubpy_mes

root@rosdk:~/gitwork/ros2_ws/src# cd pubsubpy_mes/

root@rosdk:~/gitwork/ros2_ws/src/pubsubpy_mes# ls -la
total 24
drwxr-xr-x 4 root root 4096 Jan  3 14:10 .
drwxr-xr-x 3 root root 4096 Jan  3 14:10 ..
-rw-r--r-- 1 root root 1017 Jan  3 14:10 CMakeLists.txt
drwxr-xr-x 3 root root 4096 Jan  3 14:10 include
-rw-r--r-- 1 root root  596 Jan  3 14:10 package.xml
drwxr-xr-x 2 root root 4096 Jan  3 14:10 src
```

###ホスト側から確認

別のターミナルを開いて、ファイルのオーナーを確認します。

```
myasu@jetsonn:~/gitwork/ros2_ws/src$ ls -la
合計 12
drwxr-xr-x 3 myasu myasu 4096  1月  3 14:10 .
drwxr-xr-x 3 myasu myasu 4096  1月  3 14:09 ..
drwxr-xr-x 4 myasu myasu 4096  1月  3 14:10 pubsubpy_mes

myasu@jetsonn:~/gitwork/ros2_ws/src$ cd pubsubpy_mes/

myasu@jetsonn:~/gitwork/ros2_ws/src/pubsubpy_mes$ ls -la
合計 24
drwxr-xr-x 4 myasu myasu 4096  1月  3 14:10 .
drwxr-xr-x 3 myasu myasu 4096  1月  3 14:10 ..
-rw-r--r-- 1 myasu myasu 1017  1月  3 14:10 CMakeLists.txt
drwxr-xr-x 3 myasu myasu 4096  1月  3 14:10 include
-rw-r--r-- 1 myasu myasu  596  1月  3 14:10 package.xml
drwxr-xr-x 2 myasu myasu 4096  1月  3 14:10 src
```

ファイルのオーナーが、ホスト側の一般ユーザになっています。


#6.次の課題

- Docker Compose を活用（試し中）
- Dockerで、ROS2 の[この問題](https://qiita.com/myasu/items/39362b03780cb773b1ed#%EF%BC%91ros2%E3%82%92%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%89%E3%82%A2%E3%83%AD%E3%83%B3%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%99%E3%81%A8%E3%81%8D)が解決できないか・・・

#参考資料

- https://yukota.hatenablog.com/entry/2015/04/04/160248