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

Tekkotsu v2.0
Generated Wed Jan 21 03:20:29 2004 by Doxygen 1.3.4