サービス通信の例(仮)
serviceを用いたnode間通信の例を挙げます。
task_manager.pyで起動したノードから、 serviceを用いてmove_robot.pyで起動したノードの機能を使用する例です。
pythonファイルの用意
navigation_tutorial/scripts/に以下の2つのファイルを作成してください (コピペで構いません)。
task_manager.py
#!/usr/bin/env python3
import rospy
from navigation_tutorial.srv import MoveTrigger, MoveTriggerRequest
class TaskManager:
def __init__(self):
rospy.init_node('task_manager')
# service client
self.move_robot = rospy.ServiceProxy('/move_robot', MoveTrigger)
self.move_robot.wait_for_service()
rospy.loginfo("Service /move_robot is ready!")
def move(self, straight, turn):
command = MoveTriggerRequest()
command.straight = straight
command.turn = turn
rospy.loginfo(f"request: straight={straight}, turn={turn}")
response = self.move_robot(command) # service call
return response.success
def main(self):
"""
タスクの流れを手続的に記述する
"""
result = self.move(1.0, 0.0)
if result:
rospy.loginfo("move success!")
else:
rospy.loginfo("move failed!")
result = self.move(0.0, 90.0)
if result:
rospy.loginfo("turn success!")
else:
rospy.loginfo("turn failed!")
rospy.loginfo("task completed!")
if __name__ == '__main__':
task_manager = TaskManager()
task_manager.main()
move_robot.py
#!/usr/bin/env python3
import numpy as np
import rospy
import tf
from geometry_msgs.msg import Twist
from nav_msgs.msg import Odometry
from navigation_tutorial.srv import MoveTrigger, MoveTriggerResponse
class RobotController:
def __init__(self):
rospy.init_node('robot_controller', anonymous=True)
# Publisher
self.cmd_vel_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=10)
# Subscriber
odom_sub = rospy.Subscriber('/odom', Odometry, self.callback_odom)
# Service Server
rospy.Service('/move_robot', MoveTrigger, self.callback_move_robot)
self.x = None
self.y = None
self.yaw = None
while self.x is None:
rospy.sleep(0.1)
def callback_move_robot(self, req):
res = MoveTriggerResponse()
try:
self.go_straight(req.straight)
if req.turn >= 0:
self.turn_left(req.turn)
else:
self.turn_right(-req.turn)
res.success = True
return res
except rospy.ROSInterruptException:
res.success = False
return res
def callback_odom(self, data):
self.x = data.pose.pose.position.x
self.y = data.pose.pose.position.y
self.yaw = self.get_yaw_from_quaternion(data.pose.pose.orientation)
def go_straight(self, dis, velocity=0.3):
vel = Twist()
x0 = self.x
y0 = self.y
while(np.sqrt((self.x-x0)**2+(self.y-y0)**2)<dis):
vel.linear.x = velocity
vel.angular.z = 0.0
self.cmd_vel_pub.publish(vel)
rospy.sleep(0.1)
self.stop()
def turn_right(self, yaw, yawrate=-0.5):
vel = Twist()
yaw0 = self.yaw
while(abs(self.yaw-yaw0)<np.deg2rad(yaw)):
vel.linear.x = 0.0
vel.angular.z = yawrate
self.cmd_vel_pub.publish(vel)
rospy.sleep(0.1)
self.stop()
def turn_left(self, yaw, yawrate=0.5):
vel = Twist()
yaw0 = self.yaw
while(abs(self.yaw-yaw0)<np.deg2rad(yaw)):
vel.linear.x = 0.0
vel.angular.z = yawrate
self.cmd_vel_pub.publish(vel)
rospy.sleep(0.1)
self.stop()
def stop(self):
vel = Twist()
vel.linear.x = 0.0
vel.angular.z = 0.0
self.cmd_vel_pub.publish(vel)
def get_yaw_from_quaternion(self, quaternion):
e = tf.transformations.euler_from_quaternion(
(quaternion.x, quaternion.y, quaternion.z, quaternion.w))
return e[2]
if __name__=='__main__':
simple_controller = SimpleController()
rospy.spin()
move_robot.pyはsimple_control2.pyを少し修正した程度です。 simple_control2.pyについては、chapter3で詳しく解説しています。
srvファイルの用意
また、このページを参考にして、 navigation_tutorialパッケージ内に navigation_tutorilal/srv/MoveTrigger.srvファイルを作成してください。
とくに、navigation_tutorial/CMakeLists.txtを編集する箇所を抜かさないように気をつけてください (対応する説明)。
MoveTrigger.srv
float32 straight
float32 turn
---
bool success
実行方法
ターミナルで以下のコマンドを実行した後、
$ rosrun navigation_tutorial move_robot.py
別のターミナルで
$ rosrun navigation_tutorial task_manager.py
を実行すると、ロボットが直進して左に回転します。
補足
ファイルがうまく実行できない場合、ファイルに実行権限があたえられていない可能性があります。 このページを参考にして解決してみてください。
それでも解決しない場合はslackで気軽に質問してください。