Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | 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 "Shared/WorldState.h" 00008 #include "OutputCmd.h" 00009 #include <stddef.h> 00010 00011 class EventTranslator; 00012 class EventBase; 00013 00014 //! The abstract base class for motions, provides common interface. All motions should inherit from this 00015 /*! For instructions on how to create: 00016 * - <b>an instantiation</b> of an existing MotionCommand, see MotionManager 00017 * - <b>a new subclass</b> of MotionCommand, read on. Also see the step-by-step tutorials: 00018 * - <a href="../FirstMotionCommand.html">Tekkotsu's "First MotionCommand" Tutorial</a> 00019 * - <a href="http://www.cs.cmu.edu/~dst/Tekkotsu/Tutorial/motion.shtml">David Touretzky's Motion Commands chaper</a> 00020 * - <a href="http://www.cs.cmu.edu/afs/cs/academic/class/15494-s06/www/lectures/motion_commands.pdf">CMU's Cognitive Robotics slides</a> 00021 * 00022 * To create a new type of motion, you'll want to subclass this. You 00023 * don't need to do anything fancy, but just be sure to override the 3 00024 * abstract functions, updateOutputs(), isAlive(), and isDirty(). 00025 * 00026 * There is a quick-start boilerplate included in the distribution: <a href="http://cvs.tekkotsu.org/cgi/viewcvs.cgi/Tekkotsu/project/templates/motioncommand.h?rev=HEAD&content-type=text/vnd.viewcvs-markup"><i>project</i><tt>/templates/motioncommand.h</tt></a>: 00027 * 00028 * When an output is set to a value, that output is held at that value 00029 * until it is set to a new value, even if the MotionCommand that set 00030 * it is pruned or stops using the output. Outputs never "reset" to 0 00031 * or some other relatively arbitrary base value if all the 00032 * MotionCommands are removed. 00033 * 00034 * However, PID values will reset to the default values if pruned or 00035 * not set since these values <i>do</i> have a base value which you 00036 * will want to use 99% of the time. 00037 * 00038 * Be aware that there is a delay between when you set a joint to a 00039 * value and that actually is taken into account by the system - it's 00040 * on the order of FrameTime*NumFrames (currently 8*4 = 32 ms, so 00041 * worse case 2*8*4 = 64 ms) This is because the commands are double 00042 * buffered. PIDs, on the other hand, seem to take effect more 00043 * quickly. This un-synchronization can sometimes cause a bit of 00044 * jerkiness (mainly on startup, where there's a large difference 00045 * between desired and target values.) 00046 * 00047 * Here is the cycle of calls made by MotionManager to your command: 00048 * -# shouldPrune() (by default, this will return !isAlive() iff #autoprune==true) 00049 * -# updateOutputs() (assuming the MC wasn't pruned after the previous step) 00050 * 00051 * So, if you want to hold a joint at a value, each time your 00052 * updateOutputs function is called, you should tell the 00053 * MotionManager to keep the joint there (using one of 00054 * MotionManager::setOutput()'s). If you do not set a joint after a 00055 * call to updateOutputs, the MotionManager will assume you are no 00056 * longer using that joint and a lower priority MotionCommand may 00057 * inherit it. 00058 * 00059 * MotionCommands which generate events should use the inherited 00060 * MotionCommand::postEvent() instead of trying to access a global ::erouter - the 00061 * inherited version will properly handle sending the events 00062 * regardless of the current process context, but trying to access a 00063 * non-shared global like ::erouter could cause problems otherwise. 00064 * 00065 * @warning <b>Be careful what you call in MotionManager</b> \n 00066 * Some functions are marked MotionCommand-safe - this is another 00067 * issue due to our "fake" fork. In short, when a function is called 00068 * on a MotionCommand, it uses the context of whatever process created 00069 * it, not the process that actually made the function call. Thus, 00070 * when Motion calls updateOutputs(), calls that the MotionCommand 00071 * makes are indistinguishable from concurrent calls from Main. This 00072 * can cause deadlock if a function is called which locks the 00073 * MotionManager. To get around this, we need to pass the 'this' 00074 * parameter on functions that require a lock, namely 00075 * MotionManager::setOutputs(). This allows the MotionManager to 00076 * figure out that it's the same MotionCommand it previously called 00077 * updateOutputs() on, and thus avoid trying to lock itself again. 00078 * 00079 * @warning <b>Don't store pointers in motion commands!</b> \n 00080 * Since motion commands are in shared memory, and these shared memory 00081 * regions can have different base pointers in each process, pointers 00082 * will only be valid in the process from which they were assigned. 00083 * In other processes, that address may point to something else, 00084 * especially if it was pointing outside of the shared memory 00085 * regions.\n 00086 * There are convoluted ways of getting around this. If needed, 00087 * MotionManager could be modified to hand out shared memory regions 00088 * upon request. Let's try to avoid this for now. Keep 00089 * MotionCommands simple, without dynamic memory. Do more complicated 00090 * stuff with behaviors, which only have to worry about running in Main. 00091 */ 00092 class MotionCommand : public MotionManagerMsg { 00093 //!@nosubgrouping 00094 public: 00095 00096 // ***************** 00097 //! @name *** ABSTRACT: *** (must be defined by subclasses) 00098 // ***************** 00099 00100 //! is called once per update cycle, can do any processing you need to change your priorities or set output commands on the MotionManager 00101 /*! @return zero if no changes were made, non-zero otherwise 00102 * @see RobotInfo::NumFrames @see RobotInfo::FrameTime */ 00103 virtual int updateOutputs()=0; 00104 00105 //! not used by MotionManager at the moment, but could be used to reduce recomputation, and you may find it useful 00106 /*! @return zero if none of the commands have changed since last 00107 * getJointCmd(), else non-zero */ 00108 virtual int isDirty()=0; 00109 00110 //! used to prune "dead" motions from the MotionManager 00111 /*! note that a motion could be "paused" or inactive and therefore 00112 * not dirty, but still alive, biding its time to "strike" ;) 00113 * @return zero if the motion is still processing, non-zero otherwise */ 00114 virtual int isAlive()=0; 00115 00116 //@} 00117 00118 00119 // ****************** 00120 //! @name *** INHERITED: *** 00121 // ****************** 00122 00123 //! Constructor: Defaults to kStdPriority and autoprune==true 00124 MotionCommand() : MotionManagerMsg(), queue(NULL), autoprune(true), started(false) 00125 #ifdef PLATFORM_APERIOS 00126 , state() 00127 #endif 00128 { } 00129 //! Destructor 00130 virtual ~MotionCommand() {} 00131 00132 //! called after this is added to MotionManager; don't override this, use doStart instead 00133 virtual void start() { started=true; doStart(); } 00134 00135 //! called after this is removed from MotionManager; don't override this, use doStop instead 00136 virtual void stop() { doStop(); started=false; } 00137 00138 //! returns true if the MotionCommand is currently running (although it may be overridden by a higher priority MotionCommand) 00139 virtual bool isActive() const { return started; } 00140 00141 /*! @return current setting of autopruning - used to remove motion from groups when !isAlive() */ 00142 virtual bool getAutoPrune() { return autoprune; } 00143 00144 /*! @param ap bool representing requested autopruning setting */ 00145 virtual void setAutoPrune(bool ap) { autoprune=ap; } 00146 00147 //! whether this motion should be removed from its motion group automatically ( MotionCommand::autoprune && !isAlive()) 00148 /*! @return (MotionCommand::autoprune && !isAlive())*/ 00149 virtual bool shouldPrune() { return (autoprune && !isAlive()); } 00150 00151 //! only called from MMCombo during process setup, allows MotionCommands to send events 00152 void setTranslator(EventTranslator * q) { queue=q; } 00153 00154 #ifdef PLATFORM_APERIOS 00155 //! called by MotionManager each time a process checks out the motion, makes sure #state is set for the calling process 00156 void setWorldState(WorldState* s) { state.cur=s; } 00157 #endif 00158 00159 protected: 00160 //! Override this if you want to run some startup code after being added to the MotionManager. 00161 virtual void doStart() {} 00162 //! Override this if you want to clean up after removal from MotionManager 00163 /*! The old MotionManagerMsg::mc_id will still be available, but this value is no longer valid within the MotionManager. 00164 * Only use it if you need to clean up associated values stored elsewhere. */ 00165 virtual void doStop() {} 00166 00167 //! this utility function will probably be of use to a lot of MotionCommand's 00168 /*! Does a weighted average of a and b, favoring b by x percent (so x==0 results in a, x==1 results in b) 00169 * @param a first value 00170 * @param b second value 00171 * @param x weight of second value as opposed to first 00172 * @return @f$ a*(1.0-x)+b*x @f$ 00173 * @todo - replace with a more fancy spline based thing? */ 00174 static inline double interpolate(double a, double b, double x) { 00175 return a*(1.0-x)+b*x; 00176 } 00177 //! this utility function will probably be of use to a lot of MotionCommand's 00178 /*! Does a weighted average of a and b, favoring b by x percent (so x==0 results in a, x==1 results in b) 00179 * @param a first value 00180 * @param b second value 00181 * @param x weight of second value as opposed to first 00182 * @return @f$ a*(1.0-x)+b*x @f$ 00183 * @todo - replace with a more fancy spline based thing? */ 00184 static inline float interpolate(float a, float b, float x) { 00185 return a*(1-x)+b*x; 00186 } 00187 //! this utility function will probably be of use to a lot of MotionCommand's, see interpolate(double a,double b,double r) 00188 /*! interpolates both value and weights of JointCmd's 00189 * @param a first joint cmd 00190 * @param b second joint cmd 00191 * @param x weight to favor b's value and weight 00192 * @param r joint cmd to store the result */ 00193 static inline void interpolate(const OutputCmd& a, const OutputCmd& b, float x, OutputCmd& r) { 00194 r.set(interpolate(a.value,b.value,x),interpolate(a.weight,b.weight,x)); 00195 } 00196 //@} 00197 00198 //! calls EventTranslator::trapEvent() directly (avoids needing erouter, which is a non-shared global, causes problems with context, grr, silly OS) 00199 void postEvent(const EventBase& event); 00200 00201 EventTranslator * queue; //!< send events using this, instead of posting to the erouter 00202 00203 int autoprune; //!< default true, autoprune setting, if this is true and isAlive() returns false, MotionManager will attempt to remove the MC automatically 00204 bool started; //!< true if the MotionCommand is currently running (although it may be overridden by a higher priority MotionCommand) 00205 #ifdef PLATFORM_APERIOS 00206 //! purposely shadows global ::state as a member of MotionCommand, so subclasses will be guaranteed to use the current process's instance instead of that of the process they were created in 00207 struct StateRedirect { 00208 WorldState * operator->() const { return cur==NULL ? WorldState::getCurrent() : cur; } 00209 WorldState * cur; 00210 } state; 00211 #endif 00212 00213 private: 00214 MotionCommand(const MotionCommand&); //!< don't call 00215 MotionCommand& operator=(const MotionCommand&); //!< don't call 00216 }; 00217 00218 /*! @file 00219 * @brief Defines the MotionCommand class, used for creating motions of arbitrary complexity 00220 * @author ejt (Creator) 00221 */ 00222 00223 #endif 00224 |
Tekkotsu v5.1CVS |
Generated Mon May 9 04:58:45 2016 by Doxygen 1.6.3 |