Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Kinematics.h

Go 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