[ロボ実験記録] 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
実行結果は以下の通り。うまく通信できたようです。
サーバー・クライアント通信というものもあるようですが、割愛します。
次は、一気に飛んで、ロボットアームを制御しようと思います(第六章に対応)。
この記事が気に入ったらサポートをしてみませんか?