ROSチュートリアルの流れ
はじめに
この章では、サービスの書き方について説明したいと思います。
サービスにはデータを要求する「クライアント」と応答する「サーバ」があります。
これはトピックの「サブスクライバ」と「パブリッシャ」の関係に似ていますが、サービスは更に応答の成否を知ることができます。
またトピックではメッセージ(.msg)を使用しましたが、サービスではサービスのファイル(.srv
)を使用します。
詳しくはを御覧ください。
サービスファイル
サービスでは.srv
という拡張子になっているファイルを使用します。 まず標準のサービスstd_srvs
のSetBool.srv
を見てみましょう。
rossrv show std_srvs/SetBool
以下のように表示されるはずです。
bool data
---
bool success
string message
---
の上が入力、下が出力になります。
サービスサーバ
最初にサーバ側から書いていきます。
server.py
を作成します。
roscd ros_tutorial/
vim scripts/server.py
#!/usr/bin/env python
import rospy
from std_srvs.srv import SetBool, SetBoolResponse
def callback_srv(data):
resp = SetBoolResponse()
if data.data == True:
resp.message = "called"
resp.success = True
else:
resp.message = "ready"
resp.success = False
print(resp.message)
return resp
if __name__ == "__main__":
rospy.init_node("srv_server")
srv = rospy.Service('service_call', SetBool, callback_srv)
print("ready")
rospy.spin()
実行権限を与えます。
chmod +x scripts/server.py
コード解説
#!/usr/bin/env python
import rospy
ここまで今までと同じです。
from std_srvs.srv import SetBool, SetBoolResponse
標準のサービスのstd_srvs
の中にあるSetBool
とその出力に関するSetBoolResponse
をインポートしています。
先にメイン関数について説明します。
if __name__ == "__main__":
rospy.init_node("srv_server")
srv_server
というノードの名前にしています。
srv = rospy.Service('service_call', SetBool, callback_srv)
ここでサービスをインスタンスしています。service_call
がサービス名、SetBool
がサービスの型、callback_srv
がサービスの引数を返すコールバック関数名になります。
一番最初はready
と表示させておきます。
プログラムを終了させないようにしています。
最後にコールバック関数について解説します。
def callback_srv(data):
callback_srv
という関数名で、受け取った値をdata
という名前にしてます。
resp = SetBoolResponse()
SetBoolResponse
をresp
という名前でインスタンス化しています。
if data.data == True:
resp.message = "called"
resp.success = True
else:
resp.message = "ready"
resp.success = False
Trueが入力された場合、つまり呼び出しがあった時、message
にcalledを書き込み、呼び出されたことを伝えるためsuccess
にTrueを書き込んでいます。
それ以外の場合やFalseが入力された場合は、message
にreadyを書き込み、呼び出されていないことを伝えるためsuccess
にFalseを書き込んでいます。
print(resp.message)
return resp
確認のため、message
を表示しています。
最後にサービスの型を返す必要があり、SetBoolResponse
をインスタンス化したresp
を返しています。
サービスクライアント
次にクライアント側を書いていきます。
client.py
を作成します。
roscd ros_tutorial/
vim scripts/client.py
#!/usr/bin/env python
import rospy
from std_srvs.srv import SetBool
if __name__ == "__main__":
rospy.wait_for_service('service_call')
try:
service_call = rospy.ServiceProxy('service_call', SetBool)
service_call(True)
except rospy.ServiceException, e:
print ("Service call failed: %s" % e)
実行権限を与えます。
chmod +x scripts/client.py
コード解説
#!/usr/bin/env python
import rospy
ここまで同じです。
std_srvs.srv import SetBool
SetBool
型をインポートしています。
rospy.wait_for_service('service_call')
ここでservice_call
というサービスが立ち上がるのを待ちます。
トピックを違い、サービスは一対一通信のため相手がいないとエラーを吐きます。 そのためサービスの立ち上がりを待っています。
try:
service_client = rospy.ServiceProxy('service_call', SetBool)
service_client(True)
except rospy.ServiceException, e:
print ("Service call failed: %s" % e)
sarvice_call
という名前のSetBool
型のサービスプロキシservice_client
を作成しています。
service_client
にTrueを与えています。
実行方法
それぞれ別のターミナルで実行してください。
rosrun ros_tutorial server.py
rosrun ros_tutorial client.py
実行結果
rosrun ros_tutorial client.py
を実行した時、rosrun ros_tutorial server.py
を実行しているターミナルで、
と表示されたら、正常に動作しています。
別の方法
rosrun ros_tutorial server.py
ここまで同じですが、こちらではrosservice
というコマンドを使用します。 このコマンドでもサーバに要求できます。
rosservice call /service_call "data: true"
rosservice call /service_call "data: false"