rtt_rosclock_sim_clock_thread.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2013, Johannes Meyer, TU Darmstadt
5  * Copyright (c) 2013, Intermodalics BVBA
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of TU Darmstadt and Intermodalics BVBA
19  * nor the names of its contributors may be
20  * used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * Copyright (c) 2014, Jonathan Bohren, The Johns Hopkins University
37  * - Generalized for multiple time sources
38  * - Integrated with rtt_rosclock package
39  *********************************************************************/
40 
44 
45 #include <rtt/TaskContext.hpp>
47 #include <rtt/plugin/Plugin.hpp>
48 
50 
51 #include <ros/time.h>
52 #include <ros/node_handle.h>
53 #include <ros/param.h>
54 #include <ros/subscribe_options.h>
55 
57 
58 using namespace rtt_rosclock;
59 
61 
63 {
64  return singleton;
65 }
66 
68 {
69  // Create a new singleton, if necessary
71  if(!shared) {
72  shared.reset(new SimClockThread());
73  singleton = shared;
74  }
75 
76  return shared;
77 }
78 
80 {
81  singleton.reset();
82 }
83 
84 namespace {
86 }
87 
89  : RTT::os::Thread(ORO_SCHED_OTHER, RTT::os::LowestPriority, 0.0, 0, "rtt_rosclock_SimClockThread")
90  , time_service_(RTT::os::TimeService::Instance())
92  , process_callbacks_(false)
93 {
94 }
95 
97 {
98  this->stop();
99 }
100 
102 {
103  // Don't allow changing the source while running
104  if(this->isActive()) {
105  RTT::log(RTT::Error) << "The SimClockThread clock source cannot be changed while the thread is running." << RTT::endlog();
106  return false;
107  }
108 
109  // Set the clock source
110  clock_source_ = clock_source;
111 
112  return true;
113 }
114 
116 {
118 }
119 
121 {
123 }
124 
126 {
127  return this->isActive();
128 }
129 
130 void SimClockThread::clockMsgCallback(const rosgraph_msgs::ClockConstPtr& clock)
131 {
132  // Update the RTT clock
133  updateClockInternal(ros::Time(clock->clock.sec, clock->clock.nsec));
134 }
135 
137 {
139  RTT::log(RTT::Error) << "Cannot update simulation clock manually unless the clock source is set to MANUAL_CLOCK." << RTT::endlog();
140  return false;
141  }
142 
143  return this->updateClockInternal(new_time);
144 }
145 
147 {
148  // Make sure the system time isn't being used
151  }
152 
153  // Check if time restarted
154  if(new_time.isZero()) {
155 
156  RTT::log(RTT::Warning) << "Time has reset to 0! Re-setting time service..." << RTT::endlog();
157 
158  // Re-set the time service and don't update the activities
159  this->resetTimeService();
160 
161  } else {
162  // Update the RTT time to match the sim time
163  using namespace RTT::os;
164  //TimeService::ticks rtt_ticks = time_service_->getTicks();
165  //TimeService::Seconds rtt_secs = RTT::nsecs_to_Seconds(TimeService::ticks2nsecs(rtt_ticks));
166 
167  // Compute the time update
168  TimeService::Seconds dt = (new_time - rtt_rosclock::rtt_now()).toSec();
169 
170  // Check if time went backwards
171  if(dt < 0) {
172  RTT::log(RTT::Warning) << "Time went backwards by " << dt << " seconds! (" << rtt_rosclock::rtt_now() << " --> " << new_time <<")" << RTT::endlog();
173  }
174 
175  // Update the RTT clock
177 
178  // Trigger all SimClockActivities
180  if (manager) {
181  // Update the simulation period
182  manager->setSimulationPeriod(dt);
183  // Update all the SimClockActivities
184  manager->update();
185  }
186  }
187 
188  return true;
189 }
190 
192 {
193  // We have to set the Logger reference time to zero in order to get correct logging timestamps.
194  // RTT::Logger::Instance()->setReferenceTime(0);
195  //
196  // Unfortunately this method is not available, therefore shutdown and restart logging.
197  // This workaround is not exact.
198 
199  // Shutdown the RTT Logger
201 
202  // Disable the RTT system clock so Gazebo can manipulate time and reset it to 0
204  assert(time_service_->systemClockEnabled() == false);
205 
207  assert(time_service_->getTicks() == 0);
208 
209  // Restart the RTT Logger with reference time 0
211  assert(RTT::Logger::Instance()->getReferenceTime() == 0);
212 }
213 
215 {
216 
217  RTT::log(RTT::Debug) << "[rtt_rosclock] Attempting to enable global simulation clock source..." << RTT::endlog();
218 
219  switch(clock_source_)
220  {
222  {
223  // Get /use_sim_time parameter from ROS
224  bool use_sim_time = false;
225  ros::param::get("/use_sim_time", use_sim_time);
226 
227  if(!use_sim_time) {
228  RTT::log(RTT::Error) << "[rtt_rosclock] Did not enable ROS simulation clock because the ROS parameter '/use_sim_time' is not set to true." << RTT::endlog();
229  process_callbacks_ = false;
230  return false;
231  }
232 
233  RTT::log(RTT::Debug) << "[rtt_rosclock] Switching to simulated time based on ROS /clock topic..." << RTT::endlog();
234 
235  // Reset the timeservice and logger
236  this->resetTimeService();
237 
238  // Subscribe the /clock topic (simulation time, e.g. published by Gazebo)
239  ros::SubscribeOptions ops = ros::SubscribeOptions::create<rosgraph_msgs::Clock>(
240  "/clock", 1, boost::bind(&SimClockThread::clockMsgCallback, this, _1),
243 
244  // The loop needs to run in order to call the callback queue
245  process_callbacks_ = true;
246  }
247  break;
248 
250  {
251  RTT::log(RTT::Debug) << "[rtt_rosclock] Switching to simulated time based on a manual clock source..." << RTT::endlog();
252 
253  // Reset the timeservice and logger
254  this->resetTimeService();
255 
256  // We're not processing the callback queue, so we won't loop.
257  process_callbacks_ = false;
258  }
259  break;
260 
261  default:
262  {
263  RTT::log(RTT::Error) << "Unknown simulation clock source for SimClockThread!" << RTT::endlog();
264  return false;
265  }
266  };
267 
268  return true;
269 }
270 
272 {
273  static const ros::WallDuration timeout(0.1);
274 
275  // Service callbacks while
276  while(process_callbacks_) {
278  }
279 }
280 
282 {
283  process_callbacks_ = false;
284  return true;
285 }
286 
288 {
289  RTT::log(RTT::Info) << "Disabling simulated time..." << RTT::endlog();
290 
291  // Shutdown the subscriber so no more clock message events will be handled
293 
294  // Shutdown the RTT Logger
296 
297  // Re-enable system clock
299 
300  // Restart the RTT Logger with reference walltime
302 }
303 
boost::shared_ptr< void const > VoidConstPtr
bool useManualClock()
Set the clock source to use a manual source, i.e. call updateClock() manually.
bool updateClockInternal(const ros::Time new_time)
Update the RTT clock and SimClockActivities with a new time (see updateClock() for manually updating)...
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
static Logger * Instance(std::ostream &str=std::cerr)
void shutdown()
ticks ticksChange(ticks delta)
void resetTimeService()
Re-set the RTT::os::TimeService to zero and restart logging.
static boost::shared_ptr< SimClockThread > GetInstance()
Get an instance to the singleton SimClockThread or NULL.
bool useROSClockTopic()
Set the clock source to use the ROS /clock topic.
static boost::shared_ptr< SimClockActivityManager > GetInstance()
Get an instance of the singleton if it exists, null pointer otherwise.
bool systemClockEnabled() const
SimClockSource
Simulation clock sources.
ros::Subscriber clock_subscriber_
ROS /clock topic subscriber.
ros::NodeHandle nh_
ROS NodeHandle for communication.
ROSCPP_DECL bool get(const std::string &key, std::string &s)
void startup()
virtual bool isActive() const
static boost::shared_ptr< SimClockThread > Instance()
Get an instance to the singleton SimClockThread or create one.
void enableSystemClock(bool yes_no)
static void Release()
Release the singleton SimClockThread.
ticks ticksSince(ticks relativeTime) const
bool updateClock(const ros::Time new_time)
ros::CallbackQueue callback_queue_
Custom callback queue used in this thread.
void clockMsgCallback(const rosgraph_msgs::ClockConstPtr &clock)
ROS message callback for /clock topic.
bool simTimeEnabled() const
Check if simulation time is enabled.
static boost::shared_ptr< SimClockThread > singleton
SimClockThread singleton.
Thread(int scheduler, int priority, double period, unsigned cpu_affinity, const std::string &name)
const int LowestPriority
virtual bool stop()
bool setClockSource(SimClockSource clock_source)
Set the simulation clock source by ID (see ClockSource enum)
const ros::Time rtt_now()
Get the current time according to RTT.
bool process_callbacks_
Keep running the thread loop if this is set to true.
static Logger & log()
#define ORO_SCHED_OTHER
Seconds secondsChange(Seconds delta)
static Logger::LogFunction endlog()
SimClockThread()
Constructor is protected, use Instance() to create and get a singleton.
RTT::os::TimeService * time_service_
Convenient pointer to RTT time service.
SimClockSource clock_source_
Current clock source.
ticks getTicks() const


rtt_rosclock
Author(s):
autogenerated on Sat Jun 8 2019 18:06:00