EventsExecutor with an overrunning timer can lead to a burst of timer events
Los mantenedores suelen responder en 1 día
@alsora ya está trabajando en esto.
Desde el 27/3/2025.
Evaluación
Este issue todavía no se ha evaluado.
Descripción
Hi,
I recently found an issue with the EventsExecutor relating to timers. If a timer callback is running slower than its period then it will create multiple timer events inside the EventsExecutor. This leads to 2 issues:
- Other events will not run untill all queued timers events finish
- If the timer callback starts running faster than its period, a sudden burst of timer events will run.
Example:
The code to reproduce the following is given at the end. I am running ROS2 rolling (commit: fa63fcf) on Ubuntu 24.04.
The first node is running a timer at 1Hz with a callback that publishes a message before sleeping for 2 seconds. A second node listens and measures the time between messages. The sleep time can be changed via:
ros2 topic pub /sleep_time std_msgs/msg/Float32 data:\ 0.01 -1
| Timer | Listener |
|---|---|
|
|
Why does this happen?
From my understanding of the EventsExecutor, it will add a timer event after each period of the timer regardless of if the timer has finished running or if there are other timer events in the queue. This leads to a build up of timer events. This backlog is the underlying root cause for both 1 and 2. The backlog will delay other incoming events (such as messages) and lead to the burst of timer events when the running time drops.
Observed behavioral differences to other executors:
SingleThreadedExecutor
The SingleThreadedExecutor does not display either of the behaviors. If you publish a new message, its callback will be executed after the current timer. If the running time suddenly changes, the timer doesn't run faster than its period.
| Timer | Listener |
|---|---|
|
|
MultiThreadedExecutor
The MultiThreadedExecutor can suffer from 1 (solvable by changing the setup of the callback groups) but should not suffer from 2. The issue with 1 has already been raised by this other issue https://github.com/ros2/rclcpp/issues/2402.
| Timer | Listener |
|---|---|
|
|
Code to reproduce
Timer
#include <chrono>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
#include "std_msgs/msg/float32.hpp"
#include "std_msgs/msg/bool.hpp"
using namespace std::chrono_literals;
class Timer : public rclcpp::Node
{
public:
Timer()
: Node("timer")
{
auto callback_group = create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
rclcpp::SubscriptionOptions options;
options.callback_group = callback_group;
timer_ = this->create_wall_timer(1000ms, std::bind(&Timer::timer_callback, this));
sleep_time_sub_ = this->create_subscription<std_msgs::msg::Float32>(
"sleep_time", 10, std::bind(&Timer::sleep_time_callback, this, std::placeholders::_1), options);
publisher_ = this->create_publisher<std_msgs::msg::Bool>("msg", 10);
}
private:
void timer_callback()
{
rclcpp::Rate wait_time(1.0/sleep_time_);
RCLCPP_INFO_STREAM(get_logger(), "Sleeping for " << sleep_time_ << "s");
publisher_->publish(std_msgs::msg::Bool());
wait_time.sleep();
}
void sleep_time_callback(const std_msgs::msg::Float32::SharedPtr msg)
{
sleep_time_ = msg->data;
RCLCPP_INFO_STREAM(get_logger(), "Sleep changed to " << msg->data << "s");
}
private:
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Subscription<std_msgs::msg::Float32>::SharedPtr sleep_time_sub_;
rclcpp::Publisher<std_msgs::msg::Bool>::SharedPtr publisher_;
float sleep_time_{2.0f};
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
auto node = std::make_shared<Timer>();
rclcpp::experimental::executors::EventsExecutor executor;
// rclcpp::executors::SingleThreadedExecutor executor;
// rclcpp::executors::MultiThreadedExecutor executor;
executor.add_node(node);
executor.spin();
rclcpp::shutdown();
return 0;
}
Listener
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/bool.hpp"
class Listener : public rclcpp::Node
{
public:
Listener()
: Node("listener")
{
subscription_ =
this->create_subscription<std_msgs::msg::Bool>("msg", 10, std::bind(&Listener::callback, this, std::placeholders::_1));
}
void callback(std_msgs::msg::Bool::UniquePtr msg)
{
auto current_time = std::chrono::steady_clock::now();
// Calculate the time difference between the current time and the last received time
auto duration = std::chrono::duration_cast<std::chrono::duration<float>>(current_time - last_time_);
// Print the time difference in milliseconds
RCLCPP_INFO(get_logger(), "%.2fs since last msg", duration.count());
// Update the last time to the current time
last_time_ = current_time;
}
private:
std::chrono::steady_clock::time_point last_time_;
rclcpp::Subscription<std_msgs::msg::Bool>::SharedPtr subscription_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<Listener>());
rclcpp::shutdown();
return 0;
}
- Lenguaje dominante
- C++
- Estrellas
- 815
- Forks
- 572
- Merge medio
- 6 d 8 h
- PR fusionados (30 d)
- 20
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de ros2/rclcpp
-
enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
Los mantenedores suelen responder en 1 día
-
EventsCBGExecutor timers on ROS time stall after a backward /clock jumpPosiblemente ocupada @Yadunund la tomó hace 4 días. Abiertobug
Dificultad 4/5 3-5 días Aptitud para principiantes 30/100
Los mantenedores suelen responder en 1 día
-
Late /clock delivery under use_sim_time stalls node now() for ~0.33 s (found via ros2_control controller time)Posiblemente ocupada @JeremiahM37 la tomó hace 2 días. Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 10/100
ros2/rclcpp#3329 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
:farmer: Flaky EventsCBGExecutor test: reentrant callback group fails to run callbacks concurrentlyAbiertobug
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
Los mantenedores suelen responder en 1 día
-
Copy constructor exception leaks intra-process message allocationPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 3/5 1-2 días Aptitud para principiantes 35/100
Los mantenedores suelen responder en 1 día
Todos los issues de ros2/rclcpp
Issues similares
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 91/100
FujiNetWIFI/fujinet-firmware#2045 ·
Los mantenedores suelen responder en 1 día
-
(S1 - Need confirmation)
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
CleverRaven/Cataclysm-DDA#89159 ·
Los mantenedores suelen responder en 1 día
-
area:libnvmpi bug P3
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
gjrtimmer/jetson-nvmpi#33 ·
-
bug(wasi_crypto): ArrayOutput::pull reports the wrong all-pulled flagPosiblemente ocupada @Yashbhu la tomó hoy. Abierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 84/100
Los mantenedores suelen responder en 1 día
-
bug question
Dificultad 1/5 Menos de una hora Aptitud para principiantes 62/100