refactor timers to use rates
This commit is contained in:
parent
55487d4782
commit
7b8b318e6e
1 changed files with 50 additions and 40 deletions
|
@ -21,10 +21,19 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include <ros_middleware_interface/functions.h>
|
||||||
|
#include <ros_middleware_interface/handles.h>
|
||||||
|
|
||||||
#include <rclcpp/macros.hpp>
|
#include <rclcpp/macros.hpp>
|
||||||
|
#include <rclcpp/rate.hpp>
|
||||||
|
#include <rclcpp/utilities.hpp>
|
||||||
|
|
||||||
namespace rclcpp
|
namespace rclcpp
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Forward declaration is for friend statement in GenericTimer
|
||||||
|
namespace executor {class Executor;}
|
||||||
|
|
||||||
namespace timer
|
namespace timer
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -32,58 +41,65 @@ typedef std::function<void()> CallbackType;
|
||||||
|
|
||||||
class TimerBase
|
class TimerBase
|
||||||
{
|
{
|
||||||
|
friend class rclcpp::executor::Executor;
|
||||||
public:
|
public:
|
||||||
RCLCPP_MAKE_SHARED_DEFINITIONS(TimerBase);
|
RCLCPP_MAKE_SHARED_DEFINITIONS(TimerBase);
|
||||||
|
|
||||||
virtual bool sleep() = 0;
|
TimerBase(std::chrono::nanoseconds period, CallbackType callback)
|
||||||
|
: period_(period),
|
||||||
|
callback_(callback),
|
||||||
|
canceled_(false)
|
||||||
|
{
|
||||||
|
guard_condition_ = ros_middleware_interface::create_guard_condition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cancel()
|
||||||
|
{
|
||||||
|
this->canceled_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool is_steady() = 0;
|
virtual bool is_steady() = 0;
|
||||||
virtual void reset() = 0;
|
|
||||||
|
protected:
|
||||||
|
std::chrono::nanoseconds period_;
|
||||||
|
CallbackType callback_;
|
||||||
|
ros_middleware_interface::GuardConditionHandle guard_condition_;
|
||||||
|
|
||||||
|
bool canceled_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Clock = std::chrono::high_resolution_clock>
|
template<class Clock = std::chrono::high_resolution_clock>
|
||||||
class GenericTimer : public TimerBase
|
class GenericTimer : public TimerBase
|
||||||
{
|
{
|
||||||
|
friend class rclcpp::executor::Executor;
|
||||||
public:
|
public:
|
||||||
RCLCPP_MAKE_SHARED_DEFINITIONS(GenericTimer);
|
RCLCPP_MAKE_SHARED_DEFINITIONS(GenericTimer);
|
||||||
|
|
||||||
GenericTimer(std::chrono::nanoseconds period)
|
GenericTimer(std::chrono::nanoseconds period, CallbackType callback)
|
||||||
: period_(period)
|
: TimerBase(period, callback), loop_rate_(period)
|
||||||
{
|
{
|
||||||
|
thread_ = std::thread(&GenericTimer<Clock>::run, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool
|
~GenericTimer()
|
||||||
sleep()
|
|
||||||
{
|
{
|
||||||
// Time coming into sleep
|
cancel();
|
||||||
auto now = Clock::now();
|
|
||||||
// Time of next interval
|
|
||||||
auto next_interval = last_interval_ + period_;
|
|
||||||
// Detect backwards time flow
|
|
||||||
if (now < last_interval_)
|
|
||||||
{
|
|
||||||
// Best thing to do is to set the next_interval to now + period
|
|
||||||
next_interval = now + period_;
|
|
||||||
}
|
}
|
||||||
// Calculate the time to sleep
|
|
||||||
auto time_to_sleep = next_interval - now;
|
void
|
||||||
// Update the interval
|
run()
|
||||||
last_interval_ += period_;
|
|
||||||
// If the time_to_sleep is negative or zero, don't sleep
|
|
||||||
if (time_to_sleep <= std::chrono::seconds(0))
|
|
||||||
{
|
{
|
||||||
// If an entire cycle was missed then reset next interval.
|
while (rclcpp::utilities::ok() && !this->canceled_)
|
||||||
// This might happen if the loop took more than a cycle.
|
|
||||||
// Or if time jumps forward.
|
|
||||||
if (now > next_interval + period_)
|
|
||||||
{
|
{
|
||||||
last_interval_ = now + period_;
|
loop_rate_.sleep();
|
||||||
|
if (!rclcpp::utilities::ok())
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// Either way do not sleep and return false
|
ros_middleware_interface::trigger_guard_condition(guard_condition_);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
// Sleep
|
|
||||||
std::this_thread::sleep_for(time_to_sleep);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool
|
virtual bool
|
||||||
|
@ -92,17 +108,11 @@ public:
|
||||||
return Clock::is_steady;
|
return Clock::is_steady;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void
|
|
||||||
reset()
|
|
||||||
{
|
|
||||||
last_interval_ = Clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RCLCPP_DISABLE_COPY(GenericTimer);
|
RCLCPP_DISABLE_COPY(GenericTimer);
|
||||||
|
|
||||||
std::chrono::nanoseconds period_;
|
std::thread thread_;
|
||||||
std::chrono::time_point<Clock> last_interval_;
|
rclcpp::rate::GenericRate<Clock> loop_rate_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue