ros2 / rclc

ROS Client Library for the C language.
Apache License 2.0
118 stars 42 forks source link

[rclc] Executor: rcl_wait() returns immediately when there is new data but trigger condition is not satisfied #388

Open vtran5 opened 1 year ago

vtran5 commented 1 year ago

Issue template

Steps to reproduce the issue

Set executor trigger condition to be NOT rclc_executor_trigger_any. Call rclc_executor_spin() with non-zero timeout.

Expected behavior

The executor blocks until there is a handle that has new data. It then checks the trigger condition, if the condition is not satisfied, it will block again until there is a handle has another new data.

Actual behavior

Once there is new data and trigger condition is not satisfied, rcl_wait() returns immediately as the new data is not taken. This leads to the problem that the executor will consume resource until the trigger condition is satisfied.

Additional information

My proposed solution is to take new data before checking the trigger condition. If one callback has mutiple data coming in before the trigger condition, the new data can be overwritten or dropped depends on the callback's entity qos setting.

JanStaschulat commented 1 year ago

@vtran5. Yes, indeed.

Suppose the following setup:

The trigger waits only for message A, but frequently receives message B. In this case, the rclc executor will be in a busy loop because rcl_wait() will return immediately every invocation (because of availability of B and not taking it).

Your idea would be solution. However, it would also change the expected semantics of the trigger condition. That is: if the trigger condition is satisfied, then take all new messages at that timepoint from the DDS queue. Taking the data in-between could also work, but as the QoS parameter are considered well at DDS level, one would have to implement all QoS settings again in the rclc executor (also the ones regarding timing, e.g. keep data only for x ms ...)

I have another idea: if a new message creates a busy loop, then take it out of the rcl_wait set and "save it for later". Then, if the trigger-condition is satisfied, then create one additional invocation of the rcl_wait with all messages. It is also a more complex solution, but it

By the way, the same problem occurs in ROS 2 when using WaitSets. The example code wait_set_topics_with_different_rates.cpp, will create a busy loop if sub3 receives new data, but sub2 does not. So it would be good to come up with a well-designed general solution for this problem.