この記事は「#NervesJP Advent Calendar 2022」の9日目の記事です(遅れてスミマセン(あとネタ変更しました:D
まえおき
2022年12月17日(土)に開催の「第11回FA設備技術勉強会」では,ElixirのROS 2クライアントライブラリである Rclex が Nerves でいごきまっせ!てなLTを披露しました.
イベント情報
スライド資料
デモで披露したNervesアプリのリポジトリは,こちらにあります.
デモ動画はコチラです.
リポジトリの README はそれなりに整理してあるつもりなので,試してみたかったらぜひにどうぞです!
横河電機のリアルタイムOSコントローラである e-RT3 Plus を対象としていますが,他のボードでもいごくはずです.
この記事の目的
上記のリポジトリではあらかじめ作成済みのプロジェクトをビルドするだけでいいわけですが,せっかくなら Rclex on Nerves なIoTシステムをイチからつくってみませんか??
ということでこの記事ではこの方法を紹介します.
っといいつつ,実はこの方法は Rclex のドキュメントにちゃんとまとめてあります.ってえいごなんですが;(
要は今回はこれを和訳しただけです.ただし Rclex on Nerves はまだ experimental な感じでして,今後またやりかたが改善される可能性があります(あるいはご意見ください!).つまりこの記事の情報が古くなる可能性がありますので,公式の情報もご参照ください.
動作対象のボード
現時点では,下記表のボードで Rclex on Nerves の動作が確認されています.
頑張ってゲトってください!
board | tag | arch | support for nerves_system |
---|---|---|---|
Raspberry Pi 4 | rpi4 | arm64v8 | Officially supported, recommended |
BeagleBone Green | bbb | arm32v7 | Officially supported |
Kria KR260 | kr260 | arm64v8 | Third-party supported |
ODYSSEY - STM32MP157C | stm32mp157c_odyssey | arm32v7 | Third-party supported |
F3RP70 (e-RT3 Plus) | f3rp70 | arm32v7 | Third-party supported |
準備
ホストPCのOSは不問です!(WindowsはWSLのほうがいいかも?
もちろんElixir/Nerves開発環境は準備してください.
Rclex をネイティブに動作させる場合には ROS 2 の開発・実行環境のインストールも必要でした.
Rclex on Nerves では,Dockerがうまく活用されているので,これらのインストールは不要です!!(開発環境が不要なのにROS 2のアプリが開発できる,コレ実はすごいことなんですよ:D
その代わり,Docker(DesktopまたはEngine)をインストールしてください.Engineの場合はクロス環境向けの qemu や binfmt も必要です(Ubuntuの例: sudo apt-get install qemu binfmt-support qemu-user-static
)
開発手順
この記事では e-RT3 Plus (F3RP70) を例題として紹介しています.プロセッサアーキは arm32v7
になります.このあたりは使用されるボードの tag と arch に合わせて変更してください.
export MIX_TARGET=f3rp70
--arch arm32v7
あと,以降に示す開発手順に従った作業履歴がコチラにあります.合わせて参考にすると良いかと思います.
Nervesの新規作成と依存ライブラリの取得
ここは通常のNervesアプリの開発手順と一緒です.
mix nerves.new rclex_usage_on_nerves
cd rclex_usage_on_nerves
nerves_system_f3rp70 は Nerves Project 公式のパッケージではないため,このあとに mix.exs
を編集してやる必要があります(rpi4 とか公式のものでは編集不要です)
- {:nerves_system_rpi, "~> 1.19", runtime: false, targets: :rpi},
- {:nerves_system_rpi0, "~> 1.19", runtime: false, targets: :rpi0},
- {:nerves_system_rpi2, "~> 1.19", runtime: false, targets: :rpi2},
- {:nerves_system_rpi3, "~> 1.19", runtime: false, targets: :rpi3},
- {:nerves_system_rpi3a, "~> 1.19", runtime: false, targets: :rpi3a},
- {:nerves_system_rpi4, "~> 1.19", runtime: false, targets: :rpi4},
- {:nerves_system_bbb, "~> 2.14", runtime: false, targets: :bbb},
- {:nerves_system_osd32mp1, "~> 0.10", runtime: false, targets: :osd32mp1},
- {:nerves_system_x86_64, "~> 1.19", runtime: false, targets: :x86_64},
- {:nerves_system_grisp2, "~> 0.3", runtime: false, targets: :grisp2}
+ {:nerves_system_f3rp70, "~> 0.4", runtime: false, targets: :f3rp70}
- @all_targets [:rpi, :rpi0, :rpi2, :rpi3, :rpi3a, :rpi4, :bbb, :osd32mp1, :x86_64, :grisp2]
+ @all_targets [:f3rp70]
このあとに依存ライブラリの取得を行ってください.
export MIX_TARGET=f3rp70
mix deps.get
rclex のインストール
rclex
は hex パッケージとして開済みです!
mix.exs
に rclex
を依存ライブラリのリストとして追加してください.
defp deps do
[
...
+ {:rclex, "~> 0.8.3"},
...
]
end
その後,普通に mix deps.get
するだけです.
mix deps.get
ROS 2リソースの用意
ROS 2 のリソースやライブラリを Nerves のファイルシステムに取り込みます.
ここで Docker コマンドを使用するわけです.
export ROS_DISTRO=foxy
mix rclex.prep.ros2 --arch arm32v7
rpi4 とか arm64 アーキのものでは --arch arm64v8
にしてやる必要があります.
ホストとターゲットのアーキが異なる場合には下記のメッセージが何度か表示されますが,これは無視しても問題ありません.
WARNING: The requested image's platform (linux/arm/v7) does not match the detected host platform (linux/amd64) and no specific platform was requested
ROS 2メッセージ型の生成
Rclex は ROS 2 で規定されているトピックによる出版購読型通信を実現します(ROS 2のメッセージ型についての詳しい話はコチラ)
この通信メッセージのための型を生成します
config/config.exs
に ros2_message_types
というフィールドを用意して,アプリで使用したい型の情報を記述します.コンマ区切りで複数の型が指定できます.
+config :rclex, :ros2_message_types, [
+ "std_msgs/msg/String",
+ "geometry_msgs/msg/Twist",
+ "turtlesim/msg/Pose"
+]
このあと,次のコマンドを実行してください.
mix rclex.gen.msgs
使用したいメッセージの型を追加・変更したい場合は,ファイルの変更とこのコマンドを改めて実行してください.
erlinit.config
のコピーと編集
erlinit.config
というファイルを Nerves のファイルシステムにコピーします.
(これはErlang VMの設定ファイルです)
cp deps/nerves_system_f3rp70/rootfs_overlay/etc/erlinit.config rootfs_overlay/etc
このファイルに -e LD_LIBRARY_PATH=/opt/ros/foxy/lib
という行を追加します.
foxy
は ROS_DISTRO
に合わせてください.
# Enable UTF-8 filename handling in Erlang and custom inet configuration
-e LANG=en_US.UTF-8;LANGUAGE=en;ERL_INETRC=/etc/erl_inetrc;ERL_CRASH_DUMP=/root/crash.dump
-e LD_LIBRARY_PATH=/opt/ros/foxy/lib
Rclexのコードを実装!
これで Rclex on Nerves を実現する準備が整いました!!
Rclex APIを自在に使いこなしてください!
ここでは最も単純な例 lib/rclex_usage_on_nerves.ex
を示します.文字列型のメッセージを /chatter
のトピックに出版します.
defmodule RclexUsageOnNerves do
def publish_message do
context = Rclex.rclexinit()
{:ok, node} = Rclex.ResourceServer.create_node(context, 'talker')
{:ok, publisher} = Rclex.Node.create_publisher(node, 'StdMsgs.Msg.String', 'chatter')
msg = Rclex.Msg.initialize('StdMsgs.Msg.String')
data = "Hello World from Rclex!"
msg_struct = %Rclex.StdMsgs.Msg.String{data: String.to_charlist(data)}
Rclex.Msg.set(msg, msg_struct, 'StdMsgs.Msg.String')
# This sleep is essential for now, see Issue #212
Process.sleep(100)
IO.puts("Rclex: Publishing: #{data}")
Rclex.Publisher.publish([publisher], [msg])
Rclex.Node.finish_job(publisher)
Rclex.ResourceServer.finish_node(node)
Rclex.shutdown(context)
end
end
いろいろサンプルを公開していますので,いろいろ参考にしてください.
ファームウェアの生成とSDカードへの書き込み
これはもう通常のNervesアプリ開発とと一緒です.
mix firmware
mix burn # or, mix upload
実行例
Nervesデバイスに SSH で接続します.
ssh nerves.local
Nerves の IEx 上で次のように実行してみてください.
iex()> RclexUsageOnNerves.publish_message
Rclex: Publishing: Hello World from Rclex!
{:ok, #Reference<0.2970499651.1284374532.3555>}
出版されたメッセージを確認する方法はいくつかありますが,ROS 2のネイティブ環境で購読する例をお示しします(ROS 2環境やっぱいるんかーい!
$ source /opt/ros/foxy/setup.bash
$ ros2 topic echo /chatter std_msgs/msg/String
data: Hello World from Rclex!
---
やったねっ!
おわりに
スターくださぁい!!
完全に蛇足ですが,筆者は Rclex をコアメンテしている立場ですが,この Nerves 対応についてはリポジトリに多大な contribution をいただけた成果となっています.貢献いただけましたこと,ここで深く御礼申し上げます m(_ _)m
ということでみなさんからも contribution くださぁい!!