Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00044 #ifndef ROBOT_ACTIVITY_ISOLATED_ASYNC_TIMER_H
00045 #define ROBOT_ACTIVITY_ISOLATED_ASYNC_TIMER_H
00046
00047 #include <atomic>
00048
00049 #include <ros/ros.h>
00050 #include <ros/console.h>
00051 #include <ros/callback_queue.h>
00052
00053 namespace robot_activity
00054 {
00055
00062 class IsolatedAsyncTimer
00063 {
00064 public:
00065 typedef std::function<void(void)> LambdaCallback;
00066
00071 IsolatedAsyncTimer() = delete;
00072
00088 IsolatedAsyncTimer(const ros::NodeHandle& node_handle,
00089 const IsolatedAsyncTimer::LambdaCallback& callback,
00090 const float& frequency,
00091 bool stoppable = true,
00092 bool autostart = true,
00093 bool oneshot = false)
00094 : IsolatedAsyncTimer(node_handle,
00095 to_timer_callback(callback),
00096 frequency,
00097 stoppable,
00098 autostart,
00099 oneshot) { }
00100
00117 IsolatedAsyncTimer(const ros::NodeHandle& node_handle,
00118 const ros::TimerCallback& callback,
00119 const float& frequency,
00120 bool stoppable = true,
00121 bool autostart = true,
00122 bool oneshot = false)
00123 : node_handle_(node_handle),
00124 timer_ops_(),
00125 callback_queue_(),
00126 stoppable_(stoppable),
00127 paused_(true)
00128 {
00129 callback_ = wrapTimerCallback(callback);
00130
00131 frequency_ = frequency;
00132 period_ = ros::Duration(1.0 / frequency);
00133
00134 timer_ops_.period = period_;
00135 timer_ops_.callback = callback_;
00136 timer_ops_.callback_queue = &callback_queue_;
00137 timer_ops_.oneshot = oneshot;
00138 timer_ops_.autostart = autostart;
00139
00140 timer_ = std::make_shared<ros::Timer>();
00141 *timer_ = node_handle_.createTimer(timer_ops_);
00142
00143 spinner_ = std::make_shared<ros::AsyncSpinner>(1, &callback_queue_);
00144 spinner_->start();
00145 }
00146
00150 ~IsolatedAsyncTimer()
00151 {
00152 ROS_DEBUG("IsolatedAsyncTimer destructor");
00153 }
00154
00158 void start()
00159 {
00160 timer_->start();
00161 }
00162
00166 void stop()
00167 {
00168 if (stoppable_)
00169 timer_->stop();
00170 }
00171
00175 void pause()
00176 {
00177 paused_ = true;
00178 }
00179
00183 void resume()
00184 {
00185 paused_ = false;
00186 }
00187
00191 bool isValid()
00192 {
00193 return timer_->isValid();
00194 }
00195
00206 void setRate(const float& frequency, bool reset = true)
00207 {
00208 frequency_ = frequency;
00209 period_ = ros::Duration(1.0 / frequency);
00210 timer_->setPeriod(period_, reset);
00211 }
00212
00219 static ros::TimerCallback to_timer_callback(
00220 const IsolatedAsyncTimer::LambdaCallback& callback)
00221 {
00222 return [callback](const ros::TimerEvent & event)
00223 {
00224 callback();
00225 };
00226 }
00227
00228 private:
00237 ros::TimerCallback wrapTimerCallback(const ros::TimerCallback& callback) const
00238 {
00239 return [ = ](const ros::TimerEvent & ev)
00240 {
00241 if (stoppable_ == false || paused_ == false)
00242 {
00243 auto last_loop_duration = ev.profile.last_duration.toSec();
00244 if (ev.last_real.toSec() != 0 && last_loop_duration > period_.toSec())
00245 {
00246 auto lag = last_loop_duration - period_.toSec();
00247 ROS_WARN_STREAM_THROTTLE(1,
00248 "Missed it's desired rate of " << frequency_ <<
00249 " [Hz], the loop actually took " << last_loop_duration
00250 << " [s], which is " << lag << " [s] longer");
00251 }
00252 callback(ev);
00253 }
00254 };
00255 }
00256
00260 ros::NodeHandle node_handle_;
00261
00265 float frequency_;
00266
00270 ros::Duration period_;
00271
00275 ros::TimerOptions timer_ops_;
00276
00280 ros::TimerCallback callback_;
00281
00285 ros::CallbackQueue callback_queue_;
00286
00287
00291 std::shared_ptr<ros::Timer> timer_;
00292
00297 std::shared_ptr<ros::AsyncSpinner> spinner_;
00298
00302 std::atomic<bool> stoppable_;
00303
00307 std::atomic<bool> paused_;
00308 };
00309
00310 }
00311
00312 #endif // ROBOT_ACTIVITY_ISOLATED_ASYNC_TIMER_H