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 "Shared/fmat.h" 00007 #include "Shared/Measures.h" 00008 #include "Motion/KinematicJoint.h" 00009 00010 #include <string> 00011 #include <vector> 00012 00013 class VisionObjectEvent; 00014 00015 //! Forward and inverse kinematics calculations using Tekkotsu output indices. 00016 /*! 00017 * You should read the <a 00018 * href="http://www.tekkotsu.org/Kinematics.html">Kinematics 00019 * tutorial</a> to get a general understanding of the math involved 00020 * and diagrams for usage with supported robots. 00021 * 00022 * This class involves all aspects of the forward kinematics: 00023 * calculations concerning locations and orientations in space given 00024 * a known set of joint configurations. There is a global 00025 * instantiation of Kinematics named ::kine, which can be used to 00026 * perform these calculations regarding the joint positions currently 00027 * in ::state. 00028 * 00029 * To perform kinematics on a hypothetical set of joint values, 00030 * use PostureEngine or one of its subclasses. PostureEngine also 00031 * adds inverse kinematic functions, which will allow you to 00032 * determine joint angles in order to reach a given point. 00033 * 00034 * Wherever a reference frame index is requested, you can 00035 * simply supply one of the output indexes in the usual manner: 00036 * @code kine->linkToBase(HeadOffset+TiltOffset); @endcode 00037 * 00038 * However, there are also a number of points on the body which are 00039 * not joints, but should have their own reference frames, such as 00040 * the base frame, or the camera. These frames have their own 00041 * indices, listed in the robot info file for the model in question 00042 * (such as ERS7Info.h), with names ending in @c FrameOffset. 00043 * @code kine->linkToBase(CameraFrameOffset); @endcode 00044 * 00045 * Example code: 00046 * @code 00047 * // Find the ray from the camera to whatever the near-field IR is hitting: 00048 * fmat::Transform T = kine->linkToLink(NearIRFrameOffset,CameraFrameOffset); 00049 * fmat::Column<3> camera_ray = T*fmat::pack(0,0,state->sensors[NearIRDistOffset]); 00050 * float x; // x will be in the range ±1 for resolution layer independence 00051 * float y; // y ranges ±y_dim/x_dim (i.e. ±1/aspectRatio) 00052 * config->vision.computePixel(camera_ray[0],camera_ray[1],camera_ray[2],x,y); 00053 * @endcode 00054 * 00055 * Finally, for each model we have created a database of "interest points" -- 00056 * locations of notable interest on the body of the robot. These may be of 00057 * use to people attempting to use the limbs to manipulate objects. 00058 * To access these interest points, call #getInterestPoint 00059 * with the name of the interest point, obtained 00060 * from the <a href="http://www.tekkotsu.org/Kinematics.html">diagrams</a>. 00061 * 00062 * Note that you can pass a comma separated list of interest point names 00063 * and the result will be the midpoint of those interest points: 00064 * @code kine->getInterestPoint(BaseFrameOffset,"LowerInnerFrontLFrShin,LowerOuterFrontLFrShin"); @endcode 00065 * 00066 * @see PostureEngine for inverse kinematics 00067 */ 00068 class Kinematics { 00069 public: 00070 //!Constructor, pass the full path to the kinematics configuration file 00071 Kinematics() : root(), lastUpdateTime(0) 00072 { 00073 init(); 00074 } 00075 //!Copy constructor, everything is either update-before-use or static, copy is normal init 00076 Kinematics(const Kinematics& k) : root(k.root), lastUpdateTime(0) 00077 { 00078 for(unsigned int i=0; i<NumReferenceFrames; ++i) 00079 jointMaps[i]=NULL; 00080 root.buildChildMap(jointMaps,0,NumReferenceFrames); 00081 } 00082 //!Assignment operator, everything is either update-before-use or static, assignment is no-op 00083 Kinematics& operator=(const Kinematics& k) { 00084 root=k.root; 00085 for(unsigned int i=0; i<NumReferenceFrames; ++i) 00086 jointMaps[i]=NULL; 00087 root.buildChildMap(jointMaps,0,NumReferenceFrames); 00088 return *this; 00089 } 00090 00091 //!Destructor 00092 virtual ~Kinematics(); 00093 00094 //! Returns a pointer to the root of the kinematic tree 00095 const KinematicJoint* getRoot() { return &root; } 00096 00097 //! returns the KinematicJoint structure for the specified Tekkotsu output or reference frame offset 00098 const KinematicJoint* getKinematicJoint(unsigned int idx) const { update(); return jointMaps[idx]; } 00099 00100 fmat::Column<3> getPosition(unsigned int idx) const { 00101 if(jointMaps[idx]==NULL) 00102 throw std::runtime_error("Kinematics::getPosition: kinematics unspecified for requested offset"); 00103 update(); 00104 return jointMaps[idx]->getFullT().translation(); 00105 } 00106 00107 //! Returns a matrix for transforming from link frame @a j to base frame 00108 /*! @param[in] link the output offset, see class notes for values */ 00109 fmat::Transform linkToBase(unsigned int link) { 00110 if(jointMaps[link]==NULL) 00111 throw std::runtime_error("Kinematics::linkToBase: kinematics unspecified for requested offset"); 00112 update(); 00113 return jointMaps[link]->getFullT(); 00114 } 00115 00116 //! Returns a matrix for transforming from the base frame to link @a j frame 00117 /*! @param[in] link the output offset, see class notes for values */ 00118 fmat::Transform baseToLink(unsigned int link) { return linkToBase(link).inverse(); } 00119 00120 //! Returns a matrix for transforming from link @a iL to link @a oL 00121 /*! @param[in] iL the output offset to convert from, see class notes for values 00122 * @param[in] oL the output offset to convert to, see class notes for values */ 00123 fmat::Transform linkToLink(unsigned int iL, unsigned int oL) { 00124 if(jointMaps[iL]==NULL || jointMaps[oL]==NULL) 00125 throw std::runtime_error("Kinematics::linkToLink: kinematics unspecified for requested offset"); 00126 update(); 00127 return jointMaps[iL]->getT(*jointMaps[oL]); 00128 } 00129 00130 //! returns a transformation to account for standing pose, where the origin of the "local" space is the projection of the base frame origin along the ground plane normal 00131 fmat::Transform baseToLocal() { return baseToLocal(calculateGroundPlane()); } 00132 00133 //! returns a transformation to account for standing pose, where the origin of the "local" space is the projection of the base frame origin along the ground plane normal 00134 fmat::Transform baseToLocal(const PlaneEquation& plane); 00135 00136 //! returns a transformation to account for standing pose, where the origin of the "local" space is the projection of the base frame origin along the ground plane normal 00137 fmat::Transform localToBase() { return baseToLocal(calculateGroundPlane()).inverse(); } 00138 00139 //! returns a transformation to account for standing pose, where the origin of the "local" space is the projection of the base frame origin along the ground plane normal 00140 fmat::Transform localToBase(const PlaneEquation& plane) { return localToBase(plane).inverse(); } 00141 00142 00143 //! Returns the location of a named point and the link it is attached to 00144 /*! @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. 00145 * @param[out] link on exit, offset of the link, or -1U if not found 00146 * @param[out] ip on exit, the requested point, relative to the link frame returned in @a link 00147 * @param[in] convertToJoint if true and @a name is relative to a "pure" reference frame (i.e. NumOutputs <= link < NumReferenceFrames), then @a link and @a ip will be transformed to the parent joint (if it exists) 00148 * 00149 * If @a name is not found, link will be -1 and ip will be all 0's. */ 00150 void getInterestPoint(const std::string& name, unsigned int& link, fmat::Column<3>& ip, bool convertToJoint=false); 00151 00152 //! Returns the location of a named point, relative to any desired reference frame 00153 /*! @param[in] link the desired link reference frame to give results in 00154 * @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. 00155 * 00156 * You can pass a comma separated list of interest point names and the result will be the midpoint of those IPs. 00157 * 00158 * If an interest point is not found, a std::runtime_error is thrown. */ 00159 fmat::Column<3> getInterestPoint(unsigned int link, const std::string& name); 00160 00161 00162 00163 #ifdef TGT_HAS_LEGS 00164 //! Calculate the leg heights along a given "down" vector (0 is level with base frame) 00165 /*! This can be based on either the gravity vector from accelerometer readings, 00166 * or if that may be unreliable due to being in motion, you could do some basic 00167 * balance modeling and pass a predicted vector. This uses the interest point database 00168 * to find the lowest interest point for each leg 00169 * @note on Aibo platforms, if packing accelerometer readings, don't forget to negate the "left" accelerometer! */ 00170 void calcLegHeights(const fmat::Column<3>& down, float heights[NumLegs]); 00171 00172 //! Find the leg which is in least contact with ground 00173 /*! @see calcLegHeights() 00174 * @note on Aibo platforms, if packing accelerometer readings, don't forget to negate the "left" accelerometer! 00175 * @return index of leg which is highest in reference to gravity vector */ 00176 LegOrder_t findUnusedLeg(const fmat::Column<3>& down); 00177 #endif 00178 00179 //! Find the ground plane by fitting a plane to the lowest 3 interest points 00180 /*! This function merely calls the other version of calculateGroundPlane with the current 00181 * gravity vector as the "down" vector. 00182 * @return vector of the form @f$p_1x + p_2y + p_3z = p_4@f$, relative to the base frame */ 00183 PlaneEquation calculateGroundPlane(); 00184 00185 //! Find the ground plane by fitting a plane to the lowest 3 interest points 00186 /*! @note on Aibo platforms, if packing accelerometer readings, don't forget to negate the "left" accelerometer! 00187 * @return vector of the form @f$p_1x + p_2y + p_3z = p_4@f$, relative to the base frame */ 00188 PlaneEquation calculateGroundPlane(const fmat::Column<3>& down); 00189 00190 //! Find the point of intersection between a ray and a plane 00191 /*! @param j is the link number the ray is relative to 00192 * @param r_j is the ray through the origin of link @a j 00193 * @param b is the link number the plane is relative to (probably BaseFrameOffset) 00194 * @param p_b represents the plane to be intersected 00195 * @param f is the link number the results should be relative to 00196 * @param objCentroidHeight the height of the object's centroid above the ground 00197 * 00198 * @a p_b should be of the form @f$p_1x + p_2y + p_3z = p_4@f$ 00199 * @return homogeneous coordinate of intersection (may be infinity) 00200 * 00201 * For projecting to the ground plane, one of the specialized projectToGround() 00202 * functions may be more convenient. */ 00203 fmat::Column<4> projectToPlane(unsigned int j, const fmat::Column<3>& r_j, 00204 unsigned int b, const PlaneEquation& p_b, 00205 unsigned int f, float objCentroidHeight=0); 00206 00207 //! Find the location of an object on the ground from an arbitrary ray @a r_j in reference frame @a j (probably CameraFrameOffset) 00208 /*! @param visObj the vision object to project 00209 * @param objCentroidHeight the height of the object's centroid above the ground 00210 * Uses the default calculateGroundPlane(), otherwise call projectToPlane() to specify a custom plane. */ 00211 fmat::Column<4> projectToGround(unsigned int j, const fmat::Column<3>& r_j, float objCentroidHeight=0) { 00212 return projectToPlane(j,r_j, BaseFrameOffset, calculateGroundPlane(), BaseFrameOffset,objCentroidHeight); 00213 } 00214 00215 //! Find the location of an object on the ground (the easy way from a vision object event (i.e. EventBase::visObjEGID)) 00216 /*! @param visObj the vision object to project 00217 * @param objCentroidHeight the height of the object's centroid above the ground 00218 * Uses the default calculateGroundPlane(), otherwise call the other projectToGround() to specify a custom plane. */ 00219 fmat::Column<4> projectToGround(const VisionObjectEvent& visObj, float objCentroidHeight=0) { 00220 return projectToGround(visObj, calculateGroundPlane(), objCentroidHeight); 00221 } 00222 00223 //! Find the location of an object on the ground with a custom ground plane specification 00224 /*! @a gndPlane must be specified relative to the base frame, in 00225 * the form @f$p_1x + p_2y + p_3z = p_4@f$, 00226 * @see projectToPlane() for more control over projection and results */ 00227 fmat::Column<4> projectToGround(const VisionObjectEvent& visObj, const PlaneEquation& gndPlane, float objCentroidHeight=0); 00228 00229 //! A simple utility function, converts x,y,z,h to a fmat::Column<3> 00230 /*! @param[in] x the value for the first element 00231 * @param[in] y the value for the second element 00232 * @param[in] z the value for the third element 00233 * @return @f$ \left[\begin{array}{c} x\\y\\z\\ \end{array}\right] @f$ */ 00234 static fmat::Column<3> pack(float x, float y, float z) { return fmat::pack(x,y,z); } 00235 00236 //! A simple utility function, converts x,y,z,h to a fmat::Column<4> 00237 /*! @param[in] x the value for the first element 00238 * @param[in] y the value for the second element 00239 * @param[in] z the value for the third element 00240 * @param[in] h the value for the fourth element 00241 * @return @f$ \left[\begin{array}{c} x\\y\\z\\h\\ \end{array}\right] @f$ */ 00242 static fmat::Column<4> pack(float x, float y, float z, float h) { return fmat::pack(x,y,z,h); } 00243 00244 //! 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 00245 /*! @param[in] m the column to unpack from, applying scaling factor 00246 * @param[out] ox set to the first element of @a m, divided by fourth element 00247 * @param[out] oy set to the second element of @a m, divided by fourth element 00248 * @param[out] oz set to the third row element of @a m, divided by fourth element */ 00249 static void unpack(const fmat::SubVector<4, const float>& m, float& ox, float& oy, float& oz) { 00250 ox=m[0]/m[3]; oy=m[1]/m[3]; oz=m[2]/m[3]; 00251 } 00252 00253 protected: 00254 //! Called by constructors to do basic setup - first call will read Config::motion_config::kinematics from disk, future initializes reuse static roconfig 00255 void init(); 00256 00257 //! initializes static variables -- only call if not #staticsInited 00258 static void initStatics(); 00259 00260 //! checks that statics have been initialized, and calls initStatics if they are missing 00261 static void checkStatics() { if(!staticsInited) initStatics(); } 00262 00263 public: 00264 //! refresh the joint settings in #root from WorldState::outputs 00265 virtual void update() const; 00266 00267 //! holds the position and attached link of a given interest point 00268 struct InterestPoint { 00269 InterestPoint() : p(), output(-1U) {} //!< constructor 00270 InterestPoint(float x, float y, float z, unsigned int output_) 00271 : p(fmat::pack(x,y,z)), output(output_) {} //!< constructor 00272 fmat::Column<3> p; //!< position 00273 unsigned int output; //!< output offset for link that this is relative to 00274 }; 00275 00276 protected: 00277 //! the root of the kinematic tree 00278 KinematicJoint root; 00279 00280 //! determine if the joints are up to date (compare to WorldState::lastSensorUpdateTime) 00281 mutable unsigned int lastUpdateTime; 00282 00283 //! holds mapping from tekkotsu output index to chain and link indicies 00284 KinematicJoint* jointMaps[NumReferenceFrames]; 00285 00286 //! initially false, set to true after first Kinematics is initialized 00287 static bool staticsInited; 00288 00289 //! we'll be using the hash_map to store named interest points 00290 typedef std::map<std::string,InterestPoint> InterestPointMap; 00291 //! these interest points are shared by all Kinematics classes (i.e. all PostureEngines) 00292 /*! this is to reduce initialization time, but does mean one robot can't do 00293 * interest point calculations regarding a different model robot... */ 00294 static InterestPointMap ips; 00295 }; 00296 00297 //! a global instance of Kinematics, joint values reference those of WorldState so users can easily query the current spatial locations of joints 00298 extern Kinematics * kine; 00299 00300 /*! @file 00301 * @brief Describes Kinematics, which provides access to the mathematical functionality of the roboop package using Tekkotsu data structures 00302 * @author ejt (Creator) 00303 */ 00304 00305 #endif |
Tekkotsu v5.1CVS |
Generated Mon May 9 04:58:42 2016 by Doxygen 1.6.3 |