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