| Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
Kinematics.hGo to the documentation of this file.00001 //-*-c++-*- 00002 #ifndef INCLUDED_Kinematics_h_ 00003 #define INCLUDED_Kinematics_h_ 00004 00005 #include "Shared/RobotInfo.h" 00006 #include "Wireless/Socket.h" 00007 #include "Shared/newmat/newmat.h" 00008 #include <string> 00009 #include <vector> 00010 #include <ext/hash_map> 00011 00012 namespace ROBOOP { 00013 class Robot; 00014 class Config; 00015 } 00016 00017 //! Provides access to the mathematical functionality of the ROBOOP package using Tekkotsu data structures 00018 /*! 00019 * You should read the <a 00020 * href="http://www.tekkotsu.org/Kinematics.html">Kinematics 00021 * tutorial</a> to get a general understanding of the math involved 00022 * and diagrams for usage with supported robots. 00023 * 00024 * This class involves all aspects of the forward kinematics: 00025 * calculations concerning locations and orientations in space given 00026 * a known set of joint configurations. There is a global 00027 * instantiation of Kinematics named ::kine, which can be used to 00028 * perform these calculations regarding the joint positions currently 00029 * in ::state. 00030 * 00031 * To perform kinematics on a hypothetical set of joint values, 00032 * use PostureEngine or one of its subclasses. PostureEngine also 00033 * adds inverse kinematic functions, which will allow you to 00034 * determine joint angles in order to reach a given point. 00035 * 00036 * The underlying ROBOOP library does not currently handle branching 00037 * kinematic chains - in other words, each limb of the robot is a 00038 * separate ROBOOP::Robot as far as ROBOOP is concerned. This 00039 * Kinematics class interfaces the Tekkotsu array index approach to 00040 * referencing joints with ROBOOP's chain based hierarchy. 00041 * 00042 * Thus, wherever a reference frame index is requested, you can 00043 * simply supply one of the output indexes in the usual manner: 00044 * @code kine->jointToBase(HeadOffset+TiltOffset); @endcode 00045 * 00046 * However, there are also a number of points on the body which are 00047 * not joints, but should have their own reference frames, such as 00048 * the base frame, or the camera. These frames have their own 00049 * indices, listed in the robot info file for the model in question 00050 * (such as ERS7Info.h), with names ending in @c FrameOffset. 00051 * @code kine->jointToBase(CameraFrameOffset); @endcode 00052 * Note that for these non-joint-associated reference frames, the 00053 * link and joint frames are always identical, so you can use either 00054 * version of the corresponding functions. 00055 * 00056 * Since newmat matrix library is used by ROBOOP, you will need to 00057 * pass and receive information in newmat matrices. Kinematics class 00058 * provides static #pack and #unpack functions which can convert 00059 * individual x,y,z variables into a NEWMAT::ColumnVector, and vice 00060 * versa. However, for readability of your code and long-term ease 00061 * of use, we recommend embracing the newmat data structures directly 00062 * when appropriate. 00063 * @code 00064 * // Find the ray from the camera to whatever the near-field IR is hitting: 00065 * NEWMAT::Matrix T = kine->jointToJoint(NearIRFrameOffset,CameraFrameOffset); 00066 * NEWMAT::ColumnVector camera_ray = T*Kinematics::pack(0,0,state->sensors[NearIRDistOffset]); 00067 * float x,y; // x and y will be in the range -1 to 1 for resolution layer independence 00068 * config->vision.computePixel(camera_ray(1),camera_ray(2),camera_ray(3),x,y); 00069 * @endcode 00070 * 00071 * Finally, for each model we have created a database of "interest points" -- 00072 * locations of notable interest on the body of the robot. These may be of 00073 * use to people attempting to use the limbs to manipulate objects. 00074 * To access these interest points, call either #getLinkInterestPoint 00075 * or #getJointInterestPoint with the name of the interest point, obtained 00076 * from the <a href="http://www.tekkotsu.org/Kinematics.html">diagrams</a>. 00077 * 00078 * Note that you can pass a comma separated list of interest point names 00079 * and the result will be the midpoint of those interest points: 00080 * @code kine->getLinkInterestPoint(BaseFrameOffset,"LowerInnerFrontLFrShin,LowerOuterFrontLFrShin"); @endcode 00081 * 00082 * @see PostureEngine for inverse kinematics 00083 * 00084 * 00085 * 00086 * <a name="config_file_format"></a><h2>Configuration File Format</h2> 00087 * 00088 * The file is actually read by ROBOOP::Config, and thus the syntax 00089 * of the file is defined by that class. However, Tekkotsu will look 00090 * for some additional sections beyond what is expected by ROBOOP. 00091 * 00092 * In any give link section, a <tt>tekkotsu_output</tt> field may 00093 * appear, which specifies the index (aka offset) of the 00094 * corresponding joint in Tekkotsu, as defined by the model's Info.h 00095 * file (e.g. ERS7Info.h). Alternatively, <tt>tekkotsu_frame</tt> 00096 * may be specified, which should specify the offset of an abstract 00097 * reference frame, which does not correspond to any joint. 00098 * Typically this is used for things such as the camera, or 00099 * un-actuated joints, such as the spring-loaded ankles. 00100 * 00101 * Additionally, Kinematics will look for an custom 00102 * <tt>InterestPoints</tt> section, which should contain a 00103 * <tt>Length</tt> field for specifying the number of interest 00104 * points. Kinematics will then attempt to read 00105 * <tt>%InterestPoint</tt><i>N</i> for 1 through <i>Length</i>. 00106 * 00107 * Each <tt>%InterestPoint</tt><i>N</i> section should contain: 00108 * - <tt>name</tt> - (string) name which will be passed to get*InterestPoint() to retrieve this IP 00109 * - <tt>chain</tt> - (string) name of the chain the IP is in, must match one of the kinematic chains loaded from the file 00110 * - <tt>link</tt> - (unsigned int) the index of the link the IP is connected to 00111 * - <tt>x</tt> - (float) the x location of the point, in link-relative coordinates 00112 * - <tt>y</tt> - (float) the y location of the point, in link-relative coordinates 00113 * - <tt>z</tt> - (float) the z location of the point, in link-relative coordinates 00114 */ 00115 class Kinematics { 00116 public: 00117 //!Constructor, pass the full path to the kinematics configuration file 00118 Kinematics() 00119 #ifdef THREADSAFE_KINEMATICS 00120 : chains() 00121 #endif 00122 { 00123 init(); 00124 } 00125 //!Copy constructor, everything is either update-before-use or static, copy is normal init 00126 Kinematics(const Kinematics&) 00127 #ifdef THREADSAFE_KINEMATICS 00128 : chains() 00129 #endif 00130 { 00131 init(); 00132 } 00133 //!Assignment operator, everything is either update-before-use or static, assignment is no-op 00134 Kinematics& operator=(const Kinematics&) { return *this; } 00135 00136 //!Destructor 00137 virtual ~Kinematics(); 00138 00139 00140 00141 //! Returns a matrix for transforming from link frame @a j to base frame 00142 /*! @param[in] link the output offset, see class notes for values */ 00143 NEWMAT::ReturnMatrix linkToBase(unsigned int link); 00144 00145 //! Returns a matrix for transforming from joint frame @a j to base frame 00146 /*! @param[in] joint the output offset, see class notes for values */ 00147 NEWMAT::ReturnMatrix jointToBase(unsigned int joint); 00148 00149 //! Returns a matrix for transforming from the base frame to link @a j frame 00150 /*! @param[in] link the output offset, see class notes for values */ 00151 NEWMAT::ReturnMatrix baseToLink(unsigned int link); 00152 00153 //! Returns a matrix for transforming from the base frame to joint @a j frame 00154 /*! @param[in] joint the output offset, see class notes for values */ 00155 NEWMAT::ReturnMatrix baseToJoint(unsigned int joint); 00156 00157 //! Returns a matrix for transforming from link @a ij to link @a oj 00158 /*! @param[in] iL the output offset to convert from, see class notes for values 00159 * @param[in] oL the output offset to convert to, see class notes for values */ 00160 NEWMAT::ReturnMatrix linkToLink(unsigned int iL, unsigned int oL); 00161 00162 //! Returns a matrix for transforming from link frame @a ij to joint frame @a oj 00163 /*! @param[in] iL the output offset to convert from, see class notes for values 00164 * @param[in] oJ the output offset to convert to, see class notes for values */ 00165 NEWMAT::ReturnMatrix linkToJoint(unsigned int iL, unsigned int oJ); 00166 00167 //! Returns a matrix for transforming from joint frame @a ij to link frame @a oj 00168 /*! @param[in] iJ the output offset to convert from, see class notes for values 00169 * @param[in] oL the output offset to convert to, see class notes for values */ 00170 NEWMAT::ReturnMatrix jointToLink(unsigned int iJ, unsigned int oL); 00171 00172 //! Returns a matrix for transforming from joint @a ij to joint @a oj 00173 /*! @param[in] iJ the output offset to convert from, see class notes for values 00174 * @param[in] oJ the output offset to convert to, see class notes for values */ 00175 NEWMAT::ReturnMatrix jointToJoint(unsigned int iJ, unsigned int oJ); 00176 00177 00178 00179 //! Returns the location of a named point and the link it is attached to 00180 /*! @param[in] name the name of the interest point; varies by model, <a href="http://www.tekkotsu.org/Kinematics.html">see the diagrams</a> for your model. 00181 * @param[out] link on exit, offset of the link, or -1U if not found 00182 * @param[out] ip on exit, a homogeneous column vector of the requested point, relative to the link frame returned in @a j 00183 * 00184 * If @a name is not found, j will be -1 and ip will be all 0's. */ 00185 void getInterestPoint(const std::string& name, unsigned int& link, NEWMAT::Matrix& ip); 00186 00187 //! Returns the location of a named point, relative to any desired joint reference frame 00188 /*! @param[in] joint the desired joint reference frame to give results in 00189 * @param[in] name the name of the interest point; varies by model, <a href="http://www.tekkotsu.org/Kinematics.html">see the diagrams</a> for your model. 00190 * 00191 * You can pass a comma separated list of interest point names and the result will be the midpoint of those IPs */ 00192 NEWMAT::ReturnMatrix getJointInterestPoint(unsigned int joint, const std::string& name); 00193 00194 //! Returns the location of a named point, relative to any desired reference frame 00195 /*! @param[in] link the desired link reference frame to give results in 00196 * @param[in] name the name of the interest point; varies by model, <a href="http://www.tekkotsu.org/Kinematics.html">see the diagrams</a> for your model. 00197 * 00198 * You can pass a comma separated list of interest point names and the result will be the midpoint of those IPs */ 00199 NEWMAT::ReturnMatrix getLinkInterestPoint(unsigned int link, const std::string& name) { 00200 NEWMAT::ColumnVector p=jointToLink(link,link)*getJointInterestPoint(link,name); 00201 p.Release(); return p; 00202 } 00203 00204 00205 00206 //! Calculate the leg heights along a given "down" vector (0 is level with base frame) 00207 /*! This can be based on either the gravity vector from accelerometer readings, 00208 * or if that may be unreliable due to being in motion, you could do some basic 00209 * balance modeling and pass a predicted vector. This uses the interest point database 00210 * to find the lowest interest point for each leg 00211 * @note on Aibo platforms, if packing accelerometer readings, don't forget to negate the "left" accelerometer! */ 00212 void calcLegHeights(const NEWMAT::ColumnVector& down, float heights[NumLegs]); 00213 00214 //! Find the leg which is in least contact with ground 00215 /*! @see calcLegHeights() 00216 * @note on Aibo platforms, if packing accelerometer readings, don't forget to negate the "left" accelerometer! 00217 * @return index of leg which is highest in reference to gravity vector */ 00218 LegOrder_t findUnusedLeg(const NEWMAT::ColumnVector& down); 00219 00220 //! Find the ground plane by fitting a plane to the lowest 3 interest points 00221 /*! This function merely calls the other version of calculateGroundPlane with the current 00222 * gravity vector as the "down" vector. 00223 * @return vector of the form @f$p_1x + p_2y + p_3z = p_4@f$, relative to the base frame */ 00224 NEWMAT::ReturnMatrix calculateGroundPlane(); 00225 00226 //! Find the ground plane by fitting a plane to the lowest 3 interest points 00227 /*! @note on Aibo platforms, if packing accelerometer readings, don't forget to negate the "left" accelerometer! 00228 * @return vector of the form @f$p_1x + p_2y + p_3z = p_4@f$, relative to the base frame */ 00229 NEWMAT::ReturnMatrix calculateGroundPlane(const NEWMAT::ColumnVector& down); 00230 00231 //! Find the point of intersection between a ray and a plane 00232 /*! @param j is the link number the ray is relative to 00233 * @param r_j is the line through the origin, in homogeneous coordinates 00234 * @param b is the link number the plane is relative to (probably BaseFrameOffset) 00235 * @param p_b represents the plane to be intersected 00236 * @param f is the link number the results should be relative to 00237 * 00238 * @a p_b should be of the form @f$p_1x + p_2y + p_3z = p_4@f$ 00239 * @return homogeneous coordinate of intersection (may be infinity) */ 00240 NEWMAT::ReturnMatrix projectToPlane(unsigned int j, const NEWMAT::ColumnVector& r_j, 00241 unsigned int b, const NEWMAT::ColumnVector& p_b, 00242 unsigned int f); 00243 00244 00245 //! A simple utility function, converts x,y,z,h to a NEWMAT::ColumnVector 00246 /*! @param[in] x the value for the first row 00247 * @param[in] y the value for the second row 00248 * @param[in] z the value for the third row 00249 * @param[in] h the value for the fourth row (defaults to 1 if not specified) 00250 * @return @f$ \left[\begin{array}{c} x\\y\\z\\h\\ \end{array}\right] @f$ */ 00251 static NEWMAT::ReturnMatrix pack(float x, float y, float z, float h=1) { 00252 NEWMAT::ColumnVector m(4); 00253 m(1)=x; m(2)=y; m(3)=z; m(4)=h; 00254 m.Release(); return m; 00255 } 00256 //! A simple utility function, pulls the first 3 rows of the first column, divides each by the fourth row, and stores into ox, oy, and oz 00257 /*! @param[in] m the matrix to unpack (only uses first column) 00258 * @param[out] ox set to the first row of the first column of @a m, divided by fourth row 00259 * @param[out] oy set to the second row of the first column of @a m, divided by fourth row 00260 * @param[out] oz set to the third row of the first column of @a m, divided by fourth row */ 00261 static void unpack(NEWMAT::Matrix m, float& ox, float& oy, float& oz) { 00262 ox=m(1,1)/m(4,1); oy=m(2,1)/m(4,1); oz=m(3,1)/m(4,1); 00263 } 00264 //! A simple utility function, pulls the first 4 rows of the first column, stores into ox, oy, oz, oh 00265 /*! @param[in] m the matrix to unpack (only uses first column) 00266 * @param[out] ox set to the first row of the first column of @a m 00267 * @param[out] oy set to the second row of the first column of @a m 00268 * @param[out] oz set to the third row of the first column of @a m 00269 * @param[out] oh set to the fourth row of the first column of @a m */ 00270 static void unpack(NEWMAT::Matrix m, float& ox, float& oy, float& oz, float& oh) { 00271 ox=m(1,1); oy=m(2,1); oz=m(3,1); oh=m(4,1); 00272 } 00273 00274 //! returns the global ROBOOP::Config object which Kinematics classes initialize themselves from (#roconfig) 00275 static ROBOOP::Config * getConfig() { return roconfig; } 00276 00277 protected: 00278 //! Called by constructors to do basic setup - first call will read Config::motion_config::kinematics from disk, future initializes reuse static roconfig 00279 void init(); 00280 00281 //! initializes static variables -- only call if not #staticsInited 00282 static void initStatics(); 00283 00284 //! checks that statics have been initialized, and calls initStatics if they are missing 00285 static void checkStatics() { if(!staticsInited) initStatics(); } 00286 00287 //! called by init to allocate/initialize each of #chains 00288 static ROBOOP::Robot* newChain(unsigned int chainIdx); 00289 00290 //! Returns the location of a named point, relative to the link it is attached to 00291 /*! @param[in] name the name of the interest point; varies by model, <a href="http://www.tekkotsu.org/Kinematics.html">see the diagrams</a> for your model. 00292 * @param[out] c on exit, chain index the IP is on 00293 * @param[out] l on exit, link index the IP is on 00294 * @param[out] ip on exit, a homogeneous column vector of the requested point 00295 * 00296 * If @a name is not found, @a c and @a l will be -1 and @a ip will be all 0's. 00297 * This internal version of the function allows us to use @a c and @a l, ourselves, 00298 * but users will probably want to use the getInterestPoint(name,j,ip) version */ 00299 void getInterestPoint(const std::string& name, unsigned int& c, unsigned int& l, NEWMAT::Matrix& ip); 00300 00301 //! Called at the beginning of each function which accesses ROBOOP computations - should make sure the ROBOOP structures are up to date with Tekkotsu structures 00302 /*! This class will pull current values from WorldState, but it is expected 00303 * that subclasses (i.e. PostureEngine) will want to provide their own joint values. 00304 * Updates from link 1 through link @a l. 00305 * @param[in] c the chain to update 00306 * @param[in] l the last link to update (later links in the chain are left untouched) */ 00307 virtual void update(unsigned int c, unsigned int l); 00308 00309 //! converts a Tekkotsu output index to a chain and link 00310 /*! @param[in] tkout the tekkotsu index to lookup 00311 * @param[out] c set to the chain index that @a tkout is in 00312 * @param[out] l set to the link in @a c corresponding to @a tkout */ 00313 bool lookup(unsigned int tkout, unsigned int& c, unsigned int& l) { 00314 if(tkout>=NumReferenceFrames) { 00315 serr->printf("ERROR Kinematics: illegal link %d\n",l); 00316 return false; 00317 } 00318 if(jointMaps[tkout].chain>=chains.size()) { 00319 serr->printf("ERROR Kinematics: no chain available for link %d\n",l); 00320 return false; 00321 } 00322 c=jointMaps[tkout].chain; 00323 l=jointMaps[tkout].link; 00324 return true; 00325 } 00326 00327 //! initially false, set to true after first Kinematics is initialized 00328 static bool staticsInited; 00329 00330 #ifdef THREADSAFE_KINEMATICS 00331 //! A separate ROBOOP::Robot instantiation for each chain since ROBOOP package doesn't support branching chains (which would be rather difficult to implement well) 00332 std::vector<ROBOOP::Robot*> chains; 00333 #else 00334 //! A separate ROBOOP::Robot instantiation for each chain since ROBOOP package doesn't support branching chains (which would be rather difficult to implement well) 00335 /*! static allocation solves problems with shared memory regions, but becomes thread-UNsafe... */ 00336 static std::vector<ROBOOP::Robot*> chains; 00337 #endif 00338 00339 //! holds mapping for each chain's links back to the tekkotsu outputs and reference frames they represent 00340 static std::vector< std::vector<unsigned int> > chainMaps; 00341 00342 //! Allows mapping from tekkotsu output index to chain and link indicies 00343 struct JointMap { 00344 JointMap() : chain(-1U), link(-1U) {} //!< constructor 00345 JointMap(unsigned int c, unsigned int l) : chain(c), link(l) {} //!< constructor 00346 unsigned int chain; //!< the chain index 00347 unsigned int link; //!< the link index 00348 }; 00349 //! holds the position and attached link of a given interest point 00350 struct InterestPoint { 00351 InterestPoint() : x(), y(), z(), chain(), link() {} //!< constructor 00352 InterestPoint(float x_, float y_, float z_, unsigned int chain_, unsigned int link_) 00353 : x(x_), y(y_), z(z_), chain(chain_), link(link_) {} //!< constructor 00354 float x; //!< x value 00355 float y; //!< y value 00356 float z; //!< z value 00357 unsigned int chain; //!< chain containing @a link 00358 int link; //!< link in @a chain 00359 }; 00360 00361 //! holds mapping from tekkotsu output index to chain and link indicies 00362 static JointMap jointMaps[NumReferenceFrames]; 00363 00364 //! cache of the configuration of the robot for rapid initialization (so we don't have to re-read from disk) 00365 static ROBOOP::Config * roconfig; 00366 //! allows us to use the STL hash_map with strings 00367 struct hashstring { 00368 //! hashes a string by multiplying current total by 5, add new character 00369 /*! not my idea, this is what the STL library does for char*, i've just reimplemented it for strings */ 00370 size_t operator()(const string& s) const { 00371 unsigned long h=0; 00372 for(string::size_type x=s.size(); x!=0; x--) 00373 h=h*5+s[x]; 00374 return (size_t)h; 00375 } 00376 }; 00377 //! we'll be using the hash_map to store named interest points 00378 typedef __gnu_cxx::hash_map<const string,InterestPoint,hashstring> InterestPointMap; 00379 //! these interest points are shared by all Kinematics classes (i.e. all PostureEngines) 00380 /*! this is to reduce initialization time, but does mean one robot can't do 00381 * kinematic calculations regarding a different model robot... */ 00382 static InterestPointMap * ips; 00383 }; 00384 00385 //! a global instance of Kinematics, joint values reference those of WorldState so users can easily query the current spatial locations of joints 00386 extern Kinematics * kine; 00387 00388 /*! @file 00389 * @brief Describes Kinematics, which provides access to the mathematical functionality of the roboop package using Tekkotsu data structures 00390 * @author ejt (Creator) 00391 * 00392 * $Author: ejt $ 00393 * $Name: tekkotsu-3_0 $ 00394 * $Revision: 1.36 $ 00395 * $State: Exp $ 00396 * $Date: 2006/09/16 17:32:39 $ 00397 */ 00398 00399 #endif |
|
Tekkotsu v3.0 |
Generated Wed Oct 4 00:03:43 2006 by Doxygen 1.4.7 |