はじめに (ROS2って、DDSって、Rclexってなに?)
ROS2(Robot Operating System)はロボット開発支援フレームワークです。ROS2環境ではプログラムコードはC++やPythonで書かれることが主に想定されているようですが、これをElixirでも開発したい!ということでElixirのROS2クライアントライブラリ(=RCL)、Rclexが開発されています。
ROS2は通信レイヤにDDS(Data Distribution Service)という通信プロトコル/ライブラリ/パッケージが採用されていて、開発言語を問わず実装にDDSを用いていれば、ノード間で簡単に通信することが可能です(C++で書かれたROS2ノードとPythonで書かれたROS2ノード間で簡単に通信可能)。このRclexを用いればElixirで書いたコードで他のROS2ノードと通信することが可能です。
この記事は、Rclexがバージョンアップした(0.3.1->0.4.0)ことにあわせて、ROS2をFoxyにし、パッケージインストール版で試した内容になっています。
(旧記事はこちらです。ROS2をソースからビルドしたい場合などでなければ、本記事を参照したほうが良いです。)
なおDDSについては(ROS2観点ですが)こちらの記事が参考になります。
なお本記事は、2021年6月10日時点の内容です。
環境とバージョン
Rclexは環境を選びます。以下の環境で動かしました。
- Ubuntu 20.04.2 LTS (amd64)
- ROS 2 Foxy Fitzroy
- Elixir 1.9.1
- Erlang/OTP 22
rclex 0.4.0になってROS2 Foxyに対応しました! (Dashingでもいけるようです。私は0.4.0では未試用。)
ErlangとElixirはUbuntu環境でパッケージインストールしました。特に問題ありませんでした。
環境構築、インストール
Ubuntu 20.04.2環境の構築
私はUbuntuをintel Mac(10.15 Catalina)上にVirtualBoxをインストールしその上で動かしました。ROS2に不慣れなのでGUIツール(rviz2など)も使うかなと思ったためですが、今回のようにDDSで通信を試すだけであればGUIは不要です。たぶんクラウド上のVMでも大丈夫だと思います。
VirtualBoxのインストール、またUbuntuのインストールは割愛します。調べればすぐに見つかるでしょう。
OS本体のインストールが完了したら、VirtualBoxのGuest Additionsもインストールしておきましょう。Guest AddtionsはROS2/Rclexトライアル的には不要ですが、入れたほうが便利です。このあたりを参考にしました。
https://www.linuxmania.jp/virtualbox_02.html
ROS2 Foxyのインストール
Ubuntu環境ができたら、ROS2 Foxyをインストールしていきます。ROS2はパッケージインストールとソースからの自前構築の2つの方法がありますが、ここではパッケージインストールを試します。
パッケージインストールにも、1)aptコマンドでインストールする、2)ROS2公式サイトからダウンロードするバイナリパッケージ、の2通りがあります。ここでは両方について説明します。
1) aptパッケージでのインストール
非常に簡単です。
% sudo apt update
% sudo apt install ros-foxy-desktop
少々時間はかかります。
2) ROS2公式サイトからバイナリパッケージをダウンロードしてインストール
基本的な手順はROS2のドキュメント通りです。簡単に解説していきます。
(なおROS2のドキュメントは、バージョンが異なっても全般的には非常に似ていますので注意が必要です。)
以下の手順では、ROS2のフルセットをインストールしていますが、多分、いらない物がたくさんあるはずなので、ROS2に詳しい方は不要なもののインストールは省略できるはずです。RclexのビルドにはROS2の開発環境があればよいはず。
2-1) ROS2レポジトリを追加
% sudo apt update && sudo apt install curl gnupg2 lsb-release
% 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 $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
この手順に失敗すると、次の手順のパッケージインストールの際に謎のエラーが出るので、間違えないように注意しましょう。
2-2) ROS2 Foxy本体をダウンロードして展開
ROS2 Foxyの最新はこのあたりのようです。
% cd ~/Downloads
% wget https://github.com/ros2/ros2/releases/download/release-foxy-20201211/ros2-foxy-20201211-linux-focal-amd64.tar.bz2
% mkdir -p ~/ros2_foxy
% cd ~/ros2_foxy
% tar xv ~/Downloads/ros2-foxy-20201211-linux-focal-amd64.tar.bz2
2-3) rosdepコマンドのインストールと、依存パッケージのインストール
rosdepコマンドを入れます。
% sudo apt update
% sudo apt install -y python3-rosdep
% sudo rosdep init
% rosdep update
続いて、rosdepコマンドで依存関係パッケージをインストールしていきます。
% rosdep install --from-paths ~/ros2_foxy/ros2-linux/share --ignore-src --rosdistro foxy -y --skip-keys "console_bridge fastcdr fastrtps osrf_testing_tools_cpp poco_vendor rmw_connext_cpp rosidl_typesupport_connext_c rosidl_typesupport_connext_cpp rti-connext-dds-5.3.1 tinyxml_vendor tinyxml2_vendor urdfdom urdfdom_headers"
このあと、python3のライブラリを入れます。
% sudo apt install -y libpython3-dev python3-pip
% pip3 install -U argcomplete
ドキュメントではこの後、独自のDDS環境をインストールしたい場合には入れよ、と書いてあるのですが、ここではそれはしません。
これでインストールができました。
環境変数をセット
本体や依存パッケージのインストールが終わった時点で、ROS2環境が /opt/ros/foxy (ディストリビューションパッケージの場合)もしくは ~/ros2_foxy/ros2-linux(ROS2公式パッケージの場合)配下にできています。ROS2環境を使う(動かす)ためには環境変数(PATH等)をセットする必要があり、それをするためのスクリプトが用意されています。ターミナル実行時に都度環境変数をセットするか(下記)、.bashrc等でシェル起動時に自動で読み込ませるかします。
% . /opt/ros/foxy/setup.bash (ディストリビューションのパッケージインストールの場合)
% . ~/ros2_foxy/ros2-linux/setup.bash (ROS2公式パッケージインストールの場合)
bash以外のシェル用のスクリプトもあります。(sh, zah, powershell)
簡単にサンプルを動かしてみる
ROS2の環境構築ができたら、サンプルを動かしてみましょう。
ターミナルを2つ起動し、双方でsetup.bashを実行させてros2コマンドが動くようにしておきます(下記には含んでいます)。その状態で、
% . /opt/ros/foxy/setup.bash
% ros2 run demo_nodes_cpp talker
% . /opt/ros/foxy/setup.bash
% ros2 run demo_nodes_py listener
とすると、ターミナル1側でpublishした文字列が、ターミナル2側のsubscriber側で受信できています。やりました!
実際の実行時の画面はこんな感じです。
Elixir環境の構築
ROS2環境ができたので、ようやくRclexですが、前提となるElixirを入れます。
Elixirのドキュメントに従います。
% wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i erlang-solutions_1.0_all.deb
% sudo apt-get update
% sudo apt-get install elixir
(手順では、elixir本体をインストールする前にsudo apt-get install esl-erlangするように書いてあるのですが、エラーが出ました。elixirをインストールすると依存パッケージとして勝手に入るようです。)
その他、Rclexのビルドに必要なパッケージを入れておきます。
% sudo apt-get install build-essential
% sudo apt-get install erlang-dev
Rclexをインストールする
ここからがようやく本番です!
Rclexはライブラリであり、単体で使用するものではないので、ここでは同じ開発者から提供されているサンプルコードを使います。Rclex本体はサンプルコードの中で依存パッケージとして指定されており、サンプルコードをビルドするときに自動的に、インストール・ビルドされます。
% git clone https://github.com/rclex/rclex_samples.git
% cd rclex_samples
kikuzo@kikuzo-VirtualBox:~/rclex_samples$ mix deps.get
Resolving Hex dependencies...
Dependency resolution completed:
Unchanged:
elixir_make 0.6.2
rclex 0.4.0
* Getting rclex (Hex package)
* Getting elixir_make (Hex package)
kikuzo@kikuzo-VirtualBox:~/rclex_samples$
ここで、ros2をディストリビューションのパッケージインストールした場合は問題ないのですが、ROS2公式の方から落としてきてインストールした場合には、rclexのMakefileの修正が必要です。
冒頭部分のROSDIRを修正します。
# set directory for ROSDISTRO
#ROS_DIR = /opt/ros/$(ROS_DISTRO) # ここをコメントアウトして、自分でインストールしたディレクトリに書き換える
ROS_DIR = /home/kikuzo/ros2_foxy/ros2-linux
ifeq ($(ROS_DISTRO), dashing)
ROS_VERSION = DASHING
TYPE_STRUCTURE_DIR = rosidl_generator_c
else ifeq ($(ROS_DISTRO), foxy)
ROS_VERSION = FOXY
TYPE_STRUCTURE_DIR = rosidl_runtime_c
endif
CC = gcc
LD = ld
RM = rm
PREFIX = $(MIX_APP_PATH)/priv
BUILD = $(MIX_APP_PATH)/obj
(..省略..)
(ROS2公式のインストール手順ではパッケージは作業者のホームディレクトリ配下に入れるようになっているのですが、これを任意の場所(端的に言えば/opt/ros/foxy)に変更できないものでしょうか。(未試用))
さて、mixコマンドを実行すると、すーっとビルドが通ります。
kikuzo@kikuzo-VirtualBox:~/rclex_samples$ mix deps.compile
==> rclex
mkdir -p /home/kikuzo/rclex_samples/_build/dev/lib/rclex/priv
mkdir -p /home/kikuzo/rclex_samples/_build/dev/lib/rclex/obj
gcc -c -I/usr/lib/erlang/usr/include -I/opt/ros/foxy/include -g -O2 -Wall -Wextra -Wno-unused-parameter -pedantic -fPIC -DFOXY -o
(..省略..)
gcc -o /home/kikuzo/rclex_samples/_build/dev/lib/rclex/priv/rclex.so -L/usr/lib/erlang/usr/lib -g -shared /home/kikuzo/rclex_samples/_build/dev/lib/rclex/obj/total_nif.o /home/kikuzo/rclex_samples/_build/dev/lib/rclex/obj/init_nif.o /home/kikuzo/rclex_samples/_build/dev/lib/rclex/obj/node_nif.o /home/kikuzo/rclex_samples/_build/dev/lib/rclex/obj/publisher_nif.o /home/kikuzo/rclex_samples/_build/dev/lib/rclex/obj/subscription_nif.o /home/kikuzo/rclex_samples/_build/dev/lib/rclex/obj/wait_nif.o /home/kikuzo/rclex_samples/_build/dev/lib/rclex/obj/msg_int16_nif.o /home/kikuzo/rclex_samples/_build/dev/lib/rclex/obj/msg_string_nif.o -L/opt/ros/foxy/lib -lrcl -lrmw -lrcutils -lrosidl_runtime_c -lrosidl_typesupport_c -lrosidl_typesupport_introspection_c -lstd_msgs__rosidl_generator_c -lstd_msgs__rosidl_typesupport_c -lfastcdr -lfastrtps -lrmw_fastrtps_cpp
Compiling 6 files (.ex)
Generated rclex app
kikuzo@kikuzo-VirtualBox:~/rclex_samples$
動かしてみる
rclex_samplesにある、simple_pubを使ってみましょう。
ターミナルを2つ起動し、一つでrclex_samples/simple_pubを動かして送信しし、もう一つはROS2のコマンドでsubscriberを動かして受信してみます。
kikuzo@kikuzo-VirtualBox:~/rclex_samples$ iex -S mix
Erlang/OTP 24 [erts-12.0] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [jit]
Interactive Elixir (1.11.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> RclexSamples.SimplePub.
callback/1 pub_main/1
iex(1)> RclexSamples.SimplePub.pub_main 1
finished rcl_init
publish message:hello,world
publish ok
実際の様子。
なお、iexコマンドの起動に先立って、ros2環境のセットアップ(setup.bashの実行)をしておかないと実行時にエラーが出ます。
まとめ
Rclexを動かしてみました。DDSでメッセージを送受信するだけですが、とりあえず動いていることは確認できました。
みなさんも、いろいろ試してみて、様子を教えて下さい。