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 00012 //! A class to hold various simulator parameters which need to be accessed from multiple processes 00013 class SharedGlobals { 00014 public: 00015 //! constructor 00016 SharedGlobals() 00017 : waitForSensors(false), simulatorTime(0), timeScale(1), motion(), lock(), 00018 nextTimer(-1U), nextMotion(-1U), nextSensorUpdate(-1U), bootTime(), timeOffset(0), lastTimeScale(0), autoPauseTime(-1U), 00019 semgr(2), running(semgr.getSemaphore()), sensorValid(semgr.getSemaphore()) 00020 { 00021 for(unsigned int i=0; i<NUM_RUNLEVELS; i++) 00022 level_count[i]=0; 00023 semgr.raise(running,1); 00024 semgr.raise(sensorValid,1); 00025 } 00026 //! destructor 00027 ~SharedGlobals() { 00028 semgr.releaseSemaphore(running); 00029 semgr.releaseSemaphore(sensorValid); 00030 } 00031 00032 // **************** 00033 //!@name Startup Control 00034 // **************** 00035 00036 //! Controls whether to wait for initial sensor readings before triggering the startup behavior or starting the motion polling thread. 00037 /*! This can avoid jumping to the 0-point on simulator launch. Changes after initial launch are ignored. */ 00038 plist::Primitive<bool> waitForSensors; 00039 00040 //! call this to cause "system shutdown" -- clean halt of the simulator (not actually the host system) 00041 void signalHaveSensors() { 00042 semgr.setValue(sensorValid,0); 00043 } 00044 //! test to see if the shutdown flag has been set (non-blocking) 00045 bool haveSensors() const { 00046 return semgr.testZero(sensorValid,false); 00047 } 00048 //! blocks until shutdown flag has been set 00049 bool waitSensors() { 00050 return semgr.testZero(sensorValid,true); 00051 } 00052 00053 //@} 00054 00055 00056 // **************** 00057 //!@name Shutdown Control 00058 // **************** 00059 00060 //! call this to cause "system shutdown" -- clean halt of the simulator (not actually the host system) 00061 void signalShutdown() { 00062 semgr.setValue(running,0); 00063 if(waitForSensors && !haveSensors()) 00064 signalHaveSensors(); // break out of deadlock in Main and Motion if we were waiting for the first sensor 00065 } 00066 //! test to see if the shutdown flag has been set (non-blocking) 00067 bool isShutdown() const { 00068 return semgr.testZero(running,false); 00069 } 00070 //! blocks until shutdown flag has been set 00071 bool waitShutdown() { 00072 return semgr.testZero(running,true); 00073 } 00074 00075 //! access to #semgr, returns SemaphoreManager::hadFault() 00076 bool hadFault() const { return semgr.hadFault(); } 00077 00078 //! access to #semgr's SemaphoreManager::faultShutdown() -- call this *after* a fault has occured from the signal handler; doesn't signal the fault itself 00079 void faultShutdown() { semgr.faultShutdown(); } 00080 00081 //@} 00082 00083 00084 // ************ 00085 //!@name Time Control 00086 // ************ 00087 00088 //! returns the current simulator time, in milliseconds since startup 00089 /*! the simulator should set project_get_time::get_time_callback to call this, 00090 * so calls to ::get_time() will be forwarded here. That wall all processes 00091 * will share the same time */ 00092 unsigned int get_time(); 00093 00094 //! returns the current simulator #timeScale (speed factor), as a ratio of real time (e.g. '2' means simulation is running two times wall clock) 00095 /*! the simulator should set project_get_time::get_timeScale_callback to call this, 00096 * so calls to ::getTimeScale() will be forwarded here. */ 00097 float getTimeScale() const; 00098 00099 //! the current time within the simulation, only applicable when timeScale is negative (non-realtime) 00100 unsigned int simulatorTime; 00101 00102 //! Controls the speed at which time from get_time() will move 00103 /*! You can use this to pretend your hardware is faster or slower 00104 * than it actually is. For instance, a value of .5 means time 00105 * will move at half speed (pretending your hardware is twice as 00106 * fast) This can be useful for "slow motion" analysis, or you 00107 * can speed up time to simulate a more processor-restrictive platform. 00108 * 00109 * Negative values indicate full-speed processing -- time will be 00110 * incremented only as quickly as it can be without dropping any 00111 * video or sensor frames. (may be faster or slower than realtime) 00112 * in this case, #simulatorTime is used by calls to get_time() 00113 * 00114 * A value of zero halts time. */ 00115 plist::Primitive<double> timeScale; 00116 00117 //! sets #autoPauseTime 00118 void setAutoPauseTime(unsigned int t) { autoPauseTime=t; } 00119 //! returns #autoPauseTime 00120 unsigned int getAutoPauseTime() const { return autoPauseTime; } 00121 00122 //@} 00123 00124 00125 // ********************** 00126 //!@name Runlevel Communication 00127 // ********************** 00128 00129 //! defines the runlevels that each process passes through; runlevels should monotonically increase (can't go backwards) 00130 enum runlevel_t { 00131 CREATED=0, //!< corresponding element of #level_count is incremented prior to each fork -- not strictly a runlevel per se 00132 CONSTRUCTING, //!< currently initializing 00133 STARTING, //!< setting up shared memory regions with other processes 00134 RUNNING, //!< full activity, stay here until the #running semaphore is set to 0 00135 STOPPING, //!< dereferencing shared regions, waiting for threads to finish 00136 DESTRUCTING, //!< destructors are in progress 00137 DESTRUCTED, //!< destruction has completed, corresponding element of #level_count is incremented immediately prior to process completion 00138 }; 00139 static const unsigned int NUM_RUNLEVELS=DESTRUCTED+1; //!< symbolic access to the total number of runlevel stages 00140 00141 //! string versions of runlevel_t for runtime user-feedback 00142 static const char * const runlevel_names[NUM_RUNLEVELS+1]; 00143 00144 //! a count of the number of processes which have passed through each runlevel 00145 unsigned int level_count[NUM_RUNLEVELS]; 00146 00147 //@} 00148 00149 00150 // ********************** 00151 //!@name Configuration Parameters 00152 // ********************** 00153 00154 //! holds configuration parameters for the motion process 00155 class MotionSimConfig : public virtual plist::Dictionary { 00156 public: 00157 //! constructor 00158 MotionSimConfig() : plist::Dictionary(), verbose(1), feedbackDelay(0), 00159 zeroPIDFeedback(false), /*speedLimit(0),*/ override(false), frameNumber(-1U) 00160 { 00161 setLoadSavePolicy(FIXED,SYNC); 00162 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"); 00163 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)"); 00164 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"); 00165 //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."); 00166 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"); 00167 00168 for(unsigned int i=0; i<NumOutputs; i++) 00169 providedOutputs[i]=0; 00170 } 00171 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 00172 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) 00173 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 00174 //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. 00175 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 00176 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. 00177 00178 //! Counts the number of sensor data sources which are providing readings for each output 00179 /*! This isn't a configuration setting per se, but needed so motion process can tell if it 00180 * should provide feedback for each output. If an output doesn't have any sensor feedback 00181 * (or #override is true), then motion should provide feedback. If more than one 00182 * sensor is providing the same output, that could be a problem, but not dealt with here. 00183 * 00184 * The simulator's initialization routines will pass this to DataSource::setOutputTracker(). */ 00185 unsigned int providedOutputs[NumOutputs]; 00186 00187 //! returns true if any of #providedOutputs is greater than zero 00188 bool hasProvidedOutput() const { for(unsigned int i=0; i<NumOutputs; i++) if(providedOutputs[i]>0) return true; return false; } 00189 //! returns true if any of #providedOutputs is zero 00190 bool hasUnprovidedOutput() const { for(unsigned int i=0; i<NumOutputs; i++) if(providedOutputs[i]==0) return true; return false; } 00191 } motion; 00192 00193 //@} 00194 00195 //! allows mutually exclusive access to the fields of SharedObject 00196 MutexLock<ProcessID::NumProcesses> lock; 00197 00198 //! holds the host system's process ID for each simulator process 00199 pid_t pids[ProcessID::NumProcesses]; 00200 00201 //! maximum storage size of strings in #processNames 00202 static const unsigned int MAX_PROCESS_NAME_LEN=32; 00203 00204 //! each process should set a string version of its name for user feedback 00205 char processNames[ProcessID::NumProcesses][MAX_PROCESS_NAME_LEN]; 00206 00207 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 00208 unsigned int getNextTimer() { return nextTimer; } //!< gets #nextTimer 00209 00210 void setNextMotion(unsigned int t) { nextMotion=t; } //!< sets #nextMotion 00211 unsigned int getNextMotion() { return nextMotion; } //!< gets #nextMotion 00212 00213 void setNextSensorUpdate(unsigned int t) { nextSensorUpdate=t; } //!< sets #nextSensorUpdate 00214 unsigned int getNextSensorUpdate() { return nextSensorUpdate; } //!< gets #nextSensorUpdate 00215 00216 void resetBootTime() { timeOffset=bootTime.Age().Value()*timeScale*1000; simulatorTime=0; } 00217 00218 protected: 00219 //! this returns time since boot (#bootTime), scaled by @a scale, relative to #timeOffset 00220 unsigned int get_real_time(double scale) const { 00221 return static_cast<unsigned int>(bootTime.Age().Value()*scale*1000-timeOffset); 00222 } 00223 00224 //! set by setNextTimer, called with the current value of EventRouter::getNextTimer() after each user code section, indicates time of next timer event 00225 unsigned int nextTimer; 00226 00227 //! updated by Motion process after each motion update 00228 unsigned int nextMotion; 00229 00230 //! updated by Main process after each sensor update 00231 unsigned int nextSensorUpdate; 00232 00233 //! real time since simulator startup (or, at least, since SharedGlobals was constructed... close enough) 00234 TimeET bootTime; 00235 00236 //! the scaled value of #bootTime at which isRealTime was last activated, allows you to start and stop realtime fluidly 00237 double timeOffset; 00238 00239 //! updated by each call to get_time(), if timeScale differs, allows timeOffset to be updated fluidly 00240 double lastTimeScale; 00241 00242 //! if simulatorTime is about to move past this value, timeScale is set to 0 instead, and simulatorTime is set to this 00243 unsigned int autoPauseTime; 00244 00245 SemaphoreManager semgr; //!< a semaphore set, only used for #running and #sensorValid 00246 SemaphoreManager::semid_t running; //!< the semaphore within #semgr to communicate shutdown status between processes -- when the semaphore is set to 0, shutdown is requested 00247 SemaphoreManager::semid_t sensorValid; //!< the semaphore within #semgr to notify processes when the first sensor frame is available 00248 }; 00249 00250 const unsigned int MAX_SUBJECTS=50; //!< maximum number of message queues the simulator can maintain 00251 const unsigned int MAX_SUBJECT_NAME=50; //!< maximum storage capacity of subject names 00252 00253 // just a forward definition of RegionRegistry 00254 template<unsigned int MAX_SUBJECTS, unsigned int MAX_SUBJECT_NAME> class RegionRegistry; 00255 //! the type to use for the inter-process communication registry 00256 typedef RegionRegistry<MAX_SUBJECTS,MAX_SUBJECT_NAME> ipc_setup_t; 00257 00258 extern ipc_setup_t * ipc_setup; //!< a global pointer to the inter-process message queue registry (a RegionRegistry) 00259 extern SharedGlobals * globals; //!< a global pointer to the SharedGlobals instance 00260 extern float getTimeScale(); //!< a prototype for accessing current time scale without referencing ::globals directly 00261 00262 /*! @file 00263 * @brief A class to hold various simulator parameters which need to be accessed from multiple processes 00264 * @author ejt (Creator) 00265 * 00266 * $Author: ejt $ 00267 * $Name: tekkotsu-4_0 $ 00268 * $Revision: 1.3 $ 00269 * $State: Exp $ 00270 * $Date: 2007/11/09 19:01:17 $ 00271 */ 00272 00273 #endif |
Tekkotsu Hardware Abstraction Layer 4.0 |
Generated Thu Nov 22 01:00:53 2007 by Doxygen 1.5.4 |