| Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | 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 "IPC/ListMemBuf.h" 00007 #include "PostureEngine.h" 00008 00009 //! A handy class for storing a sequence of keyframed movements 00010 /*! Each outputs is 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, if you want to 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 intermediary 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 from ::state. 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, if #hold is set (the default) it will hold its last value 00029 * until the MotionSequence is reset or stopped. If #hold is false, 00030 * then the joint is treated as 0 weight once it reaches its last frame. 00031 * 00032 * Currently, MotionSequenceEngine is intended mainly for building, 00033 * not editing. It's easy to add keyframes, but hard/impossible to 00034 * delete them. 00035 * 00036 * The MotionSequenceEngine base class is an abstract class so that you can 00037 * create memory efficient motion sequences and simply refer to them 00038 * by the common base class instead of having to worry about the 00039 * actual size allocated in the template, MotionSequenceMC. 00040 * 00041 * @see MotionSequenceEngine::SizeSmall, MotionSequenceEngine::SizeMedium, MotionSequenceEngine::SizeLarge, MotionSequenceEngine::SizeXLarge, 00042 * 00043 * The file format used is as follows: ('<' and '>' are not meant literally) 00044 * - First line: '<tt>\#MSq</tt>' 00045 * - Followed by any series of:\n 00046 * - '<tt>advanceTime </tt><i>time-delta</i>' - moves playhead forward, in milliseconds (synonym for <tt>delay</tt>) 00047 * - '<tt>delay </tt><i>time-delta</i>' - moves playhead forward, in milliseconds (synonym for <tt>advanceTime</tt>) 00048 * - '<tt>setTime </tt><i>time</i>' - sets play time to specified value, in ms 00049 * - '<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[]) 00050 * - '<tt>load </tt><i>filename</i>' - file can be a posture or another motion sequence (if MS, leaves playhead at end of the motion sequence); see setPose() and overlayMotion() 00051 * - '<tt>loadExplicit </tt><i>filename</i>' - file must be a posture, sets position for all outputs, including zero-weighted ones; see setExplicitPose() 00052 * - '<tt>degrees</tt>' - all following <i>value</i>s will be interpreted as degrees [default] 00053 * - '<tt>radians</tt>' - all following <i>value</i>s will be interpreted as radians 00054 * - '<tt>#</tt><i>comment</i>' - a comment line 00055 * - Last line: '<tt>\#END</tt>' 00056 * 00057 * Lines beginning with '#' are ignored as comments. Be aware if you 00058 * load the file and then save it again, these comments will be lost. 00059 * 00060 * Example 1: This motion sequence will straighten out the head, panning from right to left.\n 00061 <table align="center"><tr><td align=left><pre> 00062 \#MSq 00063 degrees 00064 00065 <i>\# Straighten head</i> 00066 advanceTime 50 00067 NECK:tilt 15 00068 NECK:nod 0 00069 00070 <i>\# Pan right</i> 00071 advanceTime 850 00072 NECK:pan~ -45 00073 00074 <i>\# Pan left</i> 00075 advanceTime 900 00076 NECK:pan~ 45 00077 NECK:tilt 15 00078 NECK:nod 0 00079 00080 \#END 00081 </pre></td></tr></table> 00082 * 00083 * This graph illustrates the motion of the tilt and pan joints in example 1: 00084 * <img src="MotionSequenceGraph1.png"> 00085 * Notice how the joint will move from wherever it is initally to the first 00086 * keyframe <i>for that joint</i>. Specifying the tilt joint a second time 00087 * at the end of the motion forces the tilt joint to be held at that position 00088 * throughout the motion, regardless of the #hold setting at the time 00089 * the sequence is run. 00090 * 00091 * Example 2: This example will straighten the head and the tail, pan the 00092 * head left to right, and @e then pan the tail left to right.\n 00093 <table align="center"><tr><td align=left><pre> 00094 \#MSq 00095 degrees 00096 00097 <i>\# Bring head and tail to neural positions</i> 00098 advanceTime 50 00099 NECK:pan~ 0 00100 NECK:tilt 0 00101 TAIL:pan~ 0 00102 TAIL:tilt 0 00103 00104 <i>\# Pan left</i> 00105 advanceTime 1000 00106 NECK:pan~ 90 00107 <i>\# Pan right</i> 00108 advanceTime 1000 00109 NECK:pan~ -90 00110 00111 <i>\# Center head</i> 00112 <i>\# Update tail time index</i> 00113 advanceTime 500 00114 NECK:pan~ 0 00115 <i>\# Note this respecification of TAIL:pan~ at 0 -- see graph below</i> 00116 TAIL:pan~ 0 00117 00118 <i>\# Wag left</i> 00119 advanceTime 500 00120 TAIL:pan~ 90 00121 <i>\# Wag right</i> 00122 advanceTime 500 00123 TAIL:pan~ -90 00124 00125 \#END 00126 </pre></td></tr></table> 00127 * 00128 * These graphs illustrate the motion of the pan joint for the head and the tail: 00129 * <img src="MotionSequenceGraph2-head.png"> 00130 * <img src="MotionSequenceGraph2-tail.png"> 00131 * The head's motion should be straightforward. The thing to note in the tail's 00132 * graph is why the second <code>TAIL:pan~ 0</code> is necessary at time 00133 * 2550. If it were not specified, the tail would slowly move to the left over the 00134 * course of the head's movement. We want it to stay still until the head is done, 00135 * so it must be respecified at the same position to hold it at that value in the 00136 * intervening time. 00137 * 00138 * After loading a motion sequence, the playtime is left at the end. 00139 * This is to make it easy to append/overlay motion sequences. 00140 * However, the playhead will be reset to the beginning on the first 00141 * call to updateOutputs() if isPlaying() returns true. 00142 * 00143 * You can also create a motion sequence dynamically at run time: 00144 * \code 00145 * //This code sample will stand up, point the head forward and up 0.1 radians, 00146 * //and then autoprune 00147 * 00148 * //First declare the MotionSequence itself: 00149 * SharedObject< MotionSequenceMC<MotionSequenceEngine::SizeSmall> > stand; 00150 * 00151 * //Over the course of the first 700 milliseconds, go to standing posture: 00152 * standSit->setTime(700); 00153 * standSit->setPose(PostureEngine("stand.pos")); 00154 * // could also use standSit->loadFile("stand.pos") 00155 * 00156 * //Then take another 700 milliseconds to straighten out the head: 00157 * standSit->advanceTime(700); 00158 * //We'll set joints individually this time, instead of loading a posture file: 00159 * standSit->setOutputCmd(HeadOffset+PanOffset,0); 00160 * standSit->setOutputCmd(HeadOffset+RollOffset,0); 00161 * standSit->setOutputCmd(HeadOffset+TiltOffset,0.1); //look up .1 radians 00162 * 00163 * //Add to MotionManager: 00164 * motman->addPrunableMotion(standSit); 00165 * //Playback will now begin automatically, and region deallocated when done 00166 * \endcode 00167 * 00168 * By default, #playing is true. Thus, when you add a MotionSequenceMC 00169 * to the MotionManager, it will begin executing automatically. If 00170 * you do \e not want this behavior, simply call pause() before 00171 * adding the sequence. 00172 * 00173 * When the sequence reaches the end, isAlive() will return false. 00174 * If the motion was added with MotionManager::addPrunableMotion, the 00175 * motion sequence will then autoprune itself from the MotionManager. 00176 * However, you can either call MotionManager::addPersistentMotion() 00177 * to add it, or call setAutoPrune(false), if you want to retain the 00178 * same instantiation between executions. 00179 * 00180 * @see PostureEngine for information on the posture files 00181 * @see <a href="http://www.cs.cmu.edu/~dst/Tekkotsu/Tutorial/postures.shtml">David Touretzky's "Postures and Motion Sequences" Chapter</a> 00182 * @see <a href="http://www.cs.cmu.edu/afs/cs/academic/class/15494-s06/www/lectures/postures.pdf">CMU's Cognitive Robotics posture slides</a> 00183 * @todo We should also have an insertMotion() 00184 */ 00185 class MotionSequenceEngine : public LoadSave { 00186 public: 00187 //!constructor, will start playing immediately 00188 MotionSequenceEngine(); 00189 //!destructor 00190 virtual ~MotionSequenceEngine() {} 00191 00192 //! 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 00193 virtual int updateOutputs(); 00194 00195 //!@name LoadSave related 00196 virtual unsigned int getBinSize() const; //!< inherited, returns the size used to save the sequence 00197 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. 00198 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 00199 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. 00200 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 00201 void setSaveDegrees() { loadSaveMode=M_PI/180; } //!< will store angles as degrees on future saves 00202 bool isSaveDegrees() const { return loadSaveMode!=1; } //!< returns true if will store angles as degrees on future saves 00203 void setSaveRadians() { loadSaveMode=1; } //!< will store angles as radians on future saves 00204 bool isSaveRadians() const { return loadSaveMode==1; } //!< returns true if will store angles as degrees on future saves 00205 //@} 00206 00207 //!@name Sequence Construction 00208 virtual void clear()=0; //!< empties out the sequence (constant time operation - faster than a series of pops) 00209 void setTime(unsigned int x); //!< set the time for both playback and editing (in milliseconds) 00210 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() 00211 void setOutputCmd(unsigned int i, const OutputCmd& cmd); //!< will insert a keyframe for the given output, or change an existing one 00212 const OutputCmd& getOutputCmd(unsigned int i); //!< gets the value of output @a i at the playhead 00213 void setPose(const PostureEngine& pose); //!< calls setOutputCmd for all non-zero weighted OutputCmds in @a pose (if you wish to set from a file, use loadFile) 00214 void setExplicitPose(const PostureEngine& pose); //!< calls setOutputCmd on each of the OutputCmds in @a pose, even if they are zero-weight (can be used to fade joints in/out with other conflicting motions) 00215 PostureEngine getPose(); //!< returns the set of OutputCmd's at the current playhead as a PostureEngine 00216 void getPose(PostureEngine& pose); //!< stores the set of OutputCmd's at the current playhead into the specified PostureEngine 00217 void overlayPose(const PostureEngine& pose) __attribute__((__deprecated__)); //!< deprecated, use setPose instead (what setPose used to do is now setExplicitPose) 00218 unsigned int overlayMotion(const std::string& msFile); //!< loads @a msFile from disk and calls overlayMotion(const MotionSequenceEngine&) with it, returns the duration of @a msFile (0 if there was an error) 00219 void overlayMotion(const MotionSequenceEngine& ms); //!< applies each keyframe of @a ms to this, leaves playhead at the end (in other words, advances playhead to end of @a ms) 00220 void compress(); //!< compresses the sequence by eliminating sequences of moves which are identical 00221 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 00222 virtual unsigned int getUsedFrames() const=0; //!< returns the number of used key frames (Move's) which have been stored by the instantiation MotionSequenceEngine subclass 00223 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 00224 //@} 00225 00226 //!@name Playback Control 00227 bool isPlaying(); //! returns true if currently playing 00228 void play(); //!< restarts playback from beginning 00229 void pause() { playing=false; } //!< pauses playback until another call to play() or resume() 00230 void resume(); //!< begins playback from the current playtime 00231 unsigned int getTime() const { return playtime; } //!< returns the current position of the playback (in milliseconds), see setTime() 00232 unsigned int getEndTime() const { return endtime; } //!< returns the length of the motion sequence (in milliseconds) 00233 void setSpeed(float x) { playspeed=x; } //!< sets the playback speed (e.g. 1=regular, 0.5=half speed, -1=@b backwards) 00234 float getSpeed() const { return playspeed; } //!< returns the playback speed 00235 00236 virtual void setHold(bool h=true) { hold=h; } //!< Sets #hold - if this is set to false, it will allow a persistent motion to behave the same as a pruned motion, without being pruned 00237 virtual bool getHold() { return hold; } //!< return #hold 00238 00239 //@} 00240 00241 protected: 00242 // TYPES: 00243 typedef unsigned short Move_idx_t; //!< type for indexes to move structures in subclass's storage 00244 static Move_idx_t invalid_move; //!< used to mark the ends of the Move linked lists 00245 00246 //! This struct holds all the information needed about a frame for a particular output 00247 struct Move { 00248 //!constructor 00249 Move() : cmd(), next(), prev(), starttime(0) {} 00250 OutputCmd cmd; //!< the actual command to use 00251 Move_idx_t next; //!< the next frame 00252 Move_idx_t prev; //!< the previous frame 00253 unsigned int starttime; //!< the time (relative to first frame) this frame should be expressed at 00254 }; 00255 00256 // MEMBERS: 00257 Move_idx_t starts[NumOutputs]; //!< the beginning frame for each output animation 00258 Move_idx_t prevs[NumOutputs]; //!< the previous frame (the starttime for this frame will always be less than or equal to playtime) 00259 Move_idx_t nexts[NumOutputs]; //!< the upcoming frame (the starttime for this frame will always be greater than playtime) 00260 OutputCmd curs[NumOutputs]; //!< merely a cache of current values (if computed, see #curstamps) 00261 unsigned int curstamps[NumOutputs]; //!< timestamp of corresponding value in #curs 00262 unsigned int playtime; //!< the current time of playback, 0 is start of sequence 00263 unsigned int lasttime; //!< the time of the last update 00264 unsigned int endtime; //!< max of moves's Move::starttime's 00265 float playspeed; //!< multiplies the difference between current time and starttime, negative will cause play backwards 00266 bool playing; //!< true if playing, false if paused 00267 bool hold; //!< if set to true, the posture will be kept active; otherwise joints will be marked unused after each posture is achieved (as if the posture was pruned); set through setHold() 00268 00269 float loadSaveMode; //!< 1 to use radians, M_PI/180 for degrees during a save 00270 00271 virtual Move& getKeyFrame(Move_idx_t x) =0; //!< returns the Move struct corresponding to @a x in the subclass's actual data structure 00272 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 00273 virtual Move_idx_t newKeyFrame()=0; //!< causes subclass to create a new Move structure, returns its index 00274 virtual void eraseKeyFrame(Move_idx_t x)=0; //!< causes subclass to mark the corresponding Move structure as free 00275 00276 //!Does the actual calculation of position information. Perhaps replace with a Bezier or spline or something? 00277 void calcOutput(OutputCmd& ans, unsigned int t, const Move& prev, const Move& next) const { 00278 float prevweight=(float)(next.starttime-t)/(float)(next.starttime-prev.starttime); 00279 ans.set(prev.cmd,next.cmd,prevweight); 00280 } 00281 00282 //!Sets prev and next to the appropriate values for the given time and output index, return true if there was a change 00283 virtual bool setRange(unsigned int t,Move_idx_t& prev, Move_idx_t& next) const=0; 00284 00285 //!sets playtime to next time for which any output has a keyframe, -1 if none exists 00286 unsigned int setNextFrameTime(Move_idx_t p[NumOutputs], Move_idx_t n[NumOutputs]) const; 00287 00288 //!reads a line from a file, parsing it into variables, returns ending position 00289 static unsigned int readWord(const char buf[], const char * const buflen, char word[], const unsigned int wordlen); 00290 00291 //!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 00292 static unsigned int getOutputIndex(const char name[], unsigned int i); 00293 }; 00294 00295 /*! @file 00296 * @brief Describes MotionSequenceEngine, abstract code for smoothly transitioning between a sequence of postures 00297 * @author ejt (Creator) 00298 * 00299 * $Author: ejt $ 00300 * $Name: tekkotsu-3_0 $ 00301 * $Revision: 1.18 $ 00302 * $State: Exp $ 00303 * $Date: 2006/10/03 23:01:28 $ 00304 */ 00305 00306 #endif |
|
Tekkotsu v3.0 |
Generated Wed Oct 4 00:03:44 2006 by Doxygen 1.4.7 |