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

Tekkotsu v2.4.1
Generated Tue Aug 16 16:32:47 2005 by Doxygen 1.4.4