Python3でROS2を初める(Ubuntu18.04LTS)
目次
はじめに
ROS2にはPython3用のクライアントライブラリ「rclpy」が提供されています。
そこでこの記事では、rclpyを使った基本的なpublisher/subscriberのROS2パッケージ作成方法について簡単に紹介します。
書き方が正しくない可能性がありますので、ご指摘はコメント欄にお願いします。
環境構成
- OS: Ubuntu18.04 LTS
- ROS2 (dashing)
- ディレクトリ構成
colcon_ws ├── buld ├── install ├── log └── src └── <package1> └── <package2> ...
ROS2パッケージの生成
ros2 pkg createコマンドでROS2パッケージの雛形を生成します。今回はrclpyを利用するので、--build-typeでament_pythonを指定します。 なお、C++のROS2パッケージを生成する場合は、ament_cmakeとします。
$ cd ~/colcon_ws/src $ ros2 pkg create --build-type ament_python py_hello_ros2
ここで、「py_hello_ros2」はパッケージ名であり任意に設定してください。
上記コマンドでパッケージを生成すると、以下のような構成となっているはずです。 ROS2のPython3パッケージではCMakeLists.txtは必要なく、package.xmlとsetup.pyだけでよくなりました。
$ cd py_hello_ros2 $ tree . ├── package.xml ├── py_hello_ros2 │ └── __init__.py ├── resource │ └── py_hello_ros2 ├── setup.cfg ├── setup.py └── test ├── test_copyright.py ├── test_flake8.py └── test_pep257.py
package.xmlの記述
まず、package.xmlを記述していきます。C++で記述するときと書き方は同様です。
<?xml version="1.0"?> <?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> <package format="3"> <name>py_hello_ros2</name> <version>0.1.0</version> <description>Sample of publishers/subscribers using rclpy.</description> <maintainer email="yourname@mail.domain">yourname</maintainer> <license>Apache License, Version 2.0</license> <exec_depend>rclpy</exec_depend> <exec_depend>std_msgs</exec_depend> <exec_depend>launch_ros</exec_depend> <test_depend>ament_copyright</test_depend> <test_depend>ament_flake8</test_depend> <test_depend>ament_pep257</test_depend> <test_depend>python3-pytest</test_depend> <export> <build_type>ament_python</build_type> </export> </package>
XMLタグ | 説明 |
---|---|
<exec_depend> | パッケージを実行するために必要な依存パッケージ |
<test_depend> | パッケージをテストするために必要な依存パッケージ |
setup.pyの記述
次に、setup.pyを記述していきます。ROS2のための特殊な書き方は特になく、詳しくはPython公式ドキュメント(日本語)を参照してください。具体的な書き方についてはsampleproject/setup.py at master · pypa/sampleprojectが注釈付きで記載されておりわかりやすいかと思います。
from setuptools import setup package_name = 'py_hello_ros2' setup( name=package_name, version='0.1.0', packages=[package_name], # Directory of source code. data_files=[ # File other than souece code ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), ], install_requires=['setuptools'], # Dependent python3 modules zip_safe=True, maintainer='yourname', maintainer_email='yourname@mail.domain', keywords=['ROS2'], classifiers=[ 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python', 'Topic :: Software Development', ], description='Sample of publishers/subscribers using rclpy.', license='Apache License, Version 2.0', tests_require=['pytest'], # Test frame name entry_points={ # Execution command name and its call destination 'console_scripts': [ 'publisher = '+ package_name + '.publisher:main', 'subscriber = '+ package_name + '.subscriber:main', ], }, )
記載内容の簡単な説明
- name : パッケージ名
- version : パッケージのバージョン
- packages : ソースが格納されるディレクトリ名
- data_files :ソース以外のファイル
- install_requires : このパッケージが依存するpython3モジュールを列挙
- zip_safe : "True"にすると, 全てのファイルを単一の.egg(zipファイル)にまとめる (デフォルト zip_safe=True)
- maintainer : 管理者の名前
- maintainer_email: 管理者のコンタクト先
- keywords : パッケージを検索するとき用のキーワード
- classifiers:そパッケージを検索するとき用のタグ名。タグ一覧はコチラを参照。
- description : パッケージについての簡潔な概要説明 (200文字以内の一文)。長い説明を記載したい場合は、long_descriptionを利用する。
- license : パッケージのライセンス
- tests_require : テスト実行時に必要なモジュールのリスト。詳細はコチラを参照。
- entry_points : 実行コマンド名とその呼び出し先の指定。'console_scripts'で指定されている文字列が、ros2 runコマンドで使用される。
例)$ ros2 run py_hello_ros2 publisher
公式の説明はコチラを参照してくだい。
トピックの実装
ROSのチュートリアルでよく利用される、chatterトピックを送受信する”Publisher"と"Subscriber”を実装していきます。
ソースコードの格納先は以下のようになります。
py_hello_ros2 ├── package.xml ├── py_hello_ros2 │ └── __init__.py │ └── publisher.py #<--ここ │ └── subscriber.py #<--ここ ├── resource ├── setup.cfg ├── setup.py └── test
publisher.py
import rclpy from rclpy.node import Node from std_msgs.msg import String class Publisher(Node): def __init__(self): super().__init__('publisher') self.count = 0 self.publisher = self.create_publisher(String, 'chatter') self.timer = self.create_timer(0.5, self.timer_callback) def timer_callback(self): self.count += 1 msg = String() msg.data = "Hello Publisher! [{0}]".format(self.count) self.publisher.publish(msg) self.get_logger().info(msg.data) def main(): rclpy.init() publisher_node = Publisher() rclpy.spin(publisher_node) rclpy.shutdown() if __name__ == '__main__': main()
subscriber.py
import rclpy from rclpy.node import Node from std_msgs.msg import String class Subscriber(Node): def __init__(self): super().__init__('subscriber') self.subscription = self.create_subscription( String(), '/chatter', self.listener_callback) def listener_callback(self, msg): self.get_logger().info(msg.data) def main(): rclpy.init() subscriber_node = Subscriber() rclpy.spin(subscriber_node) rclpy.shutdown() if __name__ == '__main__': main()
ビルドと実行
colcon buildコマンドを用いてビルドしていきます。
colcon build
$ cd ~/colcon_ws $ colcon build --base-path src/py_hello_ros2 $ source install/setup.bash
実行
Terminal #1
$ ros2 run py_hello_ros2 publisher [INFO] [publisher]: Hello Publisher! [1] [INFO] [publisher]: Hello Publisher! [2] [INFO] [publisher]: Hello Publisher! [3] ...
Terminal #2
$ ros2 run py_hello_ros2 subscriber [INFO] [subscriber]: Hello Publisher! [1] [INFO] [subscriber]: Hello Publisher! [2] [INFO] [subscriber]: Hello Publisher! [3] ...