rclpy: just idea - asynchronous ActionClient.wait_for_server

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)
1 Like