Homepage Demos Overview Downloads Tutorials Reference
Credits

MotionSequenceEngine.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_MotionSequenceEngine_h_
00003 #define INCLUDED_MotionSequenceEngine_h_
00004 
00005 #include "Shared/LoadSave.h"
00006 #include "Shared/ListMemBuf.h"
00007 #include "PostureEngine.h"
00008 
00009 //! A handy little (or not so little) class for switching between a sequence of postures
00010 /*! Outputs are handled independently.  It's easy to add keyframes
00011  *  which modify all of the outputs, but since each output is tracked
00012  *  individually, OutputCmd's with 0 weight can be used to not affect
00013  *  other motions.  For instance, pan the head left to right while
00014  *  moving the right leg up and down several times, you won't have to
00015  *  specify the position of the head in its motion at each of the leg
00016  *  motion keyframes.
00017  *
00018  *  Be aware that the 0 time frame will be replaced on a call to
00019  *  play() with the current body posture.  However, this only applies
00020  *  to  outputs which have a non-zero weighted frame defined at some
00021  *  point.  The weights, of the 0 time frame will remain unchanged.  
00022  *  These weights are initially set to 0, so that it's
00023  *  possible to 'fade in' the first frame of the motion sequence from
00024  *  whereever the body happens to be (or already doing)
00025  *
00026  *  To fade out at the end, set a frame with 0 weight for everything.
00027  *  Otherwise it will simply die suddenly.  When a joint reaches its
00028  *  last keyframe, it will be set to 0 weight for all future
00029  *  updateOutputs() (unless of course the playhead is reset)
00030  *
00031  *  Currently, MotionSequenceEngine is intended mainly for building, 
00032  *  not editing.  It's easy to add keyframes, but hard/impossible to
00033  *  delete them.
00034  *
00035  *  The MotionSequenceEngine base class is an abstract class so that you can
00036  *  create memory efficient motion sequences and simply refer to them
00037  *  by the common base class instead of having to worry about the
00038  *  actual size allocated in the template, MotionSequenceMC.
00039  *
00040  *  @see MotionSequenceEngine::SizeSmall, MotionSequenceEngine::SizeMedium, MotionSequenceEngine::SizeLarge, MotionSequenceEngine::SizeXLarge, 
00041  *  
00042  *  The file format used is as follows: ('<' and '>' are not meant literally)
00043  *  - First line: '<tt>#MSq</tt>'
00044  *  - Followed by any series of:\n
00045  *    - '<tt>advanceTime </tt><i>time-delta</i>' - moves playhead forward, in milliseconds (synonym for <tt>delay</tt>)
00046  *    - '<tt>delay </tt><i>time-delta</i>' - moves playhead forward, in milliseconds (synonym for <tt>advanceTime</tt>)
00047  *    - '<tt>setTime </tt><i>time</i>' - sets play time to specified value, in ms
00048  *    - '<i>outputname</i><tt> </tt><i>value</i><tt> </tt>[<i>weight</i>]' - sets the specified output to the value - assumes 1 for weight; you can view the list of valid joint names in the outputNames array within the RobotInfo extension namespace for your model.  (e.g. ERS210Info::outputNames[])
00049  *    - '<tt>load </tt><i>filename</i>' - file is a posture, sets position
00050  *    - '<tt>overlay </tt><i>filename</i>' - file can be a posture or another motion sequence
00051  *    - '<tt>degrees</tt>' - following <i>value</i>s will be interpreted as degrees [default]
00052  *    - '<tt>radians</tt>' - following <i>value</i>s will be interpreted as radians
00053  *    - '<tt>#</tt><i>comment</i>' - a comment line
00054  *  - Last line: '<tt>#END</tt>'
00055  *  
00056  *  Lines beginning with '#' are ignored as comments.  Be aware if you
00057  *  load the file and then save it again, these comments will be lost.
00058  *  
00059  *  After loading a motion sequence, the playtime is left at the end.
00060  *  This is to make it easy to append/overlay motion sequences.
00061  *  However, the playhead will be reset to the beginning on the first
00062  *  call to updateOutputs() if isPlaying() returns true.
00063  *
00064  *  You can also create a motion sequence dynamically at run time:
00065  *  \code
00066  *  //This code sample will stand up, point the head forward and up 0.1 radians,
00067  *  //and then autoprune
00068  *
00069  *  //First declare the MotionSequence itself:
00070  *  SharedObject< MotionSequenceMC<MotionSequenceEngine::SizeSmall> > stand;
00071  *
00072  *  //Over the course of the first 700 milliseconds, go to standing posture:
00073  *  standSit->setTime(700);
00074  *  standSit->setPose(PostureEngine("stand.pos")); // can also use LoadFile("stand.pos")
00075  *
00076  *  //Then take another 700 milliseconds to straighten out the head:
00077  *  standSit->advanceTime(700);
00078  *  //We'll set joints individually this time, instead of loading a posture file:
00079  *  standSit->setOutputCmd(HeadOffset+PanOffset,0);
00080  *  standSit->setOutputCmd(HeadOffset+RollOffset,0);
00081  *  standSit->setOutputCmd(HeadOffset+TiltOffset,0.1); //look up .1 radians
00082  *
00083  *  //Add to MotionManager:
00084  *  motman->addPersistentMotion(standSit);
00085  *  //Playback will now begin automatically, and region deallocated when done
00086  *  \endcode
00087  *  
00088  *  By default, #playing is true.  Thus, when you add a MotionSequenceMC
00089  *  to the MotionManager, it will begin executing automatically.  If
00090  *  you do \e not want this behavior, simply call pause() before
00091  *  adding the sequence.
00092  *
00093  *  When the sequence reaches the end, isAlive() will return false.
00094  *  If the motion was added with MotionManager::addPrunableMotion, the
00095  *  motion sequence will then autoprune itself from the MotionManager.
00096  *  However, you can either call MotionManager::addPersistentMotion()
00097  *  to add it, or call setAutoPrune(false), if you want to retain the
00098  *  same instantiation between executions.
00099  *  
00100  *  @see PostureEngine for information on the posture files
00101  */
00102 class MotionSequenceEngine : public LoadSave {
00103 public:
00104   //!constructor, will start playing immediately
00105   MotionSequenceEngine() : LoadSave(), playtime(1), lasttime(0), endtime(0), playspeed(1.0), playing(true), loadSaveMode(M_PI/180) {}
00106   //!destructor
00107   virtual ~MotionSequenceEngine() {}
00108 
00109   //!To avoid code bloat if there are a large number of different sized MotionSequences, use these sizes where possible.
00110   /*!@deprecated use MotionSequenceMC typedefs (e.g. TinyMotionSequenceMC) in conjunction with MotionSequenceMC::CAPACITY() */
00111   //!@name Template Sizes (deprecated)
00112   static const unsigned int SizeTiny __attribute__((deprecated))   =NumOutputs*2; //!< deprecated, use TinyMotionSequenceMC for type specification, or TinyMotionSequenceMC::CAPACITY if you need the actual value
00113   static const unsigned int SizeSmall __attribute__((deprecated))  =NumOutputs*3; //!< deprecated, use SmallMotionSequenceMC for type specification, or SmallMotionSequenceMC::CAPACITY if you need the actual value
00114   static const unsigned int SizeMedium __attribute__((deprecated)) =NumOutputs*6; //!< deprecated, use MediumMotionSequenceMC for type specification, or MediumMotionSequenceMC::CAPACITY if you need the actual value
00115   static const unsigned int SizeLarge __attribute__((deprecated))  =NumOutputs*11; //!< deprecated, use LargeMotionSequenceMC for type specification, or LargeMotionSequenceMC::CAPACITY if you need the actual value
00116   static const unsigned int SizeXLarge __attribute__((deprecated)) =NumOutputs*26; //!< deprecated, use XLargeMotionSequenceMC for type specification, or XLargeMotionSequenceMC::CAPACITY if you need the actual value
00117   //@}
00118 
00119   //! similar to the MotionCommand::updateOutputs, although this isn't a motion command, and doesn't make any calls on MotionManager - merely updates #lasttime, expects subclasses to do the work of sending new commands to the system
00120   virtual int updateOutputs();
00121   
00122   //!@name LoadSave related
00123   virtual unsigned int getBinSize() const; //!< inherited, returns the size used to save the sequence
00124   virtual unsigned int LoadBuffer(const char buf[], unsigned int len); //!< inherited, doesn't clear before loading - call clear yourself if you want to reset, otherwise it will overlay.  Leaves playtime at end of load.
00125   virtual unsigned int SaveBuffer(char buf[], unsigned int len) const; //!< inherited, saves the motion sequence - will save a flat file - doesn't remember references to other files which were loaded
00126   virtual unsigned int LoadFile(const char filename[]); //!< inherited, doesn't clear before loading - call clear yourself if you want to reset, otherwise it will overlay.  Leaves playtime at end of load.
00127   virtual unsigned int SaveFile(const char filename[]) const; //!< inherited, saves the motion sequence - will save a flat file - doesn't remember references to other files which were loaded
00128   void setSaveDegrees() { loadSaveMode=M_PI/180; }       //!< will store angles as degrees on future saves
00129   bool isSaveDegrees() const { return loadSaveMode!=1; } //!< returns true if will store angles as degrees on future saves
00130   void setSaveRadians() { loadSaveMode=1; }              //!< will store angles as radians on future saves
00131   bool isSaveRadians() const { return loadSaveMode==1; } //!< returns true if will store angles as degrees on future saves
00132   //@}
00133   
00134   //!@name Sequence Construction
00135   virtual void clear()=0; //!< empties out the sequence (constant time operation - faster than a series of pops)
00136   void setTime(unsigned int x); //!< set the time for both playback and editing (in milliseconds)
00137   unsigned int advanceTime(unsigned int x) {setTime(playtime+x); return playtime; } //!< advance the play/edit index by @a x milliseconds, and then returns the new getTime()
00138   void setOutputCmd(unsigned int i, const OutputCmd& cmd); //!< will insert a keyframe for the given output, or change an existing one
00139   const OutputCmd& getOutputCmd(unsigned int i); //!< gets the value of output @a i at the playhead
00140   void setPose(const PostureEngine& pose); //!< calls setOutputCmd on each of the OutputCmds in @a pose
00141   void overlayPose(const PostureEngine& pose); //!< calls setOutputCmd on non-zero weighted OutputCmds in @a pose
00142   void compress(); //!< compresses the sequence by eliminating sequences of moves which are identical
00143   virtual unsigned int getMaxFrames() const=0; //!< returns the maximum number of key frames (Move's) which can be stored, determined by the instantiating MotionSequenceMC's template parameter
00144   virtual unsigned int getUsedFrames() const=0; //!< returns the number of used key frames (Move's) which have been stored by the instantiation MotionSequenceEngine subclass
00145   void makeSafe(const float vels[NumOutputs], float margin); //!< will insert time into the motion where needed to keep the joint velocities at or below the speeds given in @a vels * @a margin
00146   //@}
00147 
00148   //!@name Playback Control
00149   bool isPlaying();                                     //! returns true if currently playing
00150   void play();                                          //!< restarts playback from beginning
00151   void pause() { playing=false; }                       //!< pauses playback until another call to play() or resume()
00152   void resume();                                        //!< begins playback from the current playtime
00153   unsigned int getTime() const { return playtime; }     //!< returns the current position of the playback (in milliseconds), see setTime()
00154   unsigned int getEndTime() const { return endtime; }   //!< returns the length of the motion sequence (in milliseconds)
00155   void setSpeed(float x) { playspeed=x; }               //!< sets the playback speed (e.g. 1=regular, 0.5=half speed, -1=@b backwards)
00156   float getSpeed() const { return playspeed; }          //!< returns the playback speed
00157   //@}
00158 
00159   //!@name Deprecated
00160   void setPlayTime(unsigned int x) __attribute__((deprecated)); //!< deprecated, use setTime(unsigned int x)
00161   unsigned int getPlayTime() const __attribute__((deprecated)); //!< deprecated, use getTime()
00162   void setPlaySpeed(float x) __attribute__((deprecated)); //!< deprecated, use setSpeed(float x)
00163   float getPlaySpeed() const __attribute__((deprecated)); //!< deprecated, use getSpeed()
00164   //@}
00165 protected:
00166   // TYPES:
00167   typedef unsigned short Move_idx_t; //!< type for indexes to move structures in #moves
00168   static Move_idx_t invalid_move; //!< used to mark the ends of the Move linked lists
00169 
00170   //! This struct holds all the information needed about a frame for a particular output
00171   struct Move {
00172     //!constructor
00173     Move() : cmd(), next(), prev(), starttime(0) {}
00174     OutputCmd cmd;           //!< the actual command to use
00175     Move_idx_t next;        //!< the next frame
00176     Move_idx_t prev;        //!< the previous frame
00177     unsigned int starttime; //!< the time (relative to first frame) this frame should be expressed at
00178   };
00179 
00180   // MEMBERS:
00181   Move_idx_t starts[NumOutputs]; //!< the beginning frame for each output animation
00182   Move_idx_t prevs[NumOutputs];  //!< the previous frame (the starttime for this frame will always be less than or equal to playtime)
00183   Move_idx_t nexts[NumOutputs];  //!< the upcoming frame (the starttime for this frame will always be greater than playtime)
00184   OutputCmd curs[NumOutputs];          //!< merely a cache of current values (if computed, see #curstamps)
00185   unsigned int curstamps[NumOutputs]; //!< timestamp of corresponding value in #curs
00186   unsigned int playtime;              //!< the current time of playback, 0 is start of sequence
00187   unsigned int lasttime;              //!< the time of the last update
00188   unsigned int endtime;               //!< max of #moves's Move::starttime's
00189   float playspeed;                    //!< multiplies the difference between current time and starttime, negative will cause play backwards
00190   bool playing;                       //!< true if playing, false if paused
00191   
00192   float loadSaveMode;                 //!< 1 to use radians, M_PI/180 for degrees during a save
00193 
00194   virtual Move& getKeyFrame(Move_idx_t x) =0;            //!< returns the Move struct corresponding to @a x in the subclass's actual data structure
00195   virtual const Move& getKeyFrame(Move_idx_t x) const=0; //!< returns the Move struct corresponding to @a x in the subclass's actual data structure
00196   virtual Move_idx_t newKeyFrame()=0;                    //!< causes subclass to create a new Move structure, returns its index
00197   virtual void eraseKeyFrame(Move_idx_t x)=0;            //!< causes subclass to mark the corresponding Move structure as free
00198 
00199   //!Does the actual calculation of position information.  Perhaps replace with a Bezier or spline or something?
00200   void calcOutput(OutputCmd& ans, unsigned int t, const Move& prev, const Move& next) const {
00201     float prevweight=(float)(next.starttime-t)/(float)(next.starttime-prev.starttime);
00202     ans.set(prev.cmd,next.cmd,prevweight);
00203   }
00204   
00205   //!Sets prev and next to the appropriate values for the given time and output index
00206   virtual void setRange(unsigned int t,Move_idx_t& prev, Move_idx_t& next) const=0;
00207 
00208   //!sets playtime to next time for which any output has a keyframe, -1 if none exists
00209   unsigned int setNextFrameTime(Move_idx_t p[NumOutputs], Move_idx_t n[NumOutputs]) const;
00210   
00211   //!reads a line from a file, parsing it into variables, returns ending position
00212   static unsigned int readWord(const char buf[], const char * const buflen, char word[], const unsigned int wordlen);
00213 
00214   //!returns the index for the output named in the string or NumOutputs if not found, begins search through RobotInfo::outputName's at index @a i
00215   static unsigned int getOutputIndex(const char name[], unsigned int i);
00216 };
00217 
00218 //! deprecated, use MotionSequenceEngine directly instead
00219 /*! @deprecated, use MotionSequenceEngine directly instead */
00220 typedef MotionSequenceEngine MotionSequence __attribute__ ((deprecated)); 
00221 
00222 /*! @file
00223  * @brief Describes MotionSequenceEngine, abstract code for smoothly transitioning between a sequence of postures
00224  * @author ejt (Creator)
00225  *
00226  * $Author: ejt $
00227  * $Name: tekkotsu-2_2_2 $
00228  * $Revision: 1.7 $
00229  * $State: Exp $
00230  * $Date: 2004/12/23 01:47:07 $
00231  */
00232 
00233 #endif

Tekkotsu v2.2.2
Generated Tue Jan 4 15:43:14 2005 by Doxygen 1.4.0