導入
最近家でインテリアとなってしまっているラズパイになにか役割を与えたいと思い、amazonでロボットカーなるものを購入してみた。
私が購入したロボカーキットの中にmicroSDが入っており、それをラズパイに挿入すればすぐに使えるといった代物です。
ただ、それだけだとちょっと面白くなさすぎたので自分で制御システムを組んでみたいと思い立ち、ゆったりと休日プログラミングを楽しむこととした。
やり方を忘れそうなので個人用のメモとして。
環境
開発用PCとラズパイのスペック
開発用PC | ラズパイ | |
---|---|---|
OS | Ubuntu 24.04.3 LTS | Ubuntu 24.04.3 LTS |
メモリ | 16GB | 8GB |
ざっくりこんな感じです。
ラズパイは4世代目のmodel Bを使っています。少し調べた感じ単なるセンサ制御程度であれば1, 2GBくらいのメモリでも十分動くらしいが、SLAMや映像認識などの実装を見据えているなら8GBくらいはほしいとのことです。
インストール
早速ROS2を入れましょう。ROS2は開発(シミュレーション)を行うPC 及び 実機となるラズパイ両方に入れる必要があります。
- ロケールの設定
ROS2は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
- aptリポジトリの登録
ROS2のinstallのためにaptリポジトリへ登録をしましょう。
sudo apt install -y software-properties-common
sudo add-apt-repository universe
sudo apt update && sudo apt install -y curl gnupg 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 $(. /etc/os-release && echo $UBUNTU_CODENAME) main" \
| sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
- ROS2のインストール
ROS2にはパッケージがいくつかあり開発用PCではフルデスクトップ版を入れ、ラズパイ側では軽量版(base)をインストールすれば良いと思います。
sudo apt update
sudo apt install -y ros-jazzy-desktop
sudo apt update
sudo apt install -y ros-jazzy-ros-base
- 環境設定
ターミナルを開くだけでROS環境が読み込まれるようにしたい人は以下のようにコマンドを打ちましょう。
echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc
source ~/.bashrc
逆に言うとこれをしない場合、ターミナルを開くたびに毎回
source /opt/ros/jazzy/setup.bash
を打てば、ROS環境を認識します。お好きな方で。
動作確認
さて、これで環境自体は概ね整ったと思います。
簡単な通信を行ってみてちゃんと動くのか確認してみましょう。
やりたいことはPCからPublishノード、PiではSubscribeノードをそれぞれ走らせて送受信ができているのかを確認することを目標とします。
ROSでは1つのプログラム(実行単位)のことをノードと呼びます。
各ノードは独立して動き、TopicやServiceという通信路を通じてデータのやり取りをします。
Step1. PCでPublishノードを作る
基本的なところですがROSのワークスペースを作成して移動しておきましょう。
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
その次にパッケージを作成しましょう。
今回はpythonで書いていこうかなと思うので、コマンドに明示しておきましょう。
ros2 pkg create --build-type ament_python test_hello
test_hello
というのはパッケージの名前なので何でも大丈夫です。
このときファイルやフォルダが自動的にパッケージ名の下に生成されていると思いますが
-
package.xml
: 依存パッケージやメタ情報が定義されている -
setup.py
: pythonパッケージをビルド・インストールするための設定ファイル。colcon build
がこれを使ってノードを実行可能ファイルとして登録する -
setup.cfg
:ros2 run
を実行したときにこのファイルを手がかりに実行可能ファイルを見つける -
<package name>
: ソースコードを置くディレクトリ
といった役割がそれぞれあります。
ではいよいよpublish.pyのコーディングといきましょう。私はVScodeをエディタとして使っているので以下のようなコマンドとなります。
cd ~/ros2_ws/src/test_hello/test_hello
code test_publish.py
test_publish.py コード
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalPublisher(Node):
def __init__(self):
super().__init__('minimal_publisher')
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 1.0
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
def timer_callback(self):
msg = String()
msg.data = f'Hello World: {self.i}'
self.publisher_.publish(msg)
self.get_logger().info(f'Publishing: "{msg.data}"')
self.i += 1
def main(args=None):
rclpy.init(args=args)
node = MinimalPublisher()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
ROS2の最下層にはRMW(ROS MiddleWare)があり、DDS(Data Distribution Service)と通信を行う。という仕組みになっています。その上にrcl(ROS Client Library, C言語)があり、基本的なノード・トピック・サービス・タイマーなどの機能があります。
rclpy(ROS Client Library for Python) はrclをpythonで使えるようにするラッパーです。
Step2. エントリーポイントの登録
ソースコードが無事に書けたらros2コマンドとして実行可能に登録する必要があります。
登録するにはsetup.py
のconsole_scriptsというところに書き足します。シンタックスは以下の感じです。
<コマンド名> = <パッケージ名>.<モジュール名>:<関数名>
今回の例で行くと
entry_points = {
`consolce_scripts`:[
"publish = test_hello.test_publish:main"
],
},
こんな感じです。
Step3. PCでSubscriveノードを作る
同様に今度は受信側のノードを作ってみましょう。
cd ~/ros2_ws/src/test_hello/test_hello
code test_subscribe.py
そしたらコーディングです。
test_subscribe.py コード
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalSubscriber(Node):
def __init__(self):
super().__init__('minimal_subscriber')
self.subscription = self.create_subscription(
String,
'topic',
self.listener_callback,
10)
def listener_callback(self, msg):
self.get_logger().info(f'I heard: "{msg.data}"')
def main(args=None):
rclpy.init(args=args)
node = MinimalSubscriber()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
コーディングが終わったら先ほどと同様にエントリーポイントを登録しておきましょう。
entry_points = {
`consolce_scripts`:[
"publish = test_hello.test_publish:main" ,
"subscribe = test_hello.test_subscribe:main",
],
},
Step. 4 ラズパイへファイルコピー
ここまでPCで行いましたが、作成したパッケージをラズパイに送ってみましょう。送る方法は何でもいいです。gitでもscpでも。
例としてscpコマンドのケースを挙げておきます。
scp -r ~/ros2_ws/src/test_hello <user>@102.168.0.0:~/ros2_ws/src
Step. 5 ノードのビルド
作成したノードをビルドしましょう。colcon
というコマンドを使います。なければsudo apt get
とかで入手しましょう。
cd ~/ros2_ws
colcon build
source install/setup.bash
colcon build
: src以下のパッケージをビルド
source install/setup.bash
: ビルド結果の環境を反映
Step. 6 実行
ではいよいよ実行です。
実行コマンドのシンタックスは以下のような感じです。
ros2 run <パッケージ名> <setup.pyで定義したコマンド>
となります。まずはpublishの方から
ros2 run test_pkg pub
うまく実行できるとターミナルの画面にメッセージが次々と流れるはずです。
次にsubscribe側ですが、せっかくなのでPCからsshでras piにつなげて実行しましょうか。
ssh user@192.168.0.0
ros2 run test_pkg sub
うまく成功すればpubで送ったメッセージがsubの方が受け取って表示するような結果となっているはずです。
パッケージが増えてきて定義したコマンドが把握しきれなくなることもあると思います。
そんなときは
ros2 pkg executables <パッケージ名>
と打つと、そのパッケージで使えるコマンドを返してくれるので使ってみてください。