Homepage Demos Overview Downloads Tutorials 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 "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_1 $
00190  * $Revision: 1.17 $
00191  * $State: Exp $
00192  * $Date: 2004/02/09 22:45:28 $
00193  */
00194 
00195 #endif
00196 

Tekkotsu v2.2.1
Generated Tue Nov 23 16:36:39 2004 by Doxygen 1.3.9.1