202 lines
5.2 KiB
C++
202 lines
5.2 KiB
C++
// Copyright 2014 Open Source Robotics Foundation, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef RCLCPP__TIMER_HPP_
|
|
#define RCLCPP__TIMER_HPP_
|
|
|
|
#include <chrono>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <sstream>
|
|
#include <thread>
|
|
#include <type_traits>
|
|
|
|
#include "rclcpp/function_traits.hpp"
|
|
#include "rclcpp/macros.hpp"
|
|
#include "rclcpp/rate.hpp"
|
|
#include "rclcpp/utilities.hpp"
|
|
#include "rclcpp/visibility_control.hpp"
|
|
#include "rmw/error_handling.h"
|
|
#include "rmw/rmw.h"
|
|
|
|
namespace rclcpp
|
|
{
|
|
namespace timer
|
|
{
|
|
|
|
class TimerBase
|
|
{
|
|
public:
|
|
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(TimerBase);
|
|
|
|
RCLCPP_PUBLIC
|
|
TimerBase(std::chrono::nanoseconds period);
|
|
|
|
RCLCPP_PUBLIC
|
|
virtual ~TimerBase();
|
|
|
|
RCLCPP_PUBLIC
|
|
void
|
|
cancel();
|
|
|
|
RCLCPP_PUBLIC
|
|
virtual void
|
|
execute_callback() = 0;
|
|
|
|
/// Check how long the timer has until its next scheduled callback.
|
|
// \return A std::chrono::duration representing the relative time until the next callback.
|
|
virtual std::chrono::nanoseconds
|
|
time_until_trigger() = 0;
|
|
|
|
/// Is the clock steady (i.e. is the time between ticks constant?)
|
|
// \return True if the clock used by this timer is steady.
|
|
virtual bool is_steady() = 0;
|
|
|
|
/// Check if the timer needs to trigger the callback.
|
|
/**
|
|
* This function expects its caller to immediately trigger the callback after this function,
|
|
* since it maintains the last time the callback was triggered.
|
|
* \return True if the timer needs to trigger.
|
|
*/
|
|
virtual bool check_and_trigger() = 0;
|
|
|
|
protected:
|
|
std::chrono::nanoseconds period_;
|
|
|
|
bool canceled_;
|
|
};
|
|
|
|
|
|
using VoidCallbackType = std::function<void()>;
|
|
using TimerCallbackType = std::function<void(TimerBase &)>;
|
|
|
|
/// Generic timer templated on the clock type. Periodically executes a user-specified callback.
|
|
template<
|
|
typename FunctorT,
|
|
class Clock = std::chrono::high_resolution_clock,
|
|
typename std::enable_if<
|
|
rclcpp::function_traits::same_arguments<FunctorT, VoidCallbackType>::value ||
|
|
rclcpp::function_traits::same_arguments<FunctorT, TimerCallbackType>::value
|
|
>::type * = nullptr
|
|
>
|
|
class GenericTimer : public TimerBase
|
|
{
|
|
public:
|
|
RCLCPP_SMART_PTR_DEFINITIONS(GenericTimer);
|
|
|
|
/// Default constructor.
|
|
/**
|
|
* \param[in] period The interval at which the timer fires.
|
|
* \param[in] callback User-specified callback function.
|
|
*/
|
|
GenericTimer(std::chrono::nanoseconds period, FunctorT && callback)
|
|
: TimerBase(period), callback_(callback), loop_rate_(period)
|
|
{
|
|
/* Set last_triggered_time_ so that the timer fires at least one period after being created. */
|
|
last_triggered_time_ = Clock::now();
|
|
}
|
|
|
|
/// Default destructor.
|
|
virtual ~GenericTimer()
|
|
{
|
|
// Stop the timer from running.
|
|
cancel();
|
|
}
|
|
|
|
void
|
|
execute_callback()
|
|
{
|
|
execute_callback_delegate<>();
|
|
}
|
|
|
|
// void specialization
|
|
template<
|
|
typename CallbackT = FunctorT,
|
|
typename std::enable_if<
|
|
rclcpp::function_traits::same_arguments<CallbackT, VoidCallbackType>::value
|
|
>::type * = nullptr
|
|
>
|
|
void
|
|
execute_callback_delegate()
|
|
{
|
|
callback_();
|
|
}
|
|
|
|
template<
|
|
typename CallbackT = FunctorT,
|
|
typename std::enable_if<
|
|
rclcpp::function_traits::same_arguments<CallbackT, TimerCallbackType>::value
|
|
>::type * = nullptr
|
|
>
|
|
void
|
|
execute_callback_delegate()
|
|
{
|
|
//callback_(std::move(std::shared_ptr<TimerBase>(this)));
|
|
callback_(*this);
|
|
}
|
|
|
|
bool
|
|
check_and_trigger()
|
|
{
|
|
if (canceled_) {
|
|
return false;
|
|
}
|
|
if (Clock::now() < last_triggered_time_) {
|
|
return false;
|
|
}
|
|
if (std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now() - last_triggered_time_) >=
|
|
loop_rate_.period())
|
|
{
|
|
last_triggered_time_ = Clock::now();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::chrono::nanoseconds
|
|
time_until_trigger()
|
|
{
|
|
std::chrono::nanoseconds time_until_trigger;
|
|
// Calculate the time between the next trigger and the current time
|
|
if (last_triggered_time_ + loop_rate_.period() < Clock::now()) {
|
|
// time is overdue, need to trigger immediately
|
|
time_until_trigger = std::chrono::nanoseconds::zero();
|
|
} else {
|
|
time_until_trigger = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
|
last_triggered_time_ - Clock::now()) + loop_rate_.period();
|
|
}
|
|
return time_until_trigger;
|
|
}
|
|
|
|
virtual bool
|
|
is_steady()
|
|
{
|
|
return Clock::is_steady;
|
|
}
|
|
|
|
protected:
|
|
RCLCPP_DISABLE_COPY(GenericTimer);
|
|
|
|
FunctorT callback_;
|
|
rclcpp::rate::GenericRate<Clock> loop_rate_;
|
|
std::chrono::time_point<Clock> last_triggered_time_;
|
|
};
|
|
|
|
template<typename CallbackType>
|
|
using WallTimer = GenericTimer<CallbackType, std::chrono::steady_clock>;
|
|
|
|
} // namespace timer
|
|
} // namespace rclcpp
|
|
|
|
#endif // RCLCPP__TIMER_HPP_
|