isolated_async_timer.h
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2018, University of Luxembourg
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of University of Luxembourg nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  * Author: Maciej Zurad
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 }  // namespace robot_activity
00311 
00312 #endif  // ROBOT_ACTIVITY_ISOLATED_ASYNC_TIMER_H


robot_activity
Author(s): Maciej ZURAD
autogenerated on Thu Jun 6 2019 18:10:04