Why does async client call block timer callback

asked 2022-09-14 10:14:36 -0500

gdroge gravatar image

updated 2022-09-15 07:12:58 -0500

ravijoshi gravatar image

I have an issue where my async client call seems to block the timer callback.

I have created a simple example by modifying the service tutorial code to have a timer function that makes a service call. When I run it using the call_async(...) method, the client completes, but the timer function never gets called again. The resulting output is

[INFO] [1663166937.600692028] [minimal_client_async]: send_request: enter
[INFO] [1663166937.602566992] [minimal_client_async]: send_request: exit
[INFO] [1663166937.602842863] [minimal_client_async]: Result of add_two_ints: for 4 + 2 = 6

If I instead make a call to the call(...) method then the output repeats indefinitely.

[INFO] [1663168270.133728816] [minimal_client_async]: send_request: enter
[INFO] [1663168270.134015634] [minimal_client_async]: send_request: exit
[INFO] [1663168270.136338613] [minimal_client_async]: Result of add_two_ints: for 4 + 2 = 6
[INFO] [1663168271.125882562] [minimal_client_async]: send_request: enter
[INFO] [1663168271.126730859] [minimal_client_async]: send_request: exit
[INFO] [1663168271.132774293] [minimal_client_async]: Result of add_two_ints: for 4 + 2 = 6
[INFO] [1663168272.124292254] [minimal_client_async]: send_request: enter
[INFO] [1663168272.124570905] [minimal_client_async]: send_request: exit
[INFO] [1663168272.126700274] [minimal_client_async]: Result of add_two_ints: for 4 + 2 = 6

Why does the async call stop the timer callback?

from example_interfaces.srv import AddTwoInts
import rclpy
from rclpy.node import Node

from rclpy.executors import MultiThreadedExecutor, SingleThreadedExecutor
from rclpy.callback_groups import MutuallyExclusiveCallbackGroup
from rclpy.callback_groups import ReentrantCallbackGroup


class MinimalClientAsync(Node):

    def __init__(self):
        super().__init__('minimal_client_async')
        self.client_cb = MutuallyExclusiveCallbackGroup()
        self.timer_cb = MutuallyExclusiveCallbackGroup() # ReentrantCallbackGroup()
        self.cli = self.create_client(AddTwoInts, 'add_two_ints', callback_group=self.client_cb)
        while not self.cli.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('service not available, waiting again...')
        self.req = AddTwoInts.Request()

        # Create a timer for the main loop execution
        self.timer = self.create_timer(1.0, self.main_loop, callback_group=self.timer_cb)

    def send_request(self, a, b):
        self.get_logger().info("send_request: enter")
        self.req.a = a
        self.req.b = b

        # Uncomment for async call - Note that this blocks
        future = self.cli.call_async(self.req)
        rclpy.spin_until_future_complete(self, future)
        self.get_logger().info("send_request: exit")
        return future.result()

        # # Uncomment for syncronous call - Note that this does not block
        # self.get_logger().info("send_request: exit")
        # return self.cli.call(self.req)

    def main_loop(self) -> None:
        response = self.send_request(4, 2)
        self.get_logger().info(
        'Result of add_two_ints: for %d + %d = %d' %
        (4, 2, response.sum))

def main(args=None):
    rclpy.init(args=args)

    minimal_client = MinimalClientAsync()

    executor = MultiThreadedExecutor()
    executor.add_node(minimal_client)
    executor.spin()

    rclpy.shutdown()


if __name__ == '__main__':
    main()
edit retag flag offensive close merge delete

Comments

It was suggested that I try to specify the number of threads in the MultiThreadedExecutor. I changed the initialization of the executor to executor = MultiThreadedExecutor(num_threads=4), but got the same result. I tried to specify the number of threads from 1 to 10 and nothing changed.

gdroge gravatar image gdroge  ( 2022-09-15 08:00:03 -0500 )edit