Hi The Construct Team,
I noticed a few things missing in the code provided in the tutorial for Chapter 5 - ROS2 Actions.
I am providing my modification suggestions.
Original code in tutorial:
5.3 Action Server
import rclpy
from rclpy.action import ActionServer
from rclpy.node import Node
from t3_action_msg.action import Move
from geometry_msgs.msg import Twist
import time
class MyActionServer(Node):
def __init__(self):
super().__init__('my_action_server')
self._action_server = ActionServer(self, Move, 'turtlebot3_as_2',self.execute_callback)
self.cmd = Twist()
self.publisher_ = self.create_publisher(Twist, 'cmd_vel', 10)
def execute_callback(self, goal_handle):
self.get_logger().info('Executing goal...')
feedback_msg = Move.Feedback()
feedback_msg.feedback = "Moving to the left left left..."
for i in range(1, goal_handle.request.secs):
self.get_logger().info('Feedback: '.format(feedback_msg.feedback))
goal_handle.publish_feedback(feedback_msg)
self.cmd.linear.x = 0.3
self.cmd.angular.z =0.3
self.publisher_.publish(self.cmd)
time.sleep(1)
goal_handle.succeed()
self.cmd.linear.x = 0.0
self.cmd.angular.z = 0.0
self.publisher_.publish(self.cmd)
result = Move.Result()
result.status = "Finished action server. Robot moved during 5 seconds"
return result
def main(args=None):
rclpy.init(args=args)
my_action_server = MyActionServer()
rclpy.spin(my_action_server)
if __name__ == '__main__':
main()
My modification suggestion:
import rclpy
from rclpy.action import ActionServer
from rclpy.node import Node
from t3_action_msg.action import Move
from geometry_msgs.msg import Twist
import time
class MyActionServer(Node):
def __init__(self):
super().__init__('my_action_server')
self._action_server = ActionServer(
self, Move, 'turtlebot3_as_2', self.execute_callback)
self.cmd = Twist()
self.publisher_ = self.create_publisher(Twist, 'cmd_vel', 10)
def execute_callback(self, goal_handle):
self.get_logger().info('Executing goal...')
feedback_msg = Move.Feedback()
feedback_msg.feedback = "Moving to the left left left..."
for i in range(1, goal_handle.request.secs):
self.get_logger().info(
'Feedback: {0}'.format(feedback_msg.feedback))
goal_handle.publish_feedback(feedback_msg)
self.cmd.linear.x = 0.3
self.cmd.angular.z = 0.3
self.publisher_.publish(self.cmd)
time.sleep(1)
goal_handle.succeed()
self.cmd.linear.x = 0.0
self.cmd.angular.z = 0.0
self.publisher_.publish(self.cmd)
result = Move.Result()
result.status = "Finished action server. Robot moved during 5 seconds"
self.get_logger().info(
'Result: {0}'.format(result.status))
return result
def main(args=None):
rclpy.init(args=args)
my_action_server = MyActionServer()
rclpy.spin(my_action_server)
if __name__ == '__main__':
main()
Differences:
Thanks,
Girish
Hi The Construct Team,
Another minor modification suggestion in Chapter 4 - ROS2 Services.
Original code in tutorial:
4.3 Service Client
# import the empty module from std_servs Service interface
from std_srvs.srv import Empty
# import the ROS2 Python client libraries
import rclpy
from rclpy.node import Node
class ClientAsync(Node):
def __init__(self):
# Here you have the class constructor
# call the class constructor to initialize the node as service_client
super().__init__('service_client')
# create the Service Client object
# defines the name and type of the Service Server you will work with.
self.client = self.create_client(Empty, 'moving')
# checks once per second if a Service matching the type and name of the Client is available.
while not self.client.wait_for_service(timeout_sec=1.0):
# if it is not available, a message is displayed
self.get_logger().info('service not available, waiting again...')
# create an Empty request
self.req = Empty.Request()
def send_request(self):
# send the request
self.future = self.client.call_async(self.req)
def main(args=None):
# initialize the ROS communication
rclpy.init(args=args)
# declare the node constructor
client = ClientAsync()
# run the send_request() method
client.send_request()
while rclpy.ok():
# pause the program execution, waits for a request to kill the node (ctrl+c)
rclpy.spin_once(client)
if client.future.done():
try:
# checks the future for a response from the Service
# while the system is running.
# If the Service has sent a response, the result will be written
# to a log message.
response = client.future.result()
except for Exception as e:
# Display the message on the console
client.get_logger().info(
'Service call failed %r' % (e,))
else:
# Display the message on the console
client.get_logger().info(
'the robot is moving' )
break
client.destroy_node()
# shutdown the ROS communication
rclpy.shutdown()
if __name__ == '__main__':
main()
My modification suggestion: (minor change only)
# import the empty module from std_servs Service interface
from std_srvs.srv import Empty
# import the ROS2 Python client libraries
import rclpy
from rclpy.node import Node
class ClientAsync(Node):
def __init__(self):
# Here you have the class constructor
# call the class constructor to initialize the node as service_client
super().__init__('service_client')
# create the Service Client object
# defines the name and type of the Service Server you will work with.
self.client = self.create_client(Empty, 'moving')
# checks once per second if a Service matching the type and name of the Client is available.
while not self.client.wait_for_service(timeout_sec=1.0):
# if it is not available, a message is displayed
self.get_logger().info('service not available, waiting again...')
# create an Empty request
self.req = Empty.Request()
def send_request(self):
# send the request
self.future = self.client.call_async(self.req)
def main(args=None):
# initialize the ROS communication
rclpy.init(args=args)
# declare the node constructor
client = ClientAsync()
# run the send_request() method
client.send_request()
while rclpy.ok():
# pause the program execution, waits for a request to kill the node (ctrl+c)
rclpy.spin_once(client)
if client.future.done():
try:
# checks the future for a response from the Service
# while the system is running.
# If the Service has sent a response, the result will be written
# to a log message.
response = client.future.result()
except Exception as e:
# Display the message on the console
client.get_logger().info(
'Service call failed %r' % (e,))
else:
# Display the message on the console
client.get_logger().info(
'the robot is moving' )
break
client.destroy_node()
# shutdown the ROS communication
rclpy.shutdown()
if __name__ == '__main__':
main()
Differences:
Thanks,
Girish
@girishkumar.kannan
Thank you so much for pointing out these bugs. I have corrected them; the corrections will be live in the next hr.