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 
00037 
00038 
00039 
00040 
00041 #include <rtt_rosclock/rtt_rosclock_sim_clock_thread.h>
00042 #include <rtt_rosclock/rtt_rosclock_sim_clock_activity.h>
00043 #include <rtt_rosclock/rtt_rosclock_sim_clock_activity_manager.h>
00044 
00045 #include <rtt/TaskContext.hpp>
00046 #include <rtt/internal/GlobalService.hpp>
00047 #include <rtt/plugin/Plugin.hpp>
00048 
00049 #include <rtt/os/StartStopManager.hpp>
00050 
00051 #include <ros/time.h>
00052 #include <ros/node_handle.h>
00053 #include <ros/param.h>
00054 #include <ros/subscribe_options.h>
00055 
00056 #include <rtt_rosclock/rtt_rosclock.h>
00057 
00058 using namespace rtt_rosclock;
00059 
00060 boost::shared_ptr<SimClockThread> SimClockThread::singleton;
00061 
00062 boost::shared_ptr<SimClockThread> SimClockThread::GetInstance()
00063 {
00064   return singleton;
00065 }
00066 
00067 boost::shared_ptr<SimClockThread> SimClockThread::Instance()
00068 {
00069   
00070   boost::shared_ptr<SimClockThread> shared = GetInstance();
00071   if(!shared) {
00072     shared.reset(new SimClockThread());
00073     singleton = shared;
00074   }
00075 
00076   return shared;
00077 }
00078 
00079 void SimClockThread::Release()
00080 {
00081   singleton.reset();
00082 }
00083 
00084 namespace {
00085   RTT::os::CleanupFunction cleanup(&SimClockThread::Release);
00086 }
00087 
00088 SimClockThread::SimClockThread() 
00089   : RTT::os::Thread(ORO_SCHED_OTHER, RTT::os::LowestPriority, 0.0, 0, "rtt_rosclock_SimClockThread")
00090   , time_service_(RTT::os::TimeService::Instance())
00091   , clock_source_(SIM_CLOCK_SOURCE_MANUAL)
00092   , process_callbacks_(false)
00093 {
00094 }
00095 
00096 SimClockThread::~SimClockThread()
00097 {
00098   this->stop();
00099 }
00100 
00101 bool SimClockThread::setClockSource(SimClockSource clock_source) 
00102 {
00103   
00104   if(this->isActive()) {
00105     RTT::log(RTT::Error) << "The SimClockThread clock source cannot be changed while the thread is running." << RTT::endlog();
00106     return false;
00107   }
00108 
00109   
00110   clock_source_ = clock_source;
00111 
00112   return true;
00113 }
00114 
00115 bool SimClockThread::useROSClockTopic() 
00116 {
00117   return this->setClockSource(SIM_CLOCK_SOURCE_ROS_CLOCK_TOPIC);
00118 }
00119 
00120 bool SimClockThread::useManualClock() 
00121 {
00122   return this->setClockSource(SIM_CLOCK_SOURCE_MANUAL);
00123 }
00124 
00125 bool SimClockThread::simTimeEnabled() const 
00126 { 
00127   return this->isActive();
00128 }
00129 
00130 void SimClockThread::clockMsgCallback(const rosgraph_msgs::ClockConstPtr& clock)
00131 {
00132   
00133   updateClockInternal(ros::Time(clock->clock.sec, clock->clock.nsec));
00134 }
00135 
00136 bool SimClockThread::updateClock(const ros::Time new_time)
00137 {
00138   if(clock_source_ != SIM_CLOCK_SOURCE_MANUAL) {
00139     RTT::log(RTT::Error) << "Cannot update simulation clock manually unless the clock source is set to MANUAL_CLOCK." << RTT::endlog();
00140     return false;
00141   }
00142 
00143   return this->updateClockInternal(new_time);
00144 }
00145 
00146 bool SimClockThread::updateClockInternal(const ros::Time new_time)
00147 {
00148   
00149   if(time_service_->systemClockEnabled()) {
00150     time_service_->enableSystemClock(false);
00151   }
00152 
00153   
00154   if(new_time.isZero()) {
00155     
00156     RTT::log(RTT::Warning) << "Time has reset to 0! Re-setting time service..." << RTT::endlog();
00157 
00158     
00159     this->resetTimeService();
00160 
00161   } else {
00162     
00163     using namespace RTT::os;
00164     
00165     
00166 
00167     
00168     TimeService::Seconds dt = (new_time - rtt_rosclock::rtt_now()).toSec();
00169 
00170     
00171     if(dt < 0) {
00172       RTT::log(RTT::Warning) << "Time went backwards by " << dt << " seconds! (" << rtt_rosclock::rtt_now() << " --> " << new_time <<")" << RTT::endlog();
00173     }
00174 
00175     
00176     time_service_->secondsChange(dt);
00177 
00178     
00179     boost::shared_ptr<SimClockActivityManager> manager = SimClockActivityManager::GetInstance();
00180     if (manager) {
00181       
00182       manager->setSimulationPeriod(dt);
00183       
00184       manager->update();
00185     }
00186   }
00187 
00188   return true;
00189 }
00190 
00191 void SimClockThread::resetTimeService()
00192 {
00193   
00194   
00195   
00196   
00197   
00198 
00199   
00200   RTT::Logger::Instance()->shutdown();
00201 
00202   
00203   time_service_->enableSystemClock(false);
00204   assert(time_service_->systemClockEnabled() == false);
00205 
00206   time_service_->ticksChange(-time_service_->ticksSince(0));
00207   assert(time_service_->getTicks() == 0);
00208 
00209   
00210   RTT::Logger::Instance()->startup();
00211   assert(RTT::Logger::Instance()->getReferenceTime() == 0);
00212 }
00213 
00214 bool SimClockThread::initialize()
00215 {
00216 
00217   RTT::log(RTT::Debug) << "[rtt_rosclock] Attempting to enable global simulation clock source..." << RTT::endlog();
00218 
00219   switch(clock_source_) 
00220   {
00221     case SIM_CLOCK_SOURCE_ROS_CLOCK_TOPIC:
00222       {
00223         
00224         bool use_sim_time = false;
00225         ros::param::get("/use_sim_time", use_sim_time);
00226 
00227         if(!use_sim_time) {
00228           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();
00229           process_callbacks_ = false;
00230           return false;
00231         }
00232 
00233         RTT::log(RTT::Debug) << "[rtt_rosclock] Switching to simulated time based on ROS /clock topic..." << RTT::endlog();
00234 
00235         
00236         this->resetTimeService();
00237 
00238         
00239         ros::SubscribeOptions ops = ros::SubscribeOptions::create<rosgraph_msgs::Clock>(
00240             "/clock", 1, boost::bind(&SimClockThread::clockMsgCallback, this, _1),
00241             ros::VoidConstPtr(), &callback_queue_);
00242         clock_subscriber_ = nh_.subscribe(ops);
00243 
00244         
00245         process_callbacks_ = true;
00246       }
00247       break;
00248 
00249     case SIM_CLOCK_SOURCE_MANUAL:
00250       {
00251         RTT::log(RTT::Debug) << "[rtt_rosclock] Switching to simulated time based on a manual clock source..." << RTT::endlog();
00252 
00253         
00254         this->resetTimeService();
00255 
00256         
00257         process_callbacks_ = false;
00258       }
00259       break;
00260 
00261     default:
00262       {
00263         RTT::log(RTT::Error) << "Unknown simulation clock source for SimClockThread!" << RTT::endlog();
00264         return false;
00265       }
00266   };
00267 
00268   return true;
00269 }
00270 
00271 void SimClockThread::loop()
00272 {
00273   static const ros::WallDuration timeout(0.1);
00274 
00275   
00276   while(process_callbacks_) {
00277     callback_queue_.callAvailable(timeout);
00278   }
00279 }
00280 
00281 bool SimClockThread::breakLoop()
00282 {
00283   process_callbacks_ = false;
00284   return true;
00285 }
00286 
00287 void SimClockThread::finalize()
00288 {
00289   RTT::log(RTT::Info) << "Disabling simulated time..." << RTT::endlog();
00290 
00291   
00292   clock_subscriber_.shutdown();
00293 
00294   
00295   RTT::Logger::Instance()->shutdown();
00296 
00297   
00298   time_service_->enableSystemClock(true);
00299   
00300   
00301   RTT::Logger::Instance()->startup();
00302 }
00303