Homepage | Demos | Overview | Downloads | Tutorials | Reference | Credits |
00001 //-*-c++-*- 00002 #ifndef INCLUDED_MotionCommand_h 00003 #define INCLUDED_MotionCommand_h 00004 00005 #include "Shared/RobotInfo.h" 00006 #include "MotionManagerMsg.h" 00007 #include "Events/EventTranslator.h" 00008 #include "OutputCmd.h" 00009 00010 //! The abstract base class for motions, provides common interface. All motions should inherit from this 00011 /*! For instructions on how to create: 00012 * - <b>a new subclass</b> of MotionCommand, read on. Also see the step-by-step 00013 * <a href="../FirstMotionCommand.html">guide</a> 00014 * - <b>an instantiation</b> of a MotionCommand subclass, see MotionManager 00015 * 00016 * To create a new type of motion, you'll want to subclass this. You don't need to do 00017 * anything fancy, but just be sure to override the 3 abstract functions. 00018 * 00019 * When an output is set to a value, that value is retained until it is set to a new value, 00020 * even if the MotionCommand that set it is pruned or stops using the output. Outputs never 00021 * "reset" to 0 or some other relatively arbitrary base value. 00022 * 00023 * However, PID values will reset to the default values if pruned or not set since these values 00024 * do have a base value which you will want to use 99% of the time. 00025 * 00026 * Be aware that there is a delay between when you set a joint to a value and that actually 00027 * is taken into account by the system - it's on the order of RobotInfo::FrameTime*RobotInfo::NumFrames 00028 * (currently 8*4 = 32 ms, at most 2*8*4 = 64 ms) This is because the commands are double buffered. 00029 * PIDs, on the other hand, seem to take effect more quickly. This un-synchronization can sometimes 00030 * cause annoying jerkiness (mainly on startup, where there's a large difference between desired 00031 * and target values.) 00032 * 00033 * Here is the cycle of calls made by MotionManager to your command: 00034 * -# shouldPrune() (by default, this will call isAlive() iff autoprune==true) 00035 * -# updateJointCmds() (assuming the MC wasn't pruned after the previous step) 00036 * 00037 * So, if you want to hold a joint at a value, each time your updateJointCmds() function is called, 00038 * you should tell the MotionManager to keep the joint there (using one of MotionManager::setOutput()'s). 00039 * If you do not set a joint after a call to updateJointCmds, the MotionManager will assume you 00040 * are no longer using that joint and a lower priority MotionCommand may inherit it. 00041 * 00042 * MotionCommands which generate events should use the inherited postEvent() instead of trying 00043 * to access a global erouter - the inherited version will properly handle sending the events, 00044 * trying to access a non-shared global like erouter could cause problems. 00045 * 00046 * @warning <b>Be careful what you call in MotionManager</b> \n 00047 * Some functions are marked MotionCommand-safe - this is another issue due to our "fake" fork. 00048 * In short, when a function is called on a MotionCommand, it thinks it is still running in whatever 00049 * process created it, not the process that actually made the function call. Thus, when Motion 00050 * calls updateOutputs(), calls that the MotionCommand makes are indistinguishable from concurrent 00051 * calls from Main. This can cause deadlock if a function is called which locks the MotionManager. 00052 * To get around this, we need to pass the 'this' parameter on functions that require a lock, namely 00053 * MotionManager::setOutputs(). This allows the MotionManager to figure out that it's the same 00054 * MotionCommand it previously called updateOutputs() on, and thus avoid trying to lock itself again. 00055 * 00056 * @warning <b>Don't store pointers in motion commands!</b> \n 00057 * Since motion commands are in shared memory, and these shared memory regions can have different 00058 * base pointers in each process, pointers will only be valid in the process from which they were 00059 * assigned. In other processes, that address may point to something else, especially if it was 00060 * pointing outside of the shared memory regions.\n 00061 * There are convoluted ways of getting around this. If needed, MotionManager could be modified 00062 * to hand out shared memory regions upon request. Let's try to avoid this for now. Keep MotionCommands 00063 * simple, without dynamic memory. Do more complicated stuff with behaviors, which only have to run in Main. 00064 * @see REGDEF @see REGIMP 00065 */ 00066 class MotionCommand : public MotionManagerMsg { 00067 //!@nosubgrouping 00068 public: 00069 00070 // ***************** 00071 //! @name *** ABSTRACT: *** (must be defined by subclasses) 00072 // ***************** 00073 00074 //! is called once per update cycle, can do any processing you need to change your priorities or set output commands on the MotionManager 00075 /*! @return zero if no changes were made, non-zero otherwise @see RobotInfo::NumFrames @see RobotInfo::FrameTime */ 00076 virtual int updateOutputs()=0; 00077 00078 //! not used by MotionManager at the moment, but could be used to reduce recomputation, and you may find it useful 00079 /*! @return zero if none of the commands have changed since last getJointCmd(), else non-zero */ 00080 virtual int isDirty()=0; 00081 00082 //! used to prune "dead" motions from the MotionManager 00083 /*! note that a motion could be "paused" or inactive and therefore not dirty, 00084 * but still alive, biding its time to "strike" ;) 00085 * @return zero if the motion is still processing, non-zero otherwise */ 00086 virtual int isAlive()=0; 00087 00088 //@} 00089 00090 00091 // ****************** 00092 //! @name *** INHERITED: *** 00093 // ****************** 00094 00095 //! Constructor: Defaults to kStdPriority and autoprune==true 00096 MotionCommand() : MotionManagerMsg(), autoprune(true), started(false) {} 00097 //! Destructor 00098 virtual ~MotionCommand() {} 00099 00100 //! called after this is added to MotionManager 00101 virtual void DoStart() { started=true; } 00102 00103 //! called after this is removed from MotionManager 00104 virtual void DoStop() { started=false; clearID(); } 00105 00106 //! returns true if the MotionCommand is currently running (although it may be overridden by a higher priority MotionCommand) 00107 virtual bool isActive() const { return started; } 00108 00109 /*! @return current setting of autopruning - used to remove motion from groups when !isAlive() */ 00110 virtual bool getAutoPrune() { return autoprune; } 00111 00112 /*! @param ap bool representing requested autopruning setting */ 00113 virtual void setAutoPrune(bool ap) { autoprune=ap; } 00114 00115 //! whether this motion should be removed from its motion group automatically ( MotionCommand::autoprune && !isAlive()) 00116 /*! @return (MotionCommand::autoprune && !isAlive())*/ 00117 virtual bool shouldPrune() { return (autoprune && !isAlive()); } 00118 00119 //! only called from MMCombo during process setup, allows MotionCommands to send events 00120 static void setQueue(EventTranslator::Queue_t * q) { queue=q; } 00121 00122 protected: 00123 //! this utility function will probably be of use to a lot of MotionCommand's 00124 /*! Does a weighted average of a and b, favoring b by x percent (so x==0 results in a, x==1 results in b) 00125 * @param a first value 00126 * @param b second value 00127 * @param x weight of second value as opposed to first 00128 * @return @f$a*(1.0-x)+b*x@f$ 00129 * @todo - replace with a more fancy spline based thing? */ 00130 static inline double interpolate(double a, double b, double x) { 00131 return a*(1.0-x)+b*x; 00132 } 00133 //! this utility function will probably be of use to a lot of MotionCommand's 00134 /*! Does a weighted average of a and b, favoring b by x percent (so x==0 results in a, x==1 results in b) 00135 * @param a first value 00136 * @param b second value 00137 * @param x weight of second value as opposed to first 00138 * @return @f$a*(1.0-x)+b*x@f$ 00139 * @todo - replace with a more fancy spline based thing? */ 00140 static inline float interpolate(float a, float b, float x) { 00141 return a*(1.0-x)+b*x; 00142 } 00143 //! this utility function will probably be of use to a lot of MotionCommand's, see interpolate(double a,double b,double r) 00144 /*! interpolates both value and weights of JointCmd's 00145 * @param a first joint cmd 00146 * @param b second joint cmd 00147 * @param x weight to favor b's value and weight 00148 * @param r joint cmd to store the result */ 00149 static inline void interpolate(const OutputCmd& a, const OutputCmd& b, float x, OutputCmd& r) { 00150 r.set(interpolate(a.value,b.value,x),interpolate(a.weight,b.weight,x)); 00151 } 00152 //@} 00153 00154 //! calls EventTranslator::enqueue directly (avoids needing erouter, which is a non-shared global, causes problems with context, grr, silly OS) 00155 static void postEvent(const EventBase& event) { EventTranslator::enqueue(event,queue); } 00156 00157 static EventTranslator::Queue_t * queue; //!< queue to store outgoing events in - call the MotionCommand::postEvent 00158 00159 int autoprune; //!< default true, autoprune setting, if this is true and isAlive() returns false, MotionManager will attempt to remove the MC automatically 00160 bool started; //!< true if the MotionCommand is currently running (although it may be overridden by a higher priority MotionCommand) 00161 00162 }; 00163 00164 /*! @file 00165 * @brief Defines the MotionCommand class, used for creating motions of arbitrary complexity 00166 * @author ejt (Creator) 00167 * 00168 * $Author: ejt $ 00169 * $Name: tekkotsu-2_0 $ 00170 * $Revision: 1.16 $ 00171 * $State: Rel $ 00172 * $Date: 2003/07/28 05:55:16 $ 00173 */ 00174 00175 #endif 00176
Tekkotsu v2.0 |
Generated Wed Jan 21 03:20:29 2004 by Doxygen 1.3.4 |