Hi,
I’ve coded this up, just as an idea to have a non-blocking ActionClient.wait_for_server
in rclpy.
Just sharing it here in case someone would be interested
import time
async def coro_wait_for_server(self, timeout_sec=None):
"""
Coroutine - waits for an action server to be ready using asyncio.
It was created to make the `ActionClient.wait_for_server` async.
Returns as soon as an action server is ready for this client.
:param timeout_sec: Number of seconds to wait until an action server is available.
If None, then wait indefinitely.
:return: True if an action server is available, False if the timeout is exceeded.
"""
# `time.monotonic()` is used because "Event loop uses monotonic clocks to track time", so just in case:
# https://docs.python.org/3/library/asyncio-eventloop.html#scheduling-delayed-callbacks
timeout_time = (time.monotonic() + timeout_sec) if timeout_sec is not None else float('inf')
while self._node.context.ok() and not self.server_is_ready() and time.monotonic() < timeout_time:
asyncio.sleep(0) # releases control to other coroutines in the event loop
return self.server_is_ready()
# Assign this new method to the `ActionClient` class
ActionClient.coro_wait_for_server = coro_wait_for_server
# Usage:
# instead of the blocking:
server_is_ready: bool = my_action_client.wait_for_server(timeout_sec=2.0)
# now we can:
server_is_ready: bool = await my_action_client.coro_wait_for_server(timeout_sec=2.0)