4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ROS2 service/client node(+service)の作成

Last updated at Posted at 2020-05-05

ROS2でプログラミングするために勉強したメモです.
ここでは,serviceの作成方法を書きます.

準備

workspaceを作成する.

workspaceの作成に関する詳細はココ

1. メインのROS2をunderlayに指定して,ターミナルに反映(source)する.

source /opt/ros/dashing/setup.bash

2. dev_wsという名前のworkspaceを作成する.

mkdir dev_ws
mkdir dev_ws/src
cd dev_ws

3. 環境の依存関係を解決する.

今回は何もgit cloneしてないのでやる必要はないけど,忘れないように手順に組み込んどく.

# (注意)workspaceのルートである,dev_wsフォルダで実行
sudo rosdep install -i --from-path src --rosdistro dashing -y

packageを作成する.

packageの作成に関する詳細はココ

1. srcフォルダに移動する

cd src

2. py_pubsubという名前のpython-packageを作成

ros2 pkg create --build-type ament_python py_srvcli --dependencies rclpy example_interfaces

ここで,

  • py_srvcliは,今回作るpackageの名前.
  • --dependenciesは,必要な依存関係の行をpackage.xmlに自動的に追加する.
  • example_interfacesは,リクエストとレスポンスを構造化するために必要な.srvファイルを含むパッケージ.

(都合で実行していないのでたぶんになるけど,)py_srvcliとは別のpackageであるexample_interfacessrvフォルダにAddTwoInts.srvというファイルができていて,中身は以下の内容になっている.

AddTwoInts.srv
int64 b
---
int64 sum

依存関係をpackageを構成するファイルたちに追加.

  • 今回は,先にまとめて依存関係を追加しておく.
    • publsher/sescriber nodeの説明では追加する説明を行ったが,ビルドする前までに記述しておけば良い.
    • UML設計の観点からすると,先にまとめて書くほうが自然だと思う.

package作成時に自動生成されたsetup.pysetup.cfgおよびpackage.xmlファイルを編集する.

package.xmlを編集

以下を編集.

package.xml
<description>Python client server tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>

<buildtool_depend>ament_python</buildtool_depend>の後に以下を追加.

package.xml
<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>

これは,コードが実行されるときにrclpystd_msgsがこのpackageにとって必要であることを記述している.

setup.pyを編集

package.xmlを編集したときと全く同じ内容でsetup.pyを編集

setup.py
maintainer='Your Name',
maintainer_email='you@email.com',
description='Python client server tutorial',
license='Apache License 2.0',

後ろの方にエントリーポイントの記述を追加.

setup.py
entry_points={
    'console_scripts': [
        'service = py_srvcli.service_member_function:main',
        'client = py_srvcli.client_member_function:main',
    ],
},

ここで,今回作るnodeは,以下の2つとなる.

  • service node: service_member_function.py
  • client node: client_member_function.py
setup.cfgを編集

自動的に生成されるので,特に編集することはない.

service nodeの作成

1. service nodeのpythonファイルを作成.

dev_ws/src/py_srvcliに移動し,以下を実行.

touch service_member_function.py

2. 以下を内容として記述.

service_member_function.py

# example_interfaces packageからサービスタイプ'AddTwoInts'をインポート
from example_interfaces.srv import AddTwoInts

import rclpy
from rclpy.node import Node


class MinimalService(Node):

    def __init__(self):
        super().__init__('minimal_service')
        # サービスを作成し,タイプ,名前,およびコールバックを定義.
        self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback)

    # サービスコールバックの定義
    # 要求データを受け取り,それを合計し,その合計を応答として返す.
    def add_two_ints_callback(self, request, response):
        response.sum = request.a + request.b
        self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b))

        return response


def main(args=None):
    # ROS 2 Pythonクライアントライブラリを初期化
    rclpy.init(args=args)
    # MinimalServiceクラスをインスタンス化してサービスノードを作成
    minimal_service = MinimalService()
    # ノードをスピンしてコールバックを処理
    rclpy.spin(minimal_service)

    rclpy.shutdown()


if __name__ == '__main__':
    main()

client nodeの作成

1. client nodeのpythonファイルを作成.

以下を実行.

touch client_member_function.py

2. 以下を内容として記述.

client_member_function.py
# sys.argvを使用して,リクエストのコマンドライン入力引数にアクセスするためにインポート
import sys

from example_interfaces.srv import AddTwoInts
import rclpy
from rclpy.node import Node


class MinimalClientAsync(Node):

    def __init__(self):
        super().__init__('minimal_client_async')
        # コンストラクター定義は,service nodeと同じタイプと名前のclient nodeを作成する.
        # タイプと名前は,clientとserviceが通信できるように一致する必要がある.
        self.cli = self.create_client(AddTwoInts, 'add_two_ints')
        # clientのタイプと名前に一致するserviceが利用可能かどうか,1秒に1回チェック.
        while not self.cli.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('service not available, waiting again...')
        # リクエスト定義
        self.req = AddTwoInts.Request()

    def send_request(self):
        self.req.a = int(sys.argv[1])
        self.req.b = int(sys.argv[2])
        self.future = self.cli.call_async(self.req)


def main(args=None):
    rclpy.init(args=args)

    minimal_client = MinimalClientAsync()
    minimal_client.send_request()

    while rclpy.ok():
        # ループは,futureシステムが実行されている限り,serviceからの応答があるかどうかを確認.
        # serviceが応答を送信した場合,結果をログメッセージに残す.
        rclpy.spin_once(minimal_client)
        if minimal_client.future.done():
            try:
                response = minimal_client.future.result()
            except Exception as e:
                minimal_client.get_logger().info(
                    'Service call failed %r' % (e,))
            else:
                minimal_client.get_logger().info(
                    'Result of add_two_ints: for %d + %d = %d' %
                    (minimal_client.req.a, minimal_client.req.b, response.sum))
            break

    minimal_client.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

ビルドと実行

publisher/subscriber nodeと全く同様の手続き.

ビルド

1. dev_wsフォルダに移動し,以下を実行.

sudo rosdep install -i --from-path src --rosdistro <distro> -y

2. py_srvclipackageをcolconでビルド.

colcon build --packages-select py_srvcli

実行

1. 新しいターミナルを開き,dev_wsに移動して以下を実行.

. install/setup.bash

2. service nodeを実行

ros2 run py_srvcli service

3. client nodeを実行

同様に,別ターミナルで. install/setup.bashを行い,nodeを実行.

ros2 run py_srvcli client 2 3

ここで,
引数に23を与えた場合,client nodeは合計した5を受け取る.

4. Ctrl+Cで終了.

参考サイト

4
3
0

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
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?