[ロボ実験記録] ROS2の勉強1: パッケージ作成とプロセス間の通信

概要

  • ロボットアームの快適な操作にはROS2は避けられないようなので、ROS2を、かいつまんで勉強していきます

  • パッケージ作成とプロセス間の通信までやってみました

ROS2のセットアップは以下のページなどを参照。
環境構築にdockerは便利ですが、自分で作ってみた方が、諸々の理解は深まると思います。

(本記事では、ROS2のロングサポートバージョンのHumbleをつかっています)

こちらの参考書をもとに勉強しています。
Githubにコードは上がっています。ただ、この記事も含め、webは断片的な情報が多いので、真面目に勉強されたい方は購入をおすすめします。
本記事のコードには適当なアレンジを加えています。

chapter2 (rosの基礎)

パッケージの作成

ROS2で何かをするには、パッケージを作るのが基本とのことです。
適当にフォルダを作成 → パッケージ作成コマンドを打つ流れで作成します。


次のコマンドで、pkg1というパッケージを作りました。

mkdir ros_ws
mkdir ros_ws/src
cd ros_ws/src

#パッケージ作成
ros2 pkg create --build-type ament_python --node-name node1 pkg1

(node-nameがなんだか、あまり分かってませんが、とりあえずnode1としました)

ビルド

パッケージを作成すると、色々とファイルが生成されます。
これをrosで呼び出せるように、buildします。
--symlink-installをつけると、シンボリックリンクが生成され、ソースコードを変更後、buildをし直さなくてもプログラムに反映されるようです。

colcon build --symlink-install

設定ファイルの読み込み

作成したモジュールを呼び出すコマンド

 source (ワークスペースへのパス)/ws1/install/setup.bash

実行

ros2 run pkg1 node1

"Hi from pkg1." というメッセージが帰ってきました。初のROSプログラムです。
src/pkg1/node1.pyが本体のようです。 試しに、書き換えてみました。
3回ループをするようにしたところ、きちんと3回printされました。

ノードの生成

プログラム上で、明示的にnodeと呼ばれるプロセス作る必要があるようです。
こちらのソースコードを写経します(一部アレンジ)。

node1.py

import rclpy
from rclpy.node import Node


class HappyNode(Node):
    def __init__(self):
        print("ノードを作ります")
        super().__init__('node1')
        self.get_logger().info('Hi from pkg1.')


def main():
    print("begin main")
    rclpy.init()
    node = HappyNode()
    rclpy.shutdown()
    print("end main")


if __name__ == '__main__':
    main()

実行すると、無事にノードができた感じがします。

プロセス(ノード)間の通信: パブリシャ&サブスクライバ

2つのプロセス間で通信をさせます。
パブリシャ&サブスクライバ通信では、一方向の通信をするようです。

パブリシャの実装

パブリシャとは、データを発信する側のようです。
以下のコードでは、0.1秒ごとに、内部変数iの状況を発信します。

node1.pyを編集します。

import rclpy
from rclpy.node import Node
from std_msgs.msg import String


class PublisherNode(Node):
    def __init__(self):
        print("ノードを作ります")
        super().__init__('node1')
        self.get_logger().info('Hi from pkg1.')
        self.pub = self.pub = self.create_publisher(String, 'chatter', 10)
        self.timer = self.create_timer(0.1, self.timer_callback)
        self.i = 100

    def timer_callback(self):
        msg = String()
        msg.data = 'Hello World: %d' % self.i
        self.pub.publish(msg)
        self.get_logger().info('Publishing: "%s"' % msg.data)
        self.i += 1


def main():
    print("begin main")
    rclpy.init()
    node = PublisherNode()
    rclpy.spin(node)
    rclpy.shutdown()
    print("end main")


if __name__ == '__main__':
    main()


spinというコマンドを実行すると、ユーザーが強制終了するまで、time_callbaclを定期的に呼び出し続けるようです。

サブスクライバの実装

データを受け取るノードのようです。
node1.pyと同じフォルダに、node2.py作ります。

import rclpy
from rclpy.node import Node
from std_msgs.msg import String


class SubscriberNode(Node):
    def __init__(self):
        print("ノード2を作ります")
        super().__init__('node2')
        self.get_logger().info('Hi from pkg1.')
        self.sub = self.create_subscription(
            String, 'chatter', self.callback, 10)

        self.sub = self.create_subscription(String, 'topic', self.callback, 10)

    def callback(self, msg):
        self.get_logger().info('I heard: "%s"' % msg.data)


def main():
    print("begin main")
    rclpy.init()
    node = SubscriberNode()
    rclpy.spin(node)
    rclpy.shutdown()
    print("end main")


if __name__ == '__main__':
    main()

setup.pyにnode2の情報を追記します。


ビルドし直して、別のターミナルでnode1, node2を実行します。

colcon build --symlink-install

1つ目のターミナル

ros2 run pkg1 node1

2つ目のターミナルを立ち上げ、humbleと今回のpackageのsetup.bashを実行し、以下のコマンドを実行

ros2 run pkg1 node2


実行結果は以下の通り。うまく通信できたようです。


サーバー・クライアント通信というものもあるようですが、割愛します。
次は、一気に飛んで、ロボットアームを制御しようと思います(第六章に対応)。

この記事が気に入ったらサポートをしてみませんか?