LoginSignup
20
10

More than 3 years have passed since last update.

ROS2で自分で作成したpythonプログラムを動かす方法

Last updated at Posted at 2019-07-30

初めに

前回はros2でpythonのサンプルを実行しました1
今回は自分で作成したプログラムを動かす方法とポイントをまとめます.

ターミナルを立ち上げたままだと環境情報が残っている場合があるので再度立ち上げてから行ってください.

ワークスペースとパッケージの作成

まずはワークスペースを作ります.

mkdir -p ~/ros2_my_python_ws/src
cd ~/ros2_my_python_ws/src

自分でpython用のROS2パッケージを作成して実行していきます2

ros2 pkg create [パッケージ名]コマンドでros2のパッケージを作成します.
ros1でのcatkin_create_packageに当たります.

ros2 pkg create my_python

これで必要なファイルが生成されました.ディレクトリ構造は以下のようになります.

ros2_my_python_ws
└── src
    └── my_python
        ├── CMakeLists.txt
        ├── include
        │   └── my_python
        ├── package.xml
        └── src

pythonプログラムの作成

先程作成したmy_pythonパッケージの中に移動してください.
pythonプログラムを配置するフォルダを作ります.
フォルダ名はなんでもいいです.

mkdir python_programs

この中にlistenerとtalkerのサンプルプログラムを入れます.

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

class Listener(Node):
    def __init__(self):
        super().__init__('listener')
        self.sub = self.create_subscription(String, 'chatter', self.chatter_callback, 10)

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

def main(args=None):
    rclpy.init(args=args)
    try:
        listener = Listener()
        rclpy.spin(listener)
    finally:
        listener.destroy_node()
        rclpy.shutdown()

if __name__ == '__main__':
    main()

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

class Talker(Node):
    def __init__(self):
        super().__init__('talker')
        self.i = 0
        self.pub = self.create_publisher(String, 'chatter', 10)
        self.timer = self.create_timer(1.0, self.timer_callback)

    def timer_callback(self):
        msg = String()
        msg.data = 'Hello World: {0}'.format(self.i)
        self.i += 1
        self.get_logger().info('Publishing: "{0}"'.format(msg.data))
        self.pub.publish(msg)

def main(args=None):
    rclpy.init(args=args)
    try:
        talker = Talker()
        rclpy.spin(talker)
    finally:
        talker.destroy_node()
        rclpy.shutdown()

if __name__ == '__main__':
    main()

最後にポイントとして,python_programsフォルダに作成したpythonファイルが認識されるように__init__.pyを追加します.

touch __init__.py

作成したROSパッケージのディレクトリ構造は以下のようになります.

./my_python
├── CMakeLists.txt
├── include
│   └── my_python
├── package.xml
├── python_programs
│   ├── __init__.py
│   ├── talker.py
│   └── listener.py
└── src

package.xmlの編集

まずデフォルトでは以下のようになります.

package.xml
package.xml
<?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>my_python</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="hoge@gmail.com">root</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

<build_type>がcpp用になっていたりするのでpython用に書き換えます.

package.xml
package.xml
<?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>my_python</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="hoge@gmail.com">root</maintainer>
  <license>TODO: License declaration</license>

  <exec_depend>rclpy</exec_depend>
  <exec_depend>std_msgs</exec_depend>

  <export>
    <build_type>ament_python</build_type>
  </export>
</package>

CMakeLists.txtの削除とpython用ファイルの追加

現時点でのros2 create pkgコマンドはpython用ではなく,c++用のファイル(CMakeLists.txt)を生成します.

今回はpythonだけを動かしたいのでc++のコンパイル対象にならないようにCMakeLists.txtは削除します.

rm CMakeLists.txt

setup.pyの追加

pythonをros2で実行するためにsetup.pyを追加します.
ros1の頃はこのようなファイルは必要なかったのですが,ros2から導入されたようです.
自分用に書き換えるのはpackage_name,py_modules,entry_pointsあたりでしょうか.
他はメタデータだったりするので適当で.

setup.py
setup.py
from setuptools import setup

package_name = 'my_python'

setup(
    name=package_name,
    version='0.0.0',
    packages=[],
    py_modules=[
        'python_programs.talker',
        'python_programs.listener',
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    author='user',
    author_email="user@todo.todo",
    maintainer='user',
    maintainer_email="user@todo.todo",
    keywords=['ROS', 'ROS2'],
    classifiers=[
        'Intended Audience :: Developers',
        'License :: OSI Approved :: Apache Software License',
        'Programming Language :: Python',
        'Topic :: Software Development',
    ],
    description='TODO: Package description.',
    license='Apache License, Version 2.0',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'my_talker= python_programs.talker:main',
            'my_listener= python_programs.listener:main',
        ],
    },
)

ポイント

いくつかポイントがあります.
py_modulesについて

py_modules=["foo","bar.hoge"]

これは
foo.pysetup.pyと同じディレクトリにあるということです.
bar.hogesetup.pyと同じディレクトリにbarというフォルダが有り,その中にhoge.pyがあるということです.
以下のような構造になります.

.
├── bar
│   └── hoge.py
├── foo.py
└── setup.py

フォルダ構造を自分で作るとハマリポイントになります.

entry_pointsについて
entry_pointsは実行するファイルと関数を指定します.

'my_talker= python_programs.talker:main',

これはmy_talkerを実行すると,python_programsフォルダの中のtalker.pyの中のmain関数を呼び出すということです.

setup.cfgの追加

次にsetup.cfgを追加します.自分で作成したros2のパッケージ名をしっかりと指定しましょう.

[develop]
script-dir=$base/lib/my_python
[install]
install-scripts=$base/lib/my_python

ここでしっかりと指定しないと

$ ros2 run my_python my_talker
$ No executable found

などのエラーが発生します.

以上を行ったディレクトリ構造は以下のようになります.

./my_python
├── include
│   └── my_python
├── package.xml
├── python_programs
│   ├── __init__.py
│   ├── listener.py
│   └── talker.py
├── setup.cfg
├── setup.py
└── src

コンパイルと実行

コンパイルします.

cd ~/ros2_my_python_ws
colcon build

コンパイルの出力先フォルダにパスを通します.

source install/setup.bash && source install/local_setup.bash

talkerを実行します.

talker.
ros2 run my_python my_talker

ターミナルを新しく開いて同様にsourceをしてパスを通してからlistenerを起動します.

listener.
ros2 run my_python my_listener

これでtalkerからpublishされたメッセージをlistenerがsubscribeします.

おわりに

ros2で自分で作成したpythonプログラムを動かす方法をまとめました.
ros2 pkg createコマンドがpython用に働かないため,自分でディレクトリ構成を整えるのが大変だと思いました.
pythonのモジュールの読み込み方を知らない人などは__init__.pyなどのハマりポイントがあります.

飽きてなかったら次はpythonとC++を共生させる方法について書きます.

20
10
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
10