Homepage | Demos | Overview | Downloads | Tutorials | Reference | Credits |
MotionSequenceEngine.hGo 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 |