背景
ros1はubuntu20.04向けのnoeticが最後なようでubuntu22.04にはaptでインストール可能なものがありませんが、dockerのros1のコンテナを使えばubuntu22.04でもros1を使えました。備忘録を兼ねてrosserial-arduinoの動作確認手順を記事にします。
使ったもの
- ubuntu22.04をインストールしたPC
Intel製のCPUで構成されたノートPCを使いました - docker-compose
dockerのインストール手順に従いdocker-ceをインストールし、その環境でdocker-compose-pluginもインストールします。 - ESP32開発ボード + USBケーブル
esp32devkitcでもm5stackでも良いです。 - PlatformIO
Arduino IDEでも良いですが、ライブラリの紹介が楽なのでこちらを利用します。
pioコマンドを使える環境を作ってください。
スクリプトを利用する方法、python-pipを利用する方法、vscodeにプラグインをインストールする方法など、方法はいくつかあります。
ESP32をrosserial端末として準備
subscriberで名前を変えられ、publisherで「名前+起動ミリ秒」を配信するrosserial端末としてESP32を動かします。この記事では~/pio/esp32-rosserial-testというディレクトリ(PlatformIOのプロジェクト)を作り、その中に必要なファイルを配置してESP32に書き込みます。
cppファイルは更にその中のsrcディレクトリ内に置くので、srcディレクトリも一緒に作ります。
mkdir -p ~/pio/esp32-rosserial-test/src
コードは古いですがライブラリとして公開されているrosserialを使います。
今回は複雑なことはしないのでライブラリが古くても動きます。
~/pio/esp32-rosserial-test/platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
rosserial_arduino
device_name_subで名前を変えられ、device_hello_pubで「hello by [名前] at [ミリ秒]」を配信するrosserial-arduinoのプログラムです。
~/pio/esp32-rosserial-test/src/main.cpp
#include <Arduino.h>
#include <ros.h>
#include <std_msgs/String.h>
String deviceName = "asdf";
void cbSubDeviceName(const std_msgs::String& ms) { deviceName = ms.data; }
ros::NodeHandle nh;
String nameTopicSubDevice = "device_name_sub";
ros::Subscriber<std_msgs::String> subDeviceName(nameTopicSubDevice.c_str(),
&cbSubDeviceName);
String nameTopicPubDeviceHello = "device_hello_pub";
std_msgs::String msDeviceHello;
ros::Publisher pubDeviceHello(nameTopicPubDeviceHello.c_str(), &msDeviceHello);
void setup() {
nh.getHardware()->setBaud(115200);
nh.initNode();
nh.advertise(pubDeviceHello);
nh.subscribe(subDeviceName);
}
void loop() {
nh.spinOnce();
String strToPub = "hello by " + deviceName + " at " + String(millis());
msDeviceHello.data = strToPub.c_str();
pubDeviceHello.publish(&msDeviceHello);
delay(10);
}
上記の設定とプログラムをESP32に書き込みます。
ESP32開発ボードをPCに接続し、下記のコマンドを実行すると書き込めます。
cd ~/pio/esp32-rosserial-tset
pio run -t upload
USBポートを指定しつつdockerコンテナを起動
下記の設定ファイルを置いたディレクトリでdocker composeを通して起動するとコンテナのros1が起動します。この記事では~/docker/ros1-testというディレクトリを作り、その中にファイルを置いてdocker composeを実行します。
mkdir -p ~/docker/ros1-test
noeticのコンテナにrosserialをインストールし、コンテナ起動時にroscoreを実行するDockerfileです。
~/docker/ros1-test/Dockerfile
FROM ros:noetic
RUN apt update && apt install -y ros-${ROS_DISTRO}-rosserial
CMD ["roscore"]
先程作成したDockerfileを利用してコンテナを起動し、それのdeviceとしてESP32の開発ボードのポートである/dev/ttyUSB0をコンテナに設定しているdocker-comoseファイルです。
これだけならdocker-compose.ymlを使わなくても良いですが、都度USBポートを指定するのが手間なのと他のコンテナと連携時はdocker-composeが必要になってくるので、あえて使いました。
USBを開くには特権(privileged)設定を有効にするか、deviceとしてusbポートを読み込ませて制限なく扱える状態にする必要があります。
privilegedを有効にして/devディレクトリを渡す書き方はこちらです。
~/docker/ros1-test/docker-compose.yml
version: "3.9"
services:
ros1:
build: .
privileged: true
volume:
- /dev:/dev
privileged権限を指定したポート(下記の場合はttyUSB0)だけに設定する書き方はこちらです。
~/docker/ros1-test/docker-compose.yml
version: "3.9"
services:
ros1:
build: .
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
Dockerfileとdocker-compose.ymlを作成したディレクトリでdocker composeを通してコンテナを起動します。
cd ~/docker/ros1-test
docker compose up
実行後にエラーが出て無ければ起動成功です。
初回起動時はコンテナのダウンロードとコンテナへのrosserialのインストールを行うので時間がかかります。
自分の環境だと5分ほどかかりました。
setup.bashを読み込みつつコマンドを実行
コンテナが起動したらrosserial-pythonを通してUSBポート(/dev/ttyUSB0)を115200bpsで開きます。docker compose exec bashで立ち上がるコマンド実行画面はrosのsetup.bashが読み込まれていないため、それを呼び出してからrosのコマンドを実行します。
これはdocker compose upを実行したのとは別のターミナルを起動して実行します。
cd ~/docker/ros1-testまたは
docker compose exec ros1 bash -c "source /opt/ros/noetic/setup.bash && rosrun rosserial_python serial_node.py _port:=/dev/ttyUSB0 _baud:=115200"
cd ~/docker/ros1-test
docker compose exec ros1 bash
source /opt/ros/noetic/setup.bash
rosrun rosserial_python serial_node.py _port:=/dev/ttyUSB0 _baud:=115200
下記のエラーで失敗する場合は、deviceでポートを指定するかprivilegedを有効にしてください。(先程のdocker-compose.ymlの解説で書き方の例を出しています。)
[ERROR] [1674892372.324435]: Error opening serial: [Errno 1] could not open port /dev/ttyUSB0: [Errno 1] Operation not permitted: '/dev/ttyUSB0'
成功するとdevice_hello_pubとdevice_name_subが認識されます。
別のターミナルでdevoce_hello_pubの内容を確認します。
cd ~/docker/ros1-test
docker compose exec ros1 bash -c "source /opt/ros/noetic/setup.bash && rostopic echo /device_hello_pub"
期待通りに配信されました。
---
data: "hello by asdf at 21197"
---
data: "hello by asdf at 21208"
---
data: "hello by asdf at 21220"
---
data: "hello by asdf at 21230"
---
data: "hello by asdf at 21241"
device_name_subを通して名前をhoiに変えてみます。
cd ~/docker/ros1-test
docker compose exec ros1 bash -c "source /opt/ros/noetic/setup.bash && rostopic pub -1 /device_name_sub std_msgs/String \"hoi\""
device_hello_pubを確認すると期待通りに名前がasdfからhoiに変わりました。
---
data: "hello by hoi at 241659"
---
data: "hello by hoi at 241670"
---
data: "hello by hoi at 241681"
---
data: "hello by hoi at 241692"
---
data: "hello by hoi at 241703"
---
data: "hello by hoi at 241714"
publisherもsubscriberも期待通りに動きました。
終わり
ros1をaptではインストールできないubuntu22.04でdockerを利用してros1のrosserialを動かせました。ros1からros2へ移行できていないプログラムをubuntu22.04で動作確認できて嬉しいです。
参考
ros - Official Image | Docker
ROS複数Docker通信
ROS Docker Setup
Is ROS already sourced if I do it from a dockerfile?
micro-ROS / micro_ros_arduino
devices | Compose file version 3 reference
[自分用]docker-compose.yamlテンプレ
0 件のコメント :
コメントを投稿