Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

WorldState.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_WorldState_h
00003 #define INCLUDED_WorldState_h
00004 
00005 #ifdef PLATFORM_APERIOS
00006 #  include <OPENR/core_macro.h>
00007 #  include <OPENR/ObjcommTypes.h>
00008 #  include <OPENR/OPENR.h>
00009 #  include <OPENR/OPENRAPI.h>
00010 #  include <OPENR/OPENRMessages.h>
00011 #else
00012 class SensorState;
00013 #endif
00014 
00015 #include "Shared/RobotInfo.h"
00016 #include "IPC/ProcessID.h"
00017 #include <vector>
00018 
00019 class EventRouter;
00020 class EventBase;
00021 
00022 //The following SourceIDs are for events created by WorldState's event generators
00023 
00024 //! holds source ID types for sensor events; see EventBase, see #SensorSourceID_t
00025 namespace SensorSrcID {
00026   //! holds source ID types for sensor events
00027   /*! May want to add a proximity alarm for IR distance?  Probably
00028    *  should do it from a separate generator to avoid screwing up
00029    *  behaviors relying on the current setup
00030    */
00031   enum SensorSourceID_t {
00032     UpdatedSID //!< sends status event as last event after processing a frame
00033   };
00034 }
00035 
00036 //! holds source ID types for power events; see EventBase, see #PowerSourceID_t
00037 namespace PowerSrcID {
00038   //! holds source ID types for power events
00039   /*! Also serve as offsets into WorldState::powerFlags[].
00040    *
00041    *  I've never seen a lot of these events thrown by the OS.  'NS'
00042    *  means never-seen, which could simply be because i haven't put it
00043    *  in that situation (don't have a station-type power charger) or
00044    *  because the OS doesn't actually support sending that flag.
00045    *
00046    *  Under normal conditions, you'll see MotorPowerSID,
00047    *  BatteryConnectSID, DischargingSID, and PowerGoodSID always
00048    *  active with occasional VibrationSID and UpdateSID.  When the
00049    *  chest button is pushed, PauseSID is activated and MotorPowerSID
00050    *  is deactivated.
00051    *
00052    *  The BatteryMonitorBehavior will give a warning once power begins
00053    *  getting low.  The OS won't boot off a battery with less than 15%
00054    *  power remaining (which is when the LowPowerWarnSID is thrown)
00055    *
00056    *  @note there's not a one-to-one correspondance of the events from
00057    *  the OPENR power system... i map several OPENR events to fewer
00058    *  Tekkotsu events, check the event's name if you want to know the
00059    *  specific source (say if low battery is low current and/or low
00060    *  voltage) Status ETIDS are only generated when one of a related
00061    *  group goes on/off but others are still active
00062    */
00063   enum PowerSourceID_t {
00064     PauseSID=0, //!< the chest button was pushed (this is not a normal button, it kills power to the motors in hardware)
00065     MotorPowerSID, //!< active while the motors have power
00066     VibrationSID, //!< triggered when the OS decides a large acceleration has occured, like falling down (or more specifically, hitting the ground afterward)
00067     BatteryEmptySID, //!< battery is dead
00068     LowPowerWarnSID, //!< triggered when sensors[PowerRemainOffset] <= 0.15 (PowerGoodSID stays on)
00069     BatteryFullSID,  //!< battery is full
00070     ExternalPowerSID, //!< receiving power from an external source (such as AC cable, may or may not include the "station", see StationConnectSID)
00071     ExternalPortSID,  //!< an external power source is plugged in (does not imply current is flowing however)
00072     BatteryConnectSID, //!< a battery is plugged in
00073     BatteryInitSID, //!< ? NS
00074     DischargingSID, //!< using power from the battery (although still stays on after hooked up to external power)
00075     ChargingSID, //!< you used to be able to charge while running, tho that has changed in more recent versions of OPEN-R.  In any case, I never saw this even when it did work.
00076     OverheatingSID, //!< in case the robot starts getting too hot NS
00077     PowerGoodSID, //!< there is power, either from external or battery
00078     ChargerStatusSID, //!< ? NS
00079     SuspendedSID, //!< ? NS
00080     OverChargedSID, //!< in case the charger screws up somehow (?) NS
00081     TermDischargeSID, //!< end of battery (?) NS
00082     TermChargeSID, //!< end of charging (?) NS
00083     ErrorSID, //!< general power error NS
00084     StationConnectSID, //!< connected to a station NS
00085     BatteryOverCurrentSID, //!< similar to OverChargedSID (?) NS
00086     DataFromStationSID, //!< ? NS
00087     RegisterUpdateSID, //!< ? NS
00088     RTCSID, //!< ? NS
00089     SpecialModeSID, //!< ? NS
00090     BMNDebugModeSID, //!< ? NS
00091     PlungerSID, //!< I think this is in reference to having a memorystick (?) NS
00092     UpdatedSID, //!< sent as last event after processing a frame
00093     NumPowerSIDs
00094   };
00095 }
00096 
00097 //! The state of the robot and its environment
00098 /*! Contains sensor readings, current joint positions, etc.  Notable members are:
00099  * - #outputs - joint positions and current LED values
00100  * - #buttons - current button values
00101  * - #sensors - values from other sensors (IR, acceleration, temperature, power levels)
00102  * - #pids - current PID settings for each joint (more specifically, each PID-controlled joint)
00103  * - #pidduties - how hard each of the PID joints is working to get to its target value
00104  *
00105  * Generally you will use enumerated values from a robot-specific namespace to
00106  * index into these arrays.  Each of those members' documentation specifies where
00107  * to find the list of indices to use with them.
00108  *
00109  * This is a shared memory region between Main, Motion, and possibly others in the future.
00110  * Be very careful about including structures that use pointers in
00111  * this class... they will only be valid from the OObject that created
00112  * them, others may cause a crash if they try to access them.
00113  *
00114  * WorldState takes power and sensor updates from the system and
00115  * maintains the last known values in its member fields.  It throws
00116  * events when some of these values change, listed in the
00117  * SensorSourceID, PowerSourceID namespaces, and the ButtonOffset_t
00118  * enumeration for your robot model's info
00119  * namespace. (e.g. ERS7Info::ButtonOffset_t)
00120  *
00121  * Status events for buttons only generated if the
00122  * WorldState::alwaysGenerateStatus flag is turned on.  Otherwise, by
00123  * default, they are only generated when a value has changed.
00124  * (i.e. when the pressure sensitive buttons get a new pressure
00125  * reading)
00126  */
00127 class WorldState {
00128 public:
00129   //! constructor - sets everything to zeros
00130   WorldState();
00131 
00132   bool alwaysGenerateStatus; //!< controls whether status events are generated for the boolean buttons
00133 
00134   float outputs[NumOutputs];     //!< last sensed positions of joints, last commanded value of LEDs; indexes (aka offsets) are defined in the target model's namespace (e.g. "Output Offsets" section of ERS7Info)
00135   float buttons[NumButtons];     //!< magnitude is pressure for some, 0/1 for others; indexes are defined in the ButtonOffset_t of the target model's namespace (e.g. ERS7Info::ButtonOffset_t)
00136   float sensors[NumSensors];     //!< IR, Accel, Thermo, Power stuff; indexes are defined in SensorOffset_t of the target model's namespace (e.g. ERS7Info::SensorOffset_t)
00137   float pids[NumPIDJoints][3];   //!< current PID settings (same ordering as the #outputs), not sensed -- updated by MotionManager whenever it sends a PID setting to the system; note this is only valid for PID joints, has NumPIDJoint entries (as opposed to NumOutputs)
00138   float pidduties[NumPIDJoints]; //!< duty cycles - -1 means the motor is trying to move full power in negative direction, 1 means full power in positive direction, in practice, these values stay rather small - 0.15 is significant force. (same ordering as the #outputs); note this is only valid for PID joints, has NumPIDJoint entries (as opposed to NumOutputs)
00139   
00140   float vel_x; //!< the current, egocentric rate of forward locomotion, mm/second
00141   float vel_y; //!< the current, egocentric rate of sideways (leftward is positive) locomotion, mm/second
00142   float vel_a; //!< the current, egocentric rate of rotational (counterclockwise is positive) locomotion, radian/second
00143   unsigned int vel_time; //!< the time at which we began moving along the current velocity vector
00144 
00145   unsigned int robotStatus;       //!< bitmask, see OPENR/OPower.h
00146   unsigned int batteryStatus;     //!< bitmask, see OPENR/OPower.h
00147   unsigned int powerFlags[PowerSrcID::NumPowerSIDs]; //!< bitmasks of similarly-grouped items from previous two masks, corresponds to the PowerSrcID::PowerSourceID_t's
00148 
00149   unsigned int button_times[NumButtons]; //!< value is time of current press, 0 if not down
00150   
00151   unsigned int lastSensorUpdateTime;     //!< primarily so calcDers can determine the time difference between updates, but others might want to know this too...
00152   unsigned int frameNumber;              //!< the serial number of the currently available frame
00153   unsigned int framesProcessed;          //!< the number of sensor updates which have been processed
00154 
00155   static const double g;                 //!< the gravitational acceleration of objects on earth
00156   static const double IROORDist;         //!< If IR returns this, we're out of range
00157 
00158 #ifdef PLATFORM_APERIOS
00159   void read(OSensorFrameVectorData& sensor, EventRouter* er); //!< will process a sensor reading as given by OPEN-R
00160   void read(const OPowerStatus& power, EventRouter* er);      //!< will process a power status update as given by OPEN-R
00161   
00162   //! returns the current WorldState instance for the running process, needed if your code may be in a shared memory region; otherwise you can directly access ::state
00163   /*! Generally you can access ::state directly, but if your code is running as a member of an object in a shared memory region,
00164    *  this handles the shared object context switching problem on Aperios, and simply returns ::state on non-Aperios. */
00165   static WorldState* getCurrent();
00166   
00167 #else
00168   //! processes incoming sensor data, generating events for buttons
00169   void read(const SensorState& sensor, bool sendEvents);
00170   
00171   //! returns the current WorldState instance for the running process, needed if your code may be in a shared memory region; otherwise you can directly access ::state
00172   /*! Generally you can access ::state directly, but if your code is running as a member of an object in a shared memory region,
00173    *  this handles the shared object context switching problem on Aperios, and simply returns ::state on non-Aperios. */
00174   static const WorldState* getCurrent();
00175 #endif
00176 
00177 protected:
00178   unsigned int curtime; //!< set by read(OSensorFrameVectorData& sensor, EventRouter* er) for chkEvent() so each call doesn't have to
00179 
00180   //! Tests to see if the button status has changed and post events as needed
00181   void chkEvent(std::vector<EventBase>& evtBuf, unsigned int off, float newval, const char* name);
00182 
00183   //! Apply calibration to the sensors and joint positions (reversing motion calibration parameters)
00184   void applyCalibration();
00185 
00186   //! sets the names of the flags that will be generating events
00187   /*! note that this function does not actually do the event posting,
00188    *  unlike chkEvent() */
00189   void chkPowerEvent(unsigned int sid, unsigned int cur, unsigned int mask, const char* name, 
00190                      std::string actname[PowerSrcID::NumPowerSIDs],
00191                      std::string dename[PowerSrcID::NumPowerSIDs],
00192                      unsigned int summask[PowerSrcID::NumPowerSIDs]) {
00193     if(cur&mask) {
00194       actname[sid]+=name;
00195       summask[sid]|=mask;
00196     } else if(powerFlags[sid]&mask)
00197       dename[sid]+=name;
00198   }
00199 
00200   //! given the next value, calculates and stores the next current, the velocity, and the acceleration
00201   /*! @param next the new value that's about to be set
00202    *  @param cur the previous value
00203    *  @param vel the previous 1st derivative
00204    *  @param acc the previous 2nd derivative
00205    *  @param invtimediff @f$1/(curtime-prevtime)@f$ in seconds*/
00206   inline void calcDers(double next, double& cur, double& vel, double& acc, double invtimediff) {
00207     double diff=next-cur;
00208     cur=next;
00209     next=diff*invtimediff;;
00210     diff=next-vel;
00211     vel=next;
00212     acc=diff*invtimediff;
00213   }
00214   
00215 private:
00216   WorldState(const WorldState&); //!< this shouldn't be called...
00217   WorldState& operator=(const WorldState&); //!< this shouldn't be called...
00218 };
00219 
00220 #ifdef PLATFORM_APERIOS
00221 extern WorldState * state; //!< the global state object, points into a shared memory region, created by MainObject
00222 inline WorldState * WorldState::getCurrent() { return state; }
00223 
00224 #else
00225 
00226 //! This class masquerades as a simple WorldState pointer, but actually checks the process ID of the referencing thread to allow each thread group to have a separate WorldState*
00227 /*! This is so if a behavior in Main is blocking, it doesn't prevent Motion threads from getting updated sensors. */
00228 class WorldStateLookup {
00229 public:
00230   WorldStateLookup() {} //!< constructor
00231   WorldState* operator->() { return &ws[ProcessID::getID()]; } //!< smart pointer to the underlying class
00232   WorldState& operator*() { return ws[ProcessID::getID()]; } //!< smart pointer to the underlying class
00233   operator WorldState*() { return &ws[ProcessID::getID()]; } //!< pretend we're a simple pointer
00234   
00235 protected:
00236   //! This holds a separate WorldState pointer for each process
00237   /*! Note that under a multi-process model, each process is only ever going to reference one of these,
00238    *  (so we could get away with a single global pointer), but under a uni-process model, we wind up
00239    *  using the various entries to differentiate the thread groups */
00240   WorldState ws[ProcessID::NumProcesses];
00241 private:
00242   WorldStateLookup(const WorldStateLookup&); //!< don't call this
00243   WorldStateLookup& operator=(const WorldStateLookup&); //!< don't call this
00244 };
00245 //! the global state object, points into a shared memory region, created by MainObject
00246 extern WorldStateLookup state;
00247 
00248 inline const WorldState* WorldState::getCurrent() { return ::state; }
00249 
00250 #endif
00251 
00252 /*! @file
00253  * @brief Describes WorldState, maintains information about the robot's environment, namely sensors and power status
00254  * @author ejt (Creator)
00255  */
00256 
00257 #endif

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:53 2016 by Doxygen 1.6.3