サービスの書き方

ROSチュートリアルの流れ

はじめに

この章では、サービスの書き方について説明したいと思います。
サービスにはデータを要求する「クライアント」と応答する「サーバ」があります。
これはトピックの「サブスクライバ」と「パブリッシャ」の関係に似ていますが、サービスは更に応答の成否を知ることができます。
またトピックではメッセージ(.msg)を使用しましたが、サービスではサービスのファイル(.srv)を使用します。
詳しくはROSでよく使用する用語を御覧ください。

サービスファイル

サービスでは.srvという拡張子になっているファイルを使用します。 まず標準のサービスstd_srvsSetBool.srvを見てみましょう。
1
rossrv show std_srvs/SetBool
Copied!
以下のように表示されるはずです。
1
bool data
2
---
3
bool success
4
string message
Copied!
---の上が入力、下が出力になります。

サービスサーバ

最初にサーバ側から書いていきます。
server.pyを作成します。
1
roscd ros_tutorial/
2
vim scripts/server.py
Copied!
server.py
1
#!/usr/bin/env python
2
import rospy
3
from std_srvs.srv import SetBool, SetBoolResponse
4
5
def callback_srv(data):
6
resp = SetBoolResponse()
7
if data.data == True:
8
resp.message = "called"
9
resp.success = True
10
else:
11
resp.message = "ready"
12
resp.success = False
13
print(resp.message)
14
return resp
15
16
if __name__ == "__main__":
17
rospy.init_node("srv_server")
18
srv = rospy.Service('service_call', SetBool, callback_srv)
19
print("ready")
20
rospy.spin()
Copied!
実行権限を与えます。
1
chmod +x scripts/server.py
Copied!

コード解説

1
#!/usr/bin/env python
2
3
import rospy
Copied!
ここまで今までと同じです。
1
from std_srvs.srv import SetBool, SetBoolResponse
Copied!
標準のサービスのstd_srvsの中にあるSetBoolとその出力に関するSetBoolResponseをインポートしています。
先にメイン関数について説明します。
1
if __name__ == "__main__":
2
rospy.init_node("srv_server")
Copied!
srv_serverというノードの名前にしています。
1
srv = rospy.Service('service_call', SetBool, callback_srv)
Copied!
ここでサービスをインスタンスしています。service_callがサービス名、SetBoolがサービスの型、callback_srvがサービスの引数を返すコールバック関数名になります。
1
print("ready")
Copied!
一番最初はreadyと表示させておきます。
1
rospy.spin()
Copied!
プログラムを終了させないようにしています。
最後にコールバック関数について解説します。
1
def callback_srv(data):
Copied!
callback_srvという関数名で、受け取った値をdataという名前にしてます。
1
resp = SetBoolResponse()
Copied!
SetBoolResponserespという名前でインスタンス化しています。
1
if data.data == True:
2
resp.message = "called"
3
resp.success = True
4
else:
5
resp.message = "ready"
6
resp.success = False
Copied!
Trueが入力された場合、つまり呼び出しがあった時、messageにcalledを書き込み、呼び出されたことを伝えるためsuccessにTrueを書き込んでいます。
それ以外の場合やFalseが入力された場合は、messageにreadyを書き込み、呼び出されていないことを伝えるためsuccessにFalseを書き込んでいます。
1
print(resp.message)
2
return resp
Copied!
確認のため、messageを表示しています。
最後にサービスの型を返す必要があり、SetBoolResponseをインスタンス化したrespを返しています。

サービスクライアント

次にクライアント側を書いていきます。
client.pyを作成します。
1
roscd ros_tutorial/
2
vim scripts/client.py
Copied!
client.py
1
#!/usr/bin/env python
2
import rospy
3
from std_srvs.srv import SetBool
4
5
if __name__ == "__main__":
6
rospy.wait_for_service('service_call')
7
try:
8
service_call = rospy.ServiceProxy('service_call', SetBool)
9
service_call(True)
10
except rospy.ServiceException, e:
11
print ("Service call failed: %s" % e)
Copied!
実行権限を与えます。
1
chmod +x scripts/client.py
Copied!

コード解説

1
#!/usr/bin/env python
2
import rospy
Copied!
ここまで同じです。
1
std_srvs.srv import SetBool
Copied!
SetBool型をインポートしています。
1
rospy.wait_for_service('service_call')
Copied!
ここでservice_callというサービスが立ち上がるのを待ちます。
トピックを違い、サービスは一対一通信のため相手がいないとエラーを吐きます。 そのためサービスの立ち上がりを待っています。
1
try:
2
service_client = rospy.ServiceProxy('service_call', SetBool)
3
service_client(True)
4
except rospy.ServiceException, e:
5
print ("Service call failed: %s" % e)
Copied!
sarvice_callという名前のSetBool型のサービスプロキシservice_clientを作成しています。
service_clientにTrueを与えています。

実行方法

それぞれ別のターミナルで実行してください。
1
roscore
Copied!
1
rosrun ros_tutorial server.py
Copied!
1
rosrun ros_tutorial client.py
Copied!

実行結果

1
rosrun ros_tutorial client.py
Copied!
を実行した時、rosrun ros_tutorial server.pyを実行しているターミナルで、
1
called
Copied!
と表示されたら、正常に動作しています。

別の方法

1
roscore
Copied!
1
rosrun ros_tutorial server.py
Copied!
ここまで同じですが、こちらではrosserviceというコマンドを使用します。 このコマンドでもサーバに要求できます。
1
rosservice call /service_call "data: true"
Copied!
1
rosservice call /service_call "data: false"
Copied!
Last modified 2yr ago