Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
SharedGlobals.hGo to the documentation of this file.00001 //-*-c++-*- 00002 #ifndef INCLUDED_CLASSNAME_h_ 00003 #define INCLUDED_CLASSNAME_h_ 00004 00005 #include "IPC/MutexLock.h" 00006 #include "IPC/SemaphoreManager.h" 00007 #include "IPC/ProcessID.h" 00008 #include "Shared/plist.h" 00009 #include "Shared/TimeET.h" 00010 #include "Shared/RobotInfo.h" 00011 #include "local/DataSource.h" 00012 00013 //! A class to hold various simulator parameters which need to be accessed from multiple processes 00014 class SharedGlobals { 00015 public: 00016 //! constructor 00017 SharedGlobals() 00018 : waitForSensors(false), simulatorTime(0), timeScale(1), motion(), sensors(), vision(), lock(), sensorState(), 00019 nextTimer(-1U), nextMotion(-1U), nextSensorUpdate(-1U), bootTime(), timeOffset(0), lastTimeScale(0), autoPauseTime(-1U), 00020 semgr(2), running(semgr.getSemaphore()), sensorValid(semgr.getSemaphore()) 00021 { 00022 sensorState.motionOverride = &motion.override; 00023 for(unsigned int i=0; i<NUM_RUNLEVELS; i++) 00024 level_count[i]=0; 00025 semgr.raise(running,1); 00026 semgr.raise(sensorValid,1); 00027 } 00028 //! destructor 00029 ~SharedGlobals() { 00030 semgr.releaseSemaphore(running); 00031 semgr.releaseSemaphore(sensorValid); 00032 } 00033 00034 // **************** 00035 //!@name Startup Control 00036 // **************** 00037 00038 //! Controls whether to wait for initial sensor readings before triggering the startup behavior or starting the motion polling thread. 00039 /*! This can avoid jumping to the 0-point on simulator launch. Changes after initial launch are ignored. */ 00040 plist::Primitive<bool> waitForSensors; 00041 00042 //! Called by Main when the first sensorEGID event is generated. 00043 /*! When the waitForSensors setting is enabled, the startupBehavior is not activated until this occurs */ 00044 void signalHaveSensors() { 00045 semgr.lower(sensorValid,1,false); 00046 } 00047 //! test to see if the initial sensor event has been generated 00048 bool haveSensors() const { 00049 return semgr.testZero(sensorValid,false); 00050 } 00051 //! blocks until the initial sensor event has been generated 00052 void waitSensors() { 00053 semgr.testZero(sensorValid,true); 00054 } 00055 00056 //@} 00057 00058 00059 // **************** 00060 //!@name Shutdown Control 00061 // **************** 00062 00063 //! call this to cause "system shutdown" -- clean halt of the simulator (not actually the host system) 00064 void signalShutdown() { 00065 semgr.setValue(running,0); 00066 if(waitForSensors && !haveSensors()) 00067 signalHaveSensors(); // break out of deadlock in Main and Motion if we were waiting for the first sensor 00068 } 00069 //! test to see if the shutdown flag has been set (non-blocking) 00070 bool isShutdown() const { 00071 return semgr.testZero(running,false); 00072 } 00073 //! blocks until shutdown flag has been set 00074 bool waitShutdown() { 00075 return semgr.testZero(running,true); 00076 } 00077 00078 //! access to #semgr, returns SemaphoreManager::hadFault() 00079 bool hadFault() const { return semgr.hadFault(); } 00080 00081 //! access to #semgr's SemaphoreManager::faultShutdown() -- call this *after* a fault has occured from the signal handler; doesn't signal the fault itself 00082 void faultShutdown() { semgr.faultShutdown(); } 00083 00084 //@} 00085 00086 00087 // ************ 00088 //!@name Time Control 00089 // ************ 00090 00091 //! returns the current simulator time, in milliseconds since startup 00092 /*! the simulator should set project_get_time::get_time_callback to call this, 00093 * so calls to ::get_time() will be forwarded here. That wall all processes 00094 * will share the same time */ 00095 unsigned int get_time(); 00096 00097 //! returns the current simulator #timeScale (speed factor), as a ratio of real time (e.g. '2' means simulation is running two times wall clock) 00098 /*! the simulator should set project_get_time::get_timeScale_callback to call this, 00099 * so calls to ::getTimeScale() will be forwarded here. */ 00100 float getTimeScale() const; 00101 00102 //! the current time within the simulation, only applicable when timeScale is negative (non-realtime) 00103 unsigned int simulatorTime; 00104 00105 //! Controls the speed at which time from get_time() will move 00106 /*! You can use this to pretend your hardware is faster or slower 00107 * than it actually is. For instance, a value of .5 means time 00108 * will move at half speed (pretending your hardware is twice as 00109 * fast) This can be useful for "slow motion" analysis, or you 00110 * can speed up time to simulate a more processor-restrictive platform. 00111 * 00112 * Negative values indicate full-speed processing -- time will be 00113 * incremented only as quickly as it can be without dropping any 00114 * video or sensor frames. (may be faster or slower than realtime) 00115 * in this case, #simulatorTime is used by calls to get_time() 00116 * 00117 * A value of zero halts time. */ 00118 plist::Primitive<double> timeScale; 00119 00120 //! sets #autoPauseTime 00121 void setAutoPauseTime(unsigned int t) { autoPauseTime=t; } 00122 //! returns #autoPauseTime 00123 unsigned int getAutoPauseTime() const { return autoPauseTime; } 00124 00125 //@} 00126 00127 00128 // ********************** 00129 //!@name Runlevel Communication 00130 // ********************** 00131 00132 //! defines the runlevels that each process passes through; runlevels should monotonically increase (can't go backwards) 00133 enum runlevel_t { 00134 CREATED=0, //!< corresponding element of #level_count is incremented prior to each fork -- not strictly a runlevel per se 00135 CONSTRUCTING, //!< currently initializing 00136 STARTING, //!< setting up shared memory regions with other processes 00137 RUNNING, //!< full activity, stay here until the #running semaphore is set to 0 00138 STOPPING, //!< dereferencing shared regions, waiting for threads to finish 00139 DESTRUCTING, //!< destructors are in progress 00140 DESTRUCTED, //!< destruction has completed, corresponding element of #level_count is incremented immediately prior to process completion 00141 }; 00142 static const unsigned int NUM_RUNLEVELS=DESTRUCTED+1; //!< symbolic access to the total number of runlevel stages 00143 00144 //! string versions of runlevel_t for runtime user-feedback 00145 static const char * const runlevel_names[NUM_RUNLEVELS+1]; 00146 00147 //! a count of the number of processes which have passed through each runlevel 00148 unsigned int level_count[NUM_RUNLEVELS]; 00149 00150 //@} 00151 00152 00153 // ********************** 00154 //!@name Configuration Parameters 00155 // ********************** 00156 00157 //! holds configuration parameters for the motion process 00158 class MotionSimConfig : public virtual plist::Dictionary { 00159 public: 00160 //! constructor 00161 MotionSimConfig() : plist::Dictionary(), verbose(1), feedbackDelay(0), 00162 zeroPIDFeedback(false), /*speedLimit(0),*/ feedbackRangeLimits(true), override(false), startPose(), frameNumber(-1U) 00163 { 00164 setLoadSavePolicy(FIXED,SYNC); 00165 addEntry("Verbose",verbose,"Report whenever motion commands are being processed or joints are updated\n0 - nothing, 1 - errors, 2 - warnings (e.g. dropped frames), 3 - notification every frame"); 00166 addEntry("FeedbackDelay",feedbackDelay,"Delay (in milliseconds) to apply to motion output before feeding back to sensor values (simulates (very roughly) inertia and system response time); 0 indicates instantaneous/perfect joint control, negative values indicate no feedback (only sensor data sets joint positions)"); 00167 addEntry("ZeroPIDFeedback",zeroPIDFeedback,"When set to false, if PIDs are set to zero, then sensor values are used to set joint positions; otherwise joint position sensors would only be used if FeedbackDelay is negative"); 00168 //addEntry("EnforceSpeedLimit",speedLimit,"The simulated motion of joints is limited to this factor of model's recommended speed limits. 0 (or negative) disables speed limit altogether."); 00169 addEntry("FeedbackRangeLimits",feedbackRangeLimits,"If true, feedback will be limited to the RobotInfo::mechnicalLimits values"); 00170 addEntry("OverrideSensors",override,"Allows motion feedback to override position values from sensor data loaded from disk.\nIf false, feedback is only provided when no other sensor data is being provided"); 00171 addEntry("StartPose",startPose,"Name of a posture file to load as the initial output values before MotionHooks or Behaviors are activated (if empty, everything will be 0)"); 00172 } 00173 plist::Primitive<int> verbose; //!< Report whenever motion commands are being processed or joints are updated; 0 - nothing, 1 - errors, 2 - warnings (e.g. dropped frames), 3 - notification every frame 00174 plist::Primitive<int> feedbackDelay; //!< Delay (in milliseconds) to apply to motion output before feeding back to sensor values (simulates (very roughly) inertia and system response time); 0 indicates instantaneous/perfect joint control, negative values indicate no feedback (only sensor data sets joint positions) 00175 plist::Primitive<bool> zeroPIDFeedback; //!< When set to false, if PIDs are set to zero, then sensor values are used to set joint positions; otherwise joint position sensors would only be used if FeedbackDelay is negative 00176 //plist::Primitive<float> speedLimit; //!< The simulated motion of joints is limited to this factor of model's recommended speed limits. 0 (or negative) disables speed limit altogether. 00177 plist::Primitive<bool> feedbackRangeLimits; //!< If true, feedback will be limited to the RobotInfo::mechnicalLimits values 00178 plist::Primitive<bool> override; //!< Allows motion feedback to override position values from sensor data loaded from disk; if false, feedback is only provided when no other sensor data is being provided 00179 plist::Primitive<std::string> startPose; //!< Name of a posture file to load as the initial output values before MotionHooks or Behaviors are activated (if empty, everything will be 0) 00180 unsigned int frameNumber; //!< a monotonically increasing count of the number of sensor frames which have been "completed". Needed to allow coordination between sensor loading from disk and feedback from motion. Count is increased by the simulator process, which will send a heartbeat message over Simulator::sensorQueue when it does so. 00181 } motion; 00182 00183 class StreamSimConfig : public virtual plist::Dictionary { 00184 public: 00185 StreamSimConfig() : plist::Dictionary(), 00186 framerate(1000.f/(FrameTime*NumFrames)), verbose(0), heartbeat(false), sources() 00187 { 00188 addEntry("Framerate",framerate,"The rate at which data should be loaded. This is a hint to the hardware devices, which generally use their 'native' framerate, but may use this to limit data flow."); 00189 addEntry("Verbose",verbose,"Controls how much feedback to give on the console regarding progress\n 0 - none\n 1 - report when frames are dropped\n 2 - also report when a frame is sent\n 3 - also report when heartbeat is sent/dropped\n 4 - also report when each frame is received and processed"); 00190 addEntry("Heartbeat",heartbeat,"If enabled, an empty \"heartbeat\" message is sent at the appropriate framerate, even if no data is being processed (i.e. frozen, no data loaded, or out of frames); this will cause an update event within the simulator, repeating processing on the previous data."); 00191 addEntry("Sources",sources,"Indicates which data sources should be activated at launch"); 00192 setLoadSavePolicy(FIXED,SYNC); 00193 } 00194 00195 //! frames per second to send -- this is only a suggestion to hardware devices, which generally use their 'native' framerate, but may use this to limit data flow 00196 plist::Primitive<float> framerate; 00197 00198 //! Controls how much feedback to give on the console regarding progress 00199 /*! 0 - none\n 00200 * 1 - report when frames are dropped\n 00201 * 2 - also report when a frame is sent\n 00202 * 3 - also report when heartbeat is sent/dropped\n 00203 * 4 - also report when each frame is received and processed */ 00204 plist::Primitive<int> verbose; 00205 00206 //! if enabled, an empty "heartbeat" message is sent at the appropriate framerate, even if no data is being processed (i.e. no data loaded or out of frames); this will cause an update event within the simulator, repeating processing on the previous data. 00207 plist::Primitive<bool> heartbeat; 00208 00209 //! list of names of DataSources which are to be activated at launch 00210 plist::ArrayOf<plist::Primitive<std::string> > sources; 00211 }; 00212 StreamSimConfig sensors; 00213 StreamSimConfig vision; 00214 00215 //@} 00216 00217 //! allows mutually exclusive access to the fields of SharedObject 00218 MutexLock<ProcessID::NumProcesses> lock; 00219 00220 //! holds the host system's process ID for each simulator process 00221 pid_t pids[ProcessID::NumProcesses]; 00222 00223 //! maximum storage size of strings in #processNames 00224 static const unsigned int MAX_PROCESS_NAME_LEN=32; 00225 00226 //! each process should set a string version of its name for user feedback 00227 char processNames[ProcessID::NumProcesses][MAX_PROCESS_NAME_LEN]; 00228 00229 bool setNextTimer(unsigned int t) { if(nextTimer==t) return false; nextTimer=t; return true; } //!< sets #nextTimer, returns true if the new value differs from previous value 00230 unsigned int getNextTimer() { return nextTimer; } //!< gets #nextTimer 00231 00232 void setNextMotion(unsigned int t) { nextMotion=t; } //!< sets #nextMotion 00233 unsigned int getNextMotion() { return nextMotion; } //!< gets #nextMotion 00234 00235 void setNextSensorUpdate(unsigned int t) { nextSensorUpdate=t; } //!< sets #nextSensorUpdate 00236 unsigned int getNextSensorUpdate() { return nextSensorUpdate; } //!< gets #nextSensorUpdate 00237 00238 void resetBootTime() { timeOffset=bootTime.Age().Value()*timeScale*1000; simulatorTime=0; } 00239 00240 SensorState sensorState; 00241 00242 protected: 00243 //! this returns time since boot (#bootTime), scaled by @a scale, relative to #timeOffset 00244 unsigned int get_real_time(double scale) const { 00245 return static_cast<unsigned int>(bootTime.Age().Value()*scale*1000-timeOffset); 00246 } 00247 00248 //! set by setNextTimer, called with the current value of EventRouter::getNextTimer() after each user code section, indicates time of next timer event 00249 unsigned int nextTimer; 00250 00251 //! updated by Motion process after each motion update 00252 unsigned int nextMotion; 00253 00254 //! updated by Main process after each sensor update 00255 unsigned int nextSensorUpdate; 00256 00257 //! real time since simulator startup (or, at least, since SharedGlobals was constructed... close enough) 00258 TimeET bootTime; 00259 00260 //! the scaled value of #bootTime at which isRealTime was last activated, allows you to start and stop realtime fluidly 00261 double timeOffset; 00262 00263 //! updated by each call to get_time(), if timeScale differs, allows timeOffset to be updated fluidly 00264 double lastTimeScale; 00265 00266 //! if simulatorTime is about to move past this value, timeScale is set to 0 instead, and simulatorTime is set to this 00267 unsigned int autoPauseTime; 00268 00269 SemaphoreManager semgr; //!< a semaphore set, only used for #running and #sensorValid 00270 SemaphoreManager::semid_t running; //!< the semaphore within #semgr to communicate shutdown status between processes -- when the semaphore is set to 0, shutdown is requested 00271 SemaphoreManager::semid_t sensorValid; //!< the semaphore within #semgr to notify processes when the first sensor frame is available 00272 }; 00273 00274 const unsigned int MAX_SUBJECTS=50; //!< maximum number of message queues the simulator can maintain 00275 const unsigned int MAX_SUBJECT_NAME=50; //!< maximum storage capacity of subject names 00276 00277 // just a forward definition of RegionRegistry 00278 template<unsigned int MAX_SUBJECTS, unsigned int MAX_SUBJECT_NAME> class RegionRegistry; 00279 //! the type to use for the inter-process communication registry 00280 typedef RegionRegistry<MAX_SUBJECTS,MAX_SUBJECT_NAME> ipc_setup_t; 00281 00282 extern ipc_setup_t * ipc_setup; //!< a global pointer to the inter-process message queue registry (a RegionRegistry) 00283 extern SharedGlobals * globals; //!< a global pointer to the SharedGlobals instance 00284 extern float getTimeScale(); //!< a prototype for accessing current time scale without referencing ::globals directly 00285 00286 /*! @file 00287 * @brief A class to hold various simulator parameters which need to be accessed from multiple processes 00288 * @author ejt (Creator) 00289 */ 00290 00291 #endif |
Tekkotsu Hardware Abstraction Layer 5.1CVS |
Generated Mon May 9 05:01:39 2016 by Doxygen 1.6.3 |