Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

SharedGlobals.h

Go 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