refactor timers to use rates

This commit is contained in:
William Woodall 2014-08-29 17:52:22 -07:00
parent 55487d4782
commit 7b8b318e6e

View file

@ -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_;
}; };