Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
PostureEngine.hGo to the documentation of this file.00001 //-*-c++-*- 00002 #ifndef INCLUDED_PostureEngine_h 00003 #define INCLUDED_PostureEngine_h 00004 00005 #include "Motion/OutputCmd.h" 00006 #include "Motion/Kinematics.h" 00007 #include "Shared/RobotInfo.h" 00008 #include "Shared/LoadSave.h" 00009 00010 class WorldState; 00011 00012 //! A class for storing a set of positions and weights for all the outputs 00013 /*! File Format: ([..] indicates an optional parameter)\n 00014 * - First line: '<tt>\#POS</tt>' 00015 * - Followed by a series of: 00016 * - '<tt>specialize </tt><i>[regex]</i>' - only robots whose model name matches the regular 00017 * expression will attempt to parse lines between this and the next 'specialize' command. An empty 00018 * (absent) regex matches all robots (equivalent to '<tt>specialize .*</tt>') 00019 * - '<tt>condensed </tt><i>model</i>' - specifies model name for which condensed specifications will be 00020 * interpreted 00021 * - '<tt>verbose</tt>' - switches the load/save format back to "verbose" style, where each output/sensor 00022 * value is listed individually 00023 * - '<tt><</tt><i>section</i><tt>></tt> ... <tt></</tt><i>section</i><tt>></tt>' - specifies a 00024 * section for following "verbose" style lines (valid <i>section</i> values listed below) 00025 * - '<i>section</i> <i>value1</i> <i>value2</i> <i>value3</i> ...' - specify all values for a section in 00026 * one line, "condensed" style (valid <i>section</i> values listed below). Must have a value for every 00027 * item in the section (no extra or missing values) 00028 * - '<i>output-name</i> <i>value</i> <i>[weight]</i>' - specifies an output value, with optional weighting 00029 * value (if no weight specified, '1' is assumed) 00030 * - Last line: '<tt>\#END</tt>' 00031 * 00032 * Note that '=' can be used to separate tokens as well as any whitespace character. 00033 * All angle values should be specified in radians. 00034 * 00035 * Valid section names are: 00036 * - <tt>meta-info</tt> - only recognizes two fields: <tt>timestamp</tt> and <tt>framenumber</tt> 00037 * - <tt>outputs</tt> - supports all output names (e.g. ERS7Info::outputNames) 00038 * - <tt>buttons</tt> - supports all button names (e.g. ERS7Info::buttonNames) 00039 * - <tt>sensors</tt> - supports all sensor names (e.g. ERS7Info::sensorNames) 00040 * - <tt>pidduties</tt> - supports output names corresponding to PID joints (this is the "duty cycle" for the joint) 00041 * 00042 * Additionally 'weights' can be used as a condensed section name (but not a 00043 * verbose tag-style section, since weights are specified on each line). The 00044 * 'weights' specification must follow the 'outputs' specification to be effective. 00045 * 00046 * Data following '\#' is ignored as comments. Be aware if you 00047 * load the file and then save it again, these comments will be lost. 00048 * 00049 * Example 1: Specifies only neck joints, looks forward and up a little 00050 <table><tr><td align=left><pre> 00051 \#POS 00052 NECK:tilt 0 00053 NECK:pan 0 00054 NECK:nod 0.2 00055 \#END 00056 </pre></td></tr></table> 00057 * All other, unspecified, joints will be set to weight=0. 00058 * 00059 * Example 2: Logged sensor data from an ERS-7 robot 00060 <table><tr><td align=left><tt> 00061 \#POS<br> 00062 condensed ERS-7<br> 00063 meta-info = 1439041 178803<br> 00064 outputs = -0.131722 0.148077 1.74592 -0.30276 0.341717 2.13361 -1.03935 0.091124 2.18958 -0.804097 0.034171 1.67458 -0.016362 -0.089143 0.125563 0.407243 -0.054399 -0.064704 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0<br> 00065 buttons = 0 0 0 0 0 0 0 0 0 1<br> 00066 sensors = 500 860.139 425 -2.06456 -0.516139 -8.94642 0.99 30.63 2200 8.265 0<br> 00067 pidduties = -0.164062 0.0878906 0.0957031 0.246094 -0.0195312 -0.0546875 -0.164062 -0.0195312 0.164062 0.0273438 0 -0.0683594 -0.00585938 -0.00390625 0.0820312 -0.0390625 0.015625 0.00390625<br> 00068 \#END<br> 00069 </tt></td></tr></table> 00070 * Condensed posture files can still be loaded on other models. For each entry, RobotInfo::Capabilities will be 00071 * used to map from the model specified by the <tt>condensed</tt> command to the current host. 00072 * 00073 * @see PostureMC 00074 * @see <a href="http://www.cs.cmu.edu/~tekkotsu/Kinematics.html">Tekkotsu's Kinematics page</a> 00075 * @see <a href="http://www.cs.cmu.edu/~dst/Tekkotsu/Tutorial/postures.shtml">David Touretzky's "Postures and Motion Sequences" Chapter</a> 00076 * @see <a href="http://www.cs.cmu.edu/~dst/Tekkotsu/Tutorial/forwardkin.shtml">David Touretzky's "Forward Kinematics" Chapter</a> 00077 * @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> 00078 * @see <a href="http://www.cs.cmu.edu/afs/cs/academic/class/15494-s06/www/lectures/kinematics.pdf">CMU's Cognitive Robotics kinematics slides</a> 00079 */ 00080 class PostureEngine : public LoadSave, public Kinematics { 00081 public: 00082 00083 //!@name Constructors 00084 00085 //!constructor 00086 PostureEngine() : LoadSave(), Kinematics(*kine), saveFormatCondensed(false), loadSaveSensors(NULL) {} 00087 //!constructor, loads a position from a file 00088 /*! @todo might want to make a library stored in memory of common positions so they don't have to be loaded repeatedly from memstick */ 00089 PostureEngine(const std::string& filename) : LoadSave(), Kinematics(*kine), saveFormatCondensed(false), loadSaveSensors(NULL) { loadFile(filename.c_str()); } 00090 //!constructor, initializes joint positions to the current state of the outputs as defined by @a state 00091 PostureEngine(const WorldState* st) : LoadSave(), Kinematics(*kine), saveFormatCondensed(false), loadSaveSensors(NULL) { if(st!=NULL) takeSnapshot(*st); } 00092 00093 //! copy constructor 00094 PostureEngine(const PostureEngine& pe) 00095 : LoadSave(pe), Kinematics(pe), saveFormatCondensed(pe.saveFormatCondensed), loadSaveSensors(pe.loadSaveSensors) 00096 { 00097 for(unsigned int i=0; i<NumOutputs; i++) 00098 cmds[i]=pe.cmds[i]; 00099 } 00100 00101 //! assignment operator 00102 PostureEngine& operator=(const PostureEngine& pe) { 00103 LoadSave::operator=(pe); 00104 Kinematics::operator=(pe); 00105 saveFormatCondensed=pe.saveFormatCondensed; 00106 loadSaveSensors=pe.loadSaveSensors; 00107 for(unsigned int i=0; i<NumOutputs; i++) 00108 cmds[i]=pe.cmds[i]; 00109 return *this; 00110 } 00111 00112 //! destructor 00113 virtual ~PostureEngine(); 00114 //@} 00115 00116 00117 00118 //! You should be able to call the non-virtual functions without checking out, just a MotionManager::peekMotion(). Theoretically. 00119 //!@name Output Value Access/Control 00120 virtual void takeSnapshot(); //!< sets the values of #cmds to the current state of the outputs (doesn't change the weights) 00121 virtual void takeSnapshot(const WorldState& st); //!< sets the values of #cmds to the current state of the outputs as defined by @a state (doesn't change the weights) 00122 virtual void setWeights(float w) { setWeights(w,0,NumOutputs); } //!< set the weights of all #cmds 00123 virtual void setWeights(float w, unsigned int lowjoint, unsigned int highjoint); //!< the the weights of a range of #cmds 00124 virtual void clear(); //!< sets all joints to unused 00125 inline PostureEngine& setOutputCmd(unsigned int i, const OutputCmd& c) { cmds[i]=c; return *this; } //!<sets output @a i to OutputCmd @a c, returns @c *this so you can chain them; also remember that OutputCmd support implicit conversion from floats (so you can just pass a float) 00126 inline OutputCmd& operator()(unsigned int i) { return cmds[i]; } //!< returns output @a i, returns a reference so you can also set through an assignment to this call, e.g. pose(MouthOffset)=.1; (remember that OutputCmd support implicit conversion from floats) 00127 inline const OutputCmd& operator()(unsigned int i) const { return cmds[i]; } //!< returns output @a i 00128 inline OutputCmd& getOutputCmd(unsigned int i) { return cmds[i]; } //!< returns output @a i, returns a reference so you can also set through an assignment 00129 inline const OutputCmd& getOutputCmd(unsigned int i) const { return cmds[i]; } //!< returns output @a i 00130 //@} 00131 00132 00133 00134 //!Uses LoadSave interface so you can load/save to files, uses a human-readable storage format 00135 //!@name LoadSave 00136 virtual void setSaveFormat(bool condensed, WorldState* ws); //!< sets #saveFormatCondensed and #loadSaveSensors (pass ::state for @a ws if you want to use current sensor values) 00137 virtual void setLoadedSensors(WorldState* ws) { loadSaveSensors=ws; } //!< if @a ws is non-NULL, any sensor values in loaded postures will be stored there (otherwise they are ignored) 00138 virtual WorldState* getLoadedSensors() const { return loadSaveSensors; } //!< returns value previously stored by setLoadSensors() 00139 virtual unsigned int getBinSize() const; 00140 virtual unsigned int loadBuffer(const char buf[], unsigned int len); 00141 virtual unsigned int saveBuffer(char buf[], unsigned int len) const; 00142 virtual unsigned int loadFile(const char filename[]); 00143 virtual unsigned int saveFile(const char filename[]) const; 00144 //@} 00145 00146 00147 00148 //!@name Kinematics 00149 00150 //! Performs inverse kinematics to solve for positioning @a Peff on link @a j as close as possible to @a Ptgt (base coordinates in homogenous form); if solution found, stores result in this posture and returns true 00151 /*! @param Ptgt the target point, in base coordinates 00152 * @param link the output offset of the joint to move 00153 * @param Peff the point (relative to @a link) which you desire to have moved to @a Ptgt (it's the desired "effector") 00154 * 00155 * The difference between solveLinkPosition() and solveLinkVector() is typically small, 00156 * but critical when you're trying to look at something -- the solution obtained by 00157 * simplying trying to solve for the position may not align the vector with the target -- 00158 * solveLinkVector() tries to ensure the vector is aligned with the target, even if that 00159 * isn't the closest solution position-wise. 00160 */ 00161 virtual bool solveLinkPosition(const NEWMAT::ColumnVector& Ptgt, unsigned int link, const NEWMAT::ColumnVector& Peff); 00162 00163 //! Performs inverse kinematics to solve for positioning Peff on link @a j as close as possible to @a Ptgt (base coordinates); if solution found, stores result in this posture and returns true 00164 /*! @param Ptgt_x the target x position (relative to base frame) 00165 * @param Ptgt_y the target y position (relative to base frame) 00166 * @param Ptgt_z the target z position (relative to base frame) 00167 * @param link the output offset of the joint to move 00168 * @param Peff_x the x position (relative to @a link) which you desire to have moved to @a Ptgt (it's the desired "effector") 00169 * @param Peff_y the y position (relative to @a link) which you desire to have moved to @a Ptgt (it's the desired "effector") 00170 * @param Peff_z the z position (relative to @a link) which you desire to have moved to @a Ptgt (it's the desired "effector") 00171 * 00172 * The difference between solveLinkPosition() and solveLinkVector() is typically small, 00173 * but critical when you're trying to look at something -- the solution obtained by 00174 * simplying trying to solve for the position may not align the vector with the target -- 00175 * solveLinkVector() tries to ensure the vector is aligned with the target, even if that 00176 * isn't the closest solution position-wise. 00177 */ 00178 virtual bool solveLinkPosition(float Ptgt_x, float Ptgt_y, float Ptgt_z, unsigned int link, float Peff_x, float Peff_y, float Peff_z) 00179 { return solveLinkPosition(pack(Ptgt_x,Ptgt_y,Ptgt_z),link,pack(Peff_x,Peff_y,Peff_z)); } 00180 00181 //! Performs inverse kinematics to solve for aligning the vector through Peff on link @a j and the link's origin to point at @a Ptgt (base coordinates in homogenous form); if solution found, stores result in this posture and returns true 00182 /*! @param Ptgt the target point, in base coordinates 00183 * @param link the output offset of the joint to move 00184 * @param Peff the point (relative to @a link) which you desire to have moved to @a Ptgt (it's the desired "effector") 00185 * 00186 * The difference between solveLinkPosition() and solveLinkVector() is typically small, 00187 * but critical when you're trying to look at something -- the solution obtained by 00188 * simplying trying to solve for the position may not align the vector with the target -- 00189 * solveLinkVector() tries to ensure the vector is aligned with the target, even if that 00190 * isn't the closest solution position-wise. 00191 */ 00192 virtual bool solveLinkVector(const NEWMAT::ColumnVector& Ptgt, unsigned int link, const NEWMAT::ColumnVector& Peff); 00193 00194 //! Performs inverse kinematics to solve for aligning the vector through Peff on link @a j and the link's origin to point at @a Ptgt (base coordinates); if solution found, stores result in this posture and returns true 00195 /*! @param Ptgt_x the target x position (relative to base frame) 00196 * @param Ptgt_y the target y position (relative to base frame) 00197 * @param Ptgt_z the target z position (relative to base frame) 00198 * @param link the output offset of the joint to move 00199 * @param Peff_x the x position (relative to @a link) which you desire to have moved to @a Ptgt (it's the desired "effector") 00200 * @param Peff_y the y position (relative to @a link) which you desire to have moved to @a Ptgt (it's the desired "effector") 00201 * @param Peff_z the z position (relative to @a link) which you desire to have moved to @a Ptgt (it's the desired "effector") 00202 * 00203 * @todo this method is an approximation, could be more precise, and perhaps faster, although this is pretty good. 00204 * 00205 * The difference between solveLinkPosition() and solveLinkVector() is typically small, 00206 * but critical when you're trying to look at something -- the solution obtained by 00207 * simplying trying to solve for the position may not align the vector with the target -- 00208 * solveLinkVector() tries to ensure the vector is aligned with the target, even if that 00209 * isn't the closest solution position-wise. 00210 */ 00211 virtual bool solveLinkVector(float Ptgt_x, float Ptgt_y, float Ptgt_z, unsigned int link, float Peff_x, float Peff_y, float Peff_z) 00212 { return solveLinkVector(pack(Ptgt_x,Ptgt_y,Ptgt_z),link,pack(Peff_x,Peff_y,Peff_z)); } 00213 00214 //@} 00215 00216 00217 00218 //!@name Combining Postures 00219 00220 //! sets joints of this to all joints of @a pe which are not equal to unused (layers @a pe over this) stores into this 00221 virtual PostureEngine& setOverlay(const PostureEngine& pe); 00222 //! sets joints of this to all joints of @a pe which are not equal to unused (layers @a pe over this) returns new PostureEngine 00223 virtual PostureEngine createOverlay(const PostureEngine& pe) const; 00224 00225 //! sets joints of this which are equal to unused to @a pe, (layers this over @a pe) stores into this 00226 virtual PostureEngine& setUnderlay(const PostureEngine& pe); 00227 //! sets joints of this which are equal to unused to @a pe, (layers this over @a pe) returns new PostureEngine 00228 virtual PostureEngine createUnderlay(const PostureEngine& pe) const; 00229 00230 //! computes a weighted average of this vs. @a pe, @a w being the weight towards @a pe (so @a w==1 just copies @a pe) 00231 virtual PostureEngine& setAverage(const PostureEngine& pe,float w=0.5); 00232 //! computes a weighted average of this vs. @a pe, @a w being the weight towards @a pe (so @a w==1 just copies @a pe) 00233 virtual PostureEngine createAverage(const PostureEngine& pe,float w=0.5) const; 00234 00235 //! computes a weighted average of this vs. @a pe, using the weight values of the joints, storing the total weight in the result's weight value 00236 virtual PostureEngine& setCombine(const PostureEngine& pe); 00237 //! computes a weighted average of this vs. @a pe, using the weight values of the joints, storing the total weight in the result's weight value 00238 virtual PostureEngine createCombine(const PostureEngine& pe) const; 00239 00240 //! returns the sum squared error between this and pe's output values, but only between outputs which are both not unused 00241 /*! @todo create a version which does weighted summing? This treats weights as all or nothing */ 00242 virtual float diff(const PostureEngine& pe) const; 00243 00244 //! returns the average sum squared error between this and pe's output values for outputs which are both not unused 00245 /*! @todo create a version which does weighted summing? This treats weights as all or nothing */ 00246 virtual float avgdiff(const PostureEngine& pe) const; 00247 00248 //! returns the max error between this and pe's output values for outputs which are both not unused 00249 /*! @todo create a version which does weighted summing? This treats weights as all or nothing */ 00250 virtual float maxdiff(const PostureEngine& pe) const; 00251 00252 //@} 00253 00254 protected: 00255 //! enumeration of the different section types that may be used as section tags in verbose mode 00256 enum section_t { 00257 SECTION_METAINFO, //!< includes timestamp and framenumber 00258 SECTION_OUTPUTS, //!< entries corresponding to NumOutputs 00259 SECTION_BUTTONS, //!< entries corresponding to NumButtons 00260 SECTION_SENSORS, //!< entries corresponding to NumSensors 00261 SECTION_PIDDUTIES //!< entries corresponding to NumPIDJoints 00262 }; 00263 //! helper function for loadBuffer, called for each individual line 00264 virtual bool loadLine(unsigned int linenum, const std::map<std::string,section_t>& sectionMap, std::vector<std::string>& words, section_t& curSection, Capabilities*& caps, bool& filtered); 00265 //! helper function for loadLine, strips trailing '~'s from output names to provide backward compatability (note pass by reference, operates 'in-place' on @a word) 00266 /*! (originally, all output names were uniform length and used '~'s as padding... ugh.) */ 00267 void stripTildes(std::string& word) { 00268 word.erase(word.find_last_not_of('~')+1); // if n is npos, npos is -1U, so becomes 0... should be safe :) 00269 } 00270 00271 //all updates come from this posture engine's own state, not WorldState 00272 virtual void update(unsigned int c, unsigned int l); 00273 00274 //!the table of outputs' values and weights, can be accessed through setOutputCmd() and getOutputCmd() 00275 OutputCmd cmds[NumOutputs]; 00276 00277 bool saveFormatCondensed; //!< requests a condensed file format, smaller but less readable 00278 WorldState* loadSaveSensors; //!< If non-null, saves will include sensor readings from here, and loads will store any read sensors into here 00279 }; 00280 00281 /*! @file 00282 * @brief Describes PostureEngine, a base class for managing the values and weights of all the outputs 00283 * @author ejt (Creator) 00284 * 00285 * $Author: ejt $ 00286 * $Name: tekkotsu-4_0 $ 00287 * $Revision: 1.28 $ 00288 * $State: Exp $ 00289 * $Date: 2007/11/11 23:57:23 $ 00290 */ 00291 00292 #endif |
Tekkotsu v4.0 |
Generated Thu Nov 22 00:54:55 2007 by Doxygen 1.5.4 |