I'm trying to figure out how to use rospy actionlib and asyncio to
wait asynchronously on the action result. For this purpose I tried
to write an action execution generator but haven't succeeded now.
My idea was to add a asyncio future to the done_callback
of the action
but the future seems to be never done in the end.
The code is here:
def _generate_action_executor(self, action):
async def run_action(goal):
action_done = asyncio.Future()
def done_callback(goal_status, result, future):
status = ActionLibGoalStatus(goal_status)
print('Action Done: {}'.format(status))
future.set_result(result)
action.send_goal(goal,
lambda x, y: done_callback(x,
y,
action_done))
try:
result = await action_done
#problem future never done
except asyncio.CancelledError as exc:
action.cancel()
raise exc
return result
return run_action
async def do_some_other_stuff(action):
//do stuff
my_goal = MyActionRequest('just do it')
run_action = self._generate_action_executor(action)
response = await run_action(my_goal)
return response
if __name__ == "__main__":
action = actionlib.SimpleActionClient('my_action',
MyAction)
try:
loop = asyncio.get_event_loop()
loop.run_until_complete(do_some_other_stuff(action))
finally:
loop.close()
Keep in mind that asyncio is meant to run in a single thread.
If the program needs to interact with other threads, you'll have to use one of the dedicated functions:
Here's a simplified example:
async def run_with_non_asyncio_lib(action, arg):
future = asyncio.Future()
loop = asyncio.get_event_loop()
def callback(*args):
loop.call_soon_threasafe(future.set_result, args)
non_asyncio_lib.register_callback(action, arg, callback)
callback_args = await future
return process(*callback_args)
Alternatively, loop.run_in_executor provides a way to interact with non-asyncio libraries by running the given function in its own thread:
async def run_with_non_asyncio_lib(action, arg):
loop = asyncio.get_event_loop()
future = loop.run_in_executor(None, non_asyncio_lib.run, action, arg)
result = await future
return result