ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

ROS2 Service Client freezes when calling twice

asked 2020-05-12 04:16:55 -0600

RodBelaFarin gravatar image

updated 2020-05-12 04:18:51 -0600

Service clients seem to freeze, if you are calling them more then just one time in ROS2.

I slightly modified the demo example from here:

https://github.com/ros2/examples/blob...

If I just remove the break like that:

future = cli.call_async(req)
while rclpy.ok():
    rclpy.spin_once(node)
    if future.done():
        try:
            result = future.result()
        except Exception as e:
            node.get_logger().info('Service call failed %r' % (e,))
        else:
            node.get_logger().info(
                'Result of add_two_ints: for %d + %d = %d' %
                (req.a, req.b, result.sum))

node.destroy_node()
rclpy.shutdown()

This way the loop is called multiple times and should print the service response multiple times as well. This ends in the result that I get the client output twice:

[INFO] [minimal_client_async]: Result of add_two_ints: for 41 + 1 = 42
[INFO] [minimal_client_async]: Result of add_two_ints: for 41 + 1 = 42

And the service server output appears only once:

[INFO] [minimal_service]: Incoming request
a: 41 b: 1

If I now additionally move the service call itself future = cli.call_async(req) inside the loop, I am expecting the request to be sent multiple times. (Yes, I know that Services are not made to be called frequently, it's just to keep the example simple.)

while rclpy.ok():
    future = cli.call_async(req)
    rclpy.spin_once(node)
    if future.done():
        try:
            result = future.result()
        except Exception as e:
            node.get_logger().info('Service call failed %r' % (e,))
        else:
            node.get_logger().info(
                'Result of add_two_ints: for %d + %d = %d' %
                (req.a, req.b, result.sum))

node.destroy_node()
rclpy.shutdown()

This results in printing from the client only once:

[INFO] [minimal_client_async]: Result of add_two_ints: for 41 + 1 = 42

But the service server seems anyway to be requested frequently, because it is continuously printing to the terminal:

[INFO] [minimal_service]: Incoming request
a: 41 b: 1
[INFO] [minimal_service]: Incoming request
a: 41 b: 1
[INFO] [minimal_service]: Incoming request
a: 41 b: 1
[INFO] [minimal_service]: Incoming request
a: 41 b: 1
...

I would just like to call a service multiple times from the client. For example I would like to use a button to stop my robot by calling the service, if the button is pressed (which might result in sending cmd_vel: 0) and as soon as it is released again, the robot should be able to move on. Any ideas on how to solve this?

I am using Ubuntu 18.04 in a VM with ROS2 Eloquent installed.

It is easy to reproduce this by using the service examples from here:

https://github.com/ros2/examples/tree...

edit retag flag offensive close merge delete

2 Answers

Sort by » oldest newest most voted
0

answered 2020-12-14 06:56:32 -0600

I also faced a same problem, so I tried that fixed this code.

Use a following code if you like:

from example_interfaces.srv import AddTwoInts

import rclpy
import random


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

    node = rclpy.create_node('minimal_client_async')

    cli = node.create_client(AddTwoInts, 'add_two_ints')

    req = AddTwoInts.Request()
    # req.a = 41
    # req.b = 1
    while not cli.wait_for_service(timeout_sec=1.0):
        node.get_logger().info('service not available, waiting again...')

    # future = cli.call_async(req)
    while rclpy.ok():
        req.a = random.randrange(10)
        req.b = random.randrange(10)
        future = cli.call_async(req)
        # rclpy.spin_once(node)
        rclpy.spin_until_future_complete(node, future)
        if future.done():
            try:
                result = future.result()
            except Exception as e:
                node.get_logger().info('Service call failed %r' % (e,))
            else:
                node.get_logger().info(
                    'Result of add_two_ints: for %d + %d = %d' %
                    (req.a, req.b, result.sum))
            # break

    node.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

[environment]
・Ubuntu 20.04.01 LTS (docker)
・ROS2 Foxy
edit flag offensive delete link more
0

answered 2021-12-02 18:43:03 -0600

achille gravatar image

The problem with the code when you add the future inside the loop is that you're overwriting the future before the service even returns. You're probably calling it hundreds of times per second and the service takes much longer than that to finish. As pointed out in the answer by ksato-dev, you can just wait for each future to complete, or you could initialize and add to a list of futures if you're trying to execute many service calls simultaneously.

edit flag offensive delete link more

Question Tools

2 followers

Stats

Asked: 2020-05-12 04:16:55 -0600

Seen: 1,956 times

Last updated: Dec 02 '21