Use callback groups to allow an Action to trigger a service of the same Node
I have a Node that hosts an Action and a Service Client:
callback_group=ReentrantCallbackGroup()
self.__driver = GrappleCraneDriverClient(self, callback_group)
self.move_joint_absolute_action_server = ActionServer(self,
action_type=MoveJointAbsolute,
action_name='move_joint_absolute',
execute_callback=move_joint_absolute_execute_callback,
goal_callback=move_joint_absolute_goal_callback,
cancel_callback=move_joint_absolute_cancel_callback,
callback_group=callback_group
)
The service client adds clients to the Node:
class GrappleCraneDriverClient:
def __init__(self, node: Node, callback_group=None):
self.__node = node
# Service clients
self.__move_x_abs=node.create_client(
srv_type=MoveOneAxis,
srv_name='accs/grapple_crane/service/move_x_abs',
callback_group=callback_group
)
def move_x_abs(self, target_position: float) -> MoveOneAxis_Response:
self.__node.get_logger().info(
f'[GrappleCraneDriverClient]: calling service {self.__move_x_abs.srv_name}')
future_trigger_result = self.__move_x_abs.call_async(
MoveOneAxis_Request(target_position=target_position))
try:
return asyncio.run(asyncio.wait_for(future_trigger_result, timeout=5))
except asyncio.TimeoutError as e:
self.__node.get_logger().error(f'TimeoutError: {e}')
return MoveOneAxis_Response(success=False, message=f'TimeoutError: {e}')
The Node hosting the services is running in a different process.
If I test the GrappleCraneDriverClient
by constructing it with a new Node, and then launching it in the same process as the Node that hosts the services, then it works fine.
However when I use the GrappleCraneDriverClient
to compose part of my Node that hosts the actions, then I get a timeout error because the service never gets called.
Why would this be?
A key difference between the test code (which works), and the action server code is that in the action server a callback is already running (the movejointabsoluteexecutecallback) when the service is called. However, I am using a ReentrantCallbackGroup()
, so this should allow the callbacks to run at the same time, should it not?
I am also using a MultiThreadedExecutor
.
If I give the GrappleCraneDriverClient
a new Node and run that Node alongside the Node hosting the action (but still in the same process), it also works.
How do I correctly get the service to be called while the action is running, and have the client and action server elonging to the same Node?
Thanks.
Asked by CraigH92 on 2021-03-08 10:31:39 UTC
Comments
I tried to think of the root cause but it was way beyond me. Just a small clarification: Can we assume
GrappleCraneDriverClient.move_x_abs
gets called from the callbackmove_joint_absolute_goal_callback
?Asked by 130s on 2023-05-07 10:30:12 UTC
In the example above, it calls the service from the
execute_callback
.In the latest version, it gets called from the
handle_accepted_callback
.I have used the
goal_callback
to determine if it should be accepted or rejected, thehandle_accepted_callback
then writes to the hardware and polls the system until the motion has started, and then theexecute_callback
polls the system to see if it has succeeded, failed, or been canceled.It now works, although I am not sure if this is due to this change, or if it is because I am now using humle.
Asked by CraigH92 on 2023-05-09 03:37:37 UTC