mrs_lib
Various reusable classes, functions and utilities for use in MRS projects
Loading...
Searching...
No Matches
rate_throttle.hpp
1#ifndef MRS_LIB_INTERNAL_RATE_THROTTLE_HPP_
2#define MRS_LIB_INTERNAL_RATE_THROTTLE_HPP_
3
4#include <algorithm>
5#include <chrono>
6#include <cmath>
7#include <cstdint>
8#include <limits>
9#include <optional>
10
11#include <rclcpp/duration.hpp>
12#include <rclcpp/time.hpp>
13
14namespace mrs_lib::internal
15{
16
27 {
28 public:
32 explicit RateThrottle(const double rate) : RateThrottle(std::chrono::nanoseconds(rate > 0 ? std::llround(std::min(1e9 / rate, double(max_period_ns_))) : 0))
33 {
34 }
35
39 explicit RateThrottle(const std::chrono::nanoseconds period)
40 : period_(rclcpp::Duration::from_nanoseconds(std::clamp<int64_t>(period.count(), 0, max_period_ns_))),
41 jitter_tolerance_(rclcpp::Duration::from_nanoseconds(period_.nanoseconds() / 4)),
42 max_catch_up_(rclcpp::Duration::from_nanoseconds(period_.nanoseconds() / 2)),
43 clock_jump_threshold_(rclcpp::Duration::from_nanoseconds((3 * period_.nanoseconds()) / 2))
44 {
45 }
46
56 bool accept(const rclcpp::Time& now)
57 {
58 if (period_.nanoseconds() <= 0)
59 {
60 return true;
61 }
62
63 // first message, or the clock jumped backwards (e.g., sim time reset)
64 if (!next_deadline_ || now < *next_deadline_ - clock_jump_threshold_)
65 {
66 next_deadline_ = now;
67 }
68
69 if (now < *next_deadline_ - jitter_tolerance_)
70 {
71 return false;
72 }
73
74 next_deadline_ = std::max(*next_deadline_ + period_, now + max_catch_up_);
75
76 return true;
77 }
78
79 private:
80 // keeps the deadline arithmetic far from int64 overflow (~73 years)
81 static constexpr int64_t max_period_ns_ = std::numeric_limits<int64_t>::max() / 4;
82
83 rclcpp::Duration period_;
84
85 rclcpp::Duration jitter_tolerance_; // a message this much before the deadline still passes
86 rclcpp::Duration max_catch_up_; // the next deadline is at least this far after a passed message, limits catch-up after a pause
87 rclcpp::Duration clock_jump_threshold_; // a message this much before the deadline means the clock jumped backwards
88
89 std::optional<rclcpp::Time> next_deadline_;
90 };
91
92} // namespace mrs_lib::internal
93
94#endif // MRS_LIB_INTERNAL_RATE_THROTTLE_HPP_
bool accept(const rclcpp::Time &now)
decide whether a message arriving at now should be passed (and register it if so)
Definition rate_throttle.hpp:56
RateThrottle(const double rate)
Definition rate_throttle.hpp:32
RateThrottle(const std::chrono::nanoseconds period)
Definition rate_throttle.hpp:39