Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

MotionCommand.h

Go 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