Calling Service from Node does not work, but calling it from CLI works.
I want to make an interface for controlling many of my nodes. One function of this node is to set the lifecycle state of the map server provided by the navigation2 package. To do so, I run the following code.
from ros2lifecycle.api import get_node_names
from lifecycle_msgs.srv import GetAvailableTransitions
[...]
for node in get_node_names(node=self):
if 'map_server' in node:
self.get_logger().info('switching_to_mapping: Found node {0.full_name}'.format(node))
# Since this service doesnt work, we will just call the node's lifecycle service.
client = self.create_client(
GetAvailableTransitions,
f'{node.full_name}/get_available_transitions')
self.get_logger().info('switching_to_mapping: Waiting for service to become available')
while True:
if client.service_is_ready():
self.get_logger().info('switching_to_mapping: Service is ready')
msg = GetAvailableTransitions.Request()
future = client.call_async(msg)
self.get_logger().info('switching_to_mapping: Calling service')
break
else:
rclpy.spin_once(self, timeout_sec=1.0)
self.get_logger().info('switching_to_mapping: Waiting for service to return')
while not future.done():
time.sleep(0.1)
self.get_logger().info('switching_to_mapping: Service returned')
I never reach that final log statement. Output side looks like this.
[control_node-21] 1636472070.912905585 [hugo_utils.hugo_control_node] [INFO] switching_to_mapping: Found node /navigation/map_server
[control_node-21] 1636472070.927478081 [hugo_utils.hugo_control_node] [INFO] switching_to_mapping: Waiting for service to become available
[control_node-21] 1636472070.929866791 [hugo_utils.hugo_control_node] [INFO] switching_to_mapping: Service is ready
[control_node-21] 1636472070.932301519 [hugo_utils.hugo_control_node] [INFO] switching_to_mapping: Calling service
[control_node-21] 1636472070.933709630 [hugo_utils.hugo_control_node] [INFO] switching_to_mapping: Waiting for service to return
Meanwhile, service caller,
# ros2 service call /hugo_utils/switch_to_mapping std_srvs/srv/Trigger
requester: making request: std_srvs.srv.Trigger_Request()
Making sure that service is available and can be called
# ros2 service call /navigation/map_server/get_available_transitions lifecycle_msgs/srv/GetAvailableTransitions
requester: making request: lifecycle_msgs.srv.GetAvailableTransitions_Request()
response:
lifecycle_msgs.srv.GetAvailableTransitions_Response(available_transitions=[lifecycle_msgs.msg.TransitionDescription(transition=lifecycle_msgs.msg.Transition(id=4, label='deactivate'), start_state=lifecycle_msgs.msg.State(id=3, label='active'), goal_state=lifecycle_msgs.msg.State(id=14, label='deactivating')), lifecycle_msgs.msg.TransitionDescription(transition=lifecycle_msgs.msg.Transition(id=7, label='shutdown'), start_state=lifecycle_msgs.msg.State(id=3, label='active'), goal_state=lifecycle_msgs.msg.State(id=12, label='shuttingdown'))])
What is going on here? Why does my node not call the service even though it can be found?
Is the indentation in your code correct? Remember that in Python indentation creates a scope, so your variables might be going out of scope. Also the
future
probably goes out of scope when thewhile
loop exits. You need to make the variable exist outside of the while loop.I would think the scope is correct, but at this rate python never ceases to surprise me. If a variable has gone out of scope, surely it would crash?