Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

robot/sim/SimulatedSerialManipulator.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)2002 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018   $Id: SimulatedSerialManipulator.cpp 1032 2004-02-11 20:47:42Z jungd $
00019   $Revision: 1.34 $
00020   $Date: 2004-02-11 15:47:42 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <robot/sim/SimulatedSerialManipulator>
00026 
00027 #include <base/Vector3>
00028 #include <base/Orient>
00029 #include <base/Transform>
00030 #include <base/Externalizer>
00031 
00032 #include <gfx/Color3>
00033 #include <gfx/Line3>
00034 #include <gfx/Segment3>
00035 #include <physics/BoundingBox>
00036 #include <physics/Material>
00037 #include <physics/Box>
00038 #include <physics/Sphere>
00039 #include <physics/Capsule>
00040 #include <physics/Solid>
00041 #include <physics/ConstraintGroup>
00042 #include <physics/Joint>
00043 #include <physics/HingeJoint>
00044 #include <physics/SliderJoint>
00045 #include <physics/Motor>
00046 #include <physics/CollisionCuller>
00047 #include <physics/CollisionDetector>
00048 #include <physics/CollisionState>
00049 #include <physics/NullCollisionResponseHandler>
00050 #include <physics/SpatialTransform>
00051 
00052 #include <physics/VisualDebugUtil>
00053 
00054 #include <robot/KinematicChain>
00055 
00056 
00057 using robot::sim::SimulatedSerialManipulator;
00058 
00059 using base::Point3;
00060 using base::Orient;
00061 using base::Dimension3;
00062 using base::Transform;
00063 using gfx::Line3;
00064 using gfx::Segment3;
00065 using gfx::Color4;
00066 using physics::BoundingBox;
00067 using physics::Collidable;
00068 using physics::CollidableBody;
00069 using physics::CollidableGroup;
00070 using physics::CollisionState;
00071 using physics::CollisionCuller;
00072 using physics::CollisionDetector;
00073 using physics::CollisionResponseHandler;
00074 using physics::NullCollisionResponseHandler;
00075 using physics::Shape;
00076 using physics::Box;
00077 using physics::Sphere;
00078 using physics::Capsule;
00079 using physics::Material;
00080 using physics::Solid;
00081 using physics::SpatialGroup;
00082 using physics::SpatialTransform;
00083 using physics::ConstraintGroup;
00084 using physics::Joint;
00085 using physics::HingeJoint;
00086 using physics::SliderJoint;
00087 using physics::Motor;
00088 
00089 using physics::VisualDebugUtil;
00090 
00091 using robot::KinematicChain;
00092 using robot::sim::SimulatedManipulatorDescription;
00093 using robot::sim::SimulatedKinematicChain;
00094 using robot::sim::SimulatedTool;
00095 
00096 //!!!
00097 #include <physics/ODESolidConnectedCollidableBody>
00098 using physics::SolidConnectedCollidableBody;
00099 using physics::ODESolidConnectedCollidableBody;
00100 
00101 
00102 #include <ode/ode.h>
00103 #include <ode/rotation.h>
00104 
00105 
00106 SimulatedSerialManipulator::SimulatedSerialManipulator(bool dynamic)
00107   : SimulatedKinematicChain(dynamic), proximityDistance(0.05), proximityAngle(Math::degToRad(3)), toolGrasped(false)
00108 {
00109 }
00110 
00111 SimulatedSerialManipulator::SimulatedSerialManipulator(ref<physics::SolidSystem> solidSystem, bool dynamic)
00112   : SimulatedKinematicChain(solidSystem, dynamic), proximityDistance(0.05), proximityAngle(Math::degToRad(3)), toolGrasped(false)
00113 {   
00114 }
00115 
00116 SimulatedSerialManipulator::SimulatedSerialManipulator(ref<const robot::ManipulatorDescription> manipulatorDescription, ref<physics::SolidSystem> solidSystem, bool dynamic)
00117   : SimulatedKinematicChain(solidSystem,dynamic),
00118     proximityDistance(0.05), proximityAngle(Math::degToRad(3)), toolGrasped(false)
00119 {
00120   if (instanceof(*manipulatorDescription, const SimulatedManipulatorDescription))
00121     manipulatorDescr = narrow_ref<const SimulatedManipulatorDescription>(manipulatorDescription);
00122   else
00123     manipulatorDescr = ref<SimulatedManipulatorDescription>(NewObj SimulatedManipulatorDescription(*manipulatorDescription));
00124 
00125   chain = manipulatorDescr->getKinematicChain();
00126   q.reset(manipulatorDescr->initialConfiguration());
00127 }
00128 
00129 
00130 
00131 bool SimulatedSerialManipulator::formatSupported(String format, Real version, ExternalizationType type) const
00132 {
00133   return false;
00134 }
00135 
00136 void SimulatedSerialManipulator::externalize(base::Externalizer& e, String format, Real version)
00137 {
00138   if (format == "") format = "xml";
00139 
00140   if (!formatSupported(format,version,e.ioType()))
00141     throw std::invalid_argument(Exception(String("format ")+format+" v"+base::realToString(version)+" unsupported"));
00142 
00143   // just externalize the description
00144   manipulatorDescr->externalize(e,format,version);
00145 }
00146 
00147 
00148 
00149 void SimulatedSerialManipulator::setJointForce(Int j, Real f)
00150 {
00151   Assertm((j>=1)&&(j<=chain.dof()), "joint index in range");
00152   
00153   if (!dynamic) return;
00154   
00155   ref<Motor> motor(joints[j-1]->getMotor(1));
00156   motor->setTargetVel( (f>0)?10:-10 ); 
00157   motor->setMaxForce(f);
00158 }
00159 
00160 void SimulatedSerialManipulator::setJointVel(Int j, Real v, Real maxForce)
00161 {
00162   Assertm((j>=1)&&(j<=chain.dof()), "joint index in range");
00163 
00164   if (!dynamic) return;
00165   
00166   ref<Motor> motor(joints[j-1]->getMotor(1));
00167   motor->setTargetVel(v); 
00168   motor->setMaxForce(maxForce);
00169 }
00170 
00171 
00172 void SimulatedSerialManipulator::setJointPos(Int j, Real p)
00173 {
00174   Assertm((j>=1)&&(j<=chain.dof()), "joint index in range");
00175 
00176   q[j-1] = p;
00177   
00178   //... actually move the links
00179   //hack!!! (expensive - only need to update the joint in question)
00180 
00181   Transform baseTransform(manipulatorDescr->getBaseTransform());
00182   mountConfiguration = inverse(baseTransform)*linkGroups[0]->getConfiguration();
00183   
00184   TransformInfo transformInfo( computeLinkTransforms(mountConfiguration, q) );
00185   positionLinks(transformInfo);
00186     
00187   // re-position the tool at the ee-end
00188   if (toolGrasped) {
00189     Transform eeConfig( getEEPosition(), getEEOrientation() );
00190     proximityTool->setConfiguration( eeConfig );
00191   }
00192   //hack!!!
00193 }
00194 
00195   
00196 Real SimulatedSerialManipulator::getJointPos(Int j) const
00197 {
00198   Assertm((j>=1)&&(j<=chain.dof()), "joint index in range");
00199 
00200   if (dynamic) { // get joint pos from physics::Joint
00201     
00202     // NB: physics::Joints have their 0 pos at the position/orientation
00203     //  at which the two bodies were initially attached.  That was
00204     //  computed from the manipulator joint parameter home position.
00205   
00206     if (chain[j-1].type() == KinematicChain::Link::Revolute) {
00207   
00208       ref<HingeJoint> hinge(narrow_ref<HingeJoint>(joints[j-1]));
00209 
00210       q[j-1] = hinge->getAngle();
00211   
00212     } else { // prismatic
00213       ref<SliderJoint> slider(narrow_ref<SliderJoint>(joints[j-1]));
00214       q[j-1] = slider->getPosition();
00215     }
00216     
00217   } else { // static
00218     /*
00219     Transform relConfig = inverse( links[j]->getConfiguration() )*links[j-1]->getConfiguration();
00220     Real rotAboutZ = Math::normalizeAngle(relConfig.getRotation().getVector(Orient::EulerZYX)[0]);
00221     Debugln(Tmp,"rotAboutZ=" << rotAboutZ);
00222     return rotAboutZ;
00223     */
00224   }
00225 
00226   return q[j-1];
00227 
00228 }
00229 
00230 
00231 Real SimulatedSerialManipulator::getJointVel(Int j) const
00232 {
00233   Assertm((j>=1)&&(j<=chain.dof()), "joint index in range");
00234 
00235   if (!dynamic) return 0;
00236 
00237   if (chain[j-1].type() == KinematicChain::Link::Revolute) {
00238 
00239     ref<HingeJoint> hinge(narrow_ref<HingeJoint>(joints[j-1]));
00240     return hinge->getAngleRate();
00241   }
00242   else { // prismatic
00243 
00244     ref<SliderJoint> slider(narrow_ref<SliderJoint>(joints[j-1]));
00245     return slider->getPositionRate();
00246   }
00247 
00248 }
00249 
00250 
00251 
00252 
00253 
00254 
00255 array<base::Dimension3> SimulatedSerialManipulator::computeLinkDimensions(const array<Real>& linkRadii) 
00256 {
00257   // call super and then add the dim of the base link as link 0
00258   array<Dimension3> dim( SimulatedKinematicChain::computeLinkDimensions(linkRadii) );
00259   
00260   Matrix4 baseTransform(manipulatorDescr->getBaseTransform());
00261   Real len = baseTransform.column(4).toVector3().length();
00262 
00263   linkLengths[0] = len;
00264     
00265   Real zl=len*0.98;
00266   if (Math::equals(len,0)) zl=0.05; // some links are zero length so make them very small instead
00267   
00268   Real yz;
00269   if (linkRadii.size() >= 1)
00270     yz = linkRadii[0]*2.0;
00271   else
00272     yz = Math::maximum(0.05,zl*0.14); // make x&y-dims smaller than length (z-dim)
00273     
00274   dim[0] = Dimension3(yz,yz,zl);
00275 
00276   return dim; 
00277 }
00278 
00279 
00280 
00281 
00282 
00283 SimulatedSerialManipulator::TransformInfo SimulatedSerialManipulator::computeLinkTransforms(const Transform& mountTransform, const base::Vector& q) const
00284 {
00285   TransformInfo transformInfo;
00286   transformInfo.mountTransform = mountTransform;
00287   transformInfo.q.reset(q);
00288   
00289   array<Transform>& A(transformInfo.A); // convenient aliases
00290   array<Transform>& T(transformInfo.T);
00291   array<Transform>& SLT(transformInfo.SLT);
00292   A.resize(chain.size()+1);  
00293   T.resize(A.size());
00294   SLT.resize(A.size());
00295 
00296   Transform baseTransform(manipulatorDescr->getBaseTransform());
00297 
00298   A[0] = transformInfo.mountTransform * baseTransform; // link 0
00299   T[0] = A[0];
00300   Int j=0; // joint variable index
00301   
00302   // handle base link (i.e. link joining mount to first joint origin) as a special case first
00303   
00304   SLT[0] = Transform(Vector3(0,0,-linkLengths[0]/2.0));
00305   // for the base, we want the Solid to have it's z-axis co-incident with
00306   //  the line joining the mount origin and the first joint's origin
00307   // (so we construct a rotation that rotates the z-axis of the base Solid
00308   //  into the joining line)
00309   Vector3 localZAxis(Vector3(0,0,1)); // untransformed z-axis
00310   Vector3 baseOffset(baseTransform.getTranslation());
00311   if (!Math::equals(baseOffset.norm(),0)) {
00312     // mount and base origins are not co-incident, need to orient Solid
00313     Vector3 baseZAxis( baseOffset.normalize()); // vector we want the z-axis be coincide with
00314     Vector3 rotAxis = cross(localZAxis, baseZAxis); // rotate about this vector
00315     if (!rotAxis.equals(Vector3(0,0,0))) { // not co-linear, transformation necessary
00316       Real rotAngle = Math::acos(dot(localZAxis, baseZAxis)); // by this amount
00317       //!!! do we need to account for when baseZAxis.y < 0 (and do rotAngle=360-rotAngle)??!!!
00318       Transform R = Quat4(rotAxis, rotAngle);
00319       SLT[0] = R * SLT[0];
00320     }
00321   }
00322 
00323   transformInfo.mountToBaseSolid = inverse(SLT[0]);
00324   
00325   
00326   
00327   // now the rest of the links
00328   for (Int l=1; l<=chain.size(); l++) { // for each link
00329     
00330     const KinematicChain::Link& link(chain[l-1]);
00331     
00332     //
00333     // ask KinematicChain to compute the transform for each link
00334     Vector lq(link.dof());
00335     if (lq.size()>0)
00336       lq[0] = transformInfo.q[j]; // this currently only handles 1-dof links (!!!)
00337     A[l] = base::toMatrix4(link.kinematicTransform(lq));
00338     
00339     //
00340     // accumulate inter-link transforms 
00341     T[l] = T[l-1]*A[l]; 
00342     
00343     //
00344     // finally compute the relative configuration of each link's Solid from its origin
00345 
00346     // Rotate the z-axis into the x-axis, as the link coord. frame has the x-axis along
00347     //  the link length, but the Solid's z-axis is the long one.
00348     // Also translate back 1/2 the Solid length along the long axis (z)
00349     //  (as the origin of the Solid is at its center of mass, but the origin of a link
00350     //   is at its end)
00351     SLT[l] = Quat4(Vector3(0,1,0),consts::Pi/2.0) * Transform(Vector3(0,0,-linkLengths[l]/2.0));
00352 
00353     if (link.isDHType()) {
00354 //!!! fix comment & and make analogous changes (re linkLength==0) to SimulatedTool if necessary!!!
00355       // We also want to rotate the Solid so that the ends meet even if there
00356       //  is a displacement due to DH-parameter d
00357       //  (this will be a rotation about the y-axis of link l-1 to make the Solid's z-axis
00358       //   point to the previous link's origin rather than being parallel with
00359       //   the link x-axis.  To achieve this we bring link Solid l's y&z-axes parallel to
00360       //   those of link l-1 by reversing the skew DH-parameter alpha, then rotate about the x-axis,
00361       //   and then redo the skew)
00362       Real d = (link.type() == KinematicChain::Link::Prismatic)?lq[0]:link.getD();
00363       Real incline = ( !Math::equals(d,0) && !Math::equals(linkLengths[l],0) )? 
00364                                                                 Math::asin(d/linkLengths[l]) : 0;
00365       if (!Math::equals(incline,0)) {
00366         Transform rotYl    = Quat4(Vector3(0,1,0),-incline);
00367         Transform rotXl    = Quat4(Vector3(1,0,0), link.getAlpha());
00368         Transform rotXlInv = Quat4(Vector3(1,0,0),-link.getAlpha());
00369         Transform rotYlm1 = rotXlInv * rotYl * rotXl;
00370         
00371         SLT[l] = rotYlm1 * SLT[l];
00372       }
00373  
00374     }
00375 
00376     if (l==chain.size())
00377       transformInfo.eeToEESolid = inverse(SLT[l]); //!!! check
00378     
00379     j += link.dof();
00380   } // for each link
00381 
00382   
00383   return transformInfo;
00384 }
00385 
00386 
00387 
00388 
00389 
00390 void SimulatedSerialManipulator::createLinks(const array<base::Dimension3>& linkDims)
00391 {
00392   // We create a Solid for each link and place it in SolidSystem
00393   // Unless the geometry is specified, the Shape will be a Box who's dimensions
00394   // are specified in linkDims[]
00395   // The links are also chained together using SpatialGroups
00396   Assert(chain.size() > 0);
00397 
00398   links.resize(chain.size()+1);
00399   
00400   for (Int l=0; l<=chain.size(); l++) { // for each link
00401     const Dimension3& dim(linkDims[l]);
00402     //ref<Box> box(NewObj Box(dim.x,dim.y,dim.z));
00403     ref<Capsule> cap(NewObj Capsule(dim.z, dim.x/2.0));
00404     ref<Material> material(NewObj physics::Material());
00405     
00406     // colour
00407     switch (l%10) {
00408     case 0: material->setBaseColor(gfx::Color3(0.6,0.6,0.6)); break;
00409     case 1: material->setBaseColor(gfx::Color3(0,1,0)); break;
00410     case 2: material->setBaseColor(gfx::Color3(0+0.1,1-0.1,0+0.1)); break;
00411     case 3: material->setBaseColor(gfx::Color3(0+0.2,1-0.2,0+0.2)); break;
00412     case 4: material->setBaseColor(gfx::Color3(0+0.3,1-0.3,0+0.3)); break;
00413     case 5: material->setBaseColor(gfx::Color3(0+0.4,1-0.4,0+0.4)); break;
00414     case 6: material->setBaseColor(gfx::Color3(0+0.5,1-0.5,0+0.5)); break;
00415     case 7: material->setBaseColor(gfx::Color3(0+0.6,1-0.6,0+0.6)); break;
00416     case 8: material->setBaseColor(gfx::Color3(1,1,1)); break;
00417     case 9: material->setBaseColor(gfx::Color3(1,0,0)); break;
00418     default:
00419       material->setBaseColor(gfx::Color3(0,0,1));
00420     }
00421     
00422     // add it to the system
00423     links[l] = solidSystem->createSolid(cap,material);
00424     links[l]->setName(getManipulatorDescription()->getName()+" "
00425                       +String("link ")+base::intToString(l));
00426     solidSystem->addSolid(links[l]);
00427 
00428     // create a SpatialGroup which will hold a SpatialTransform warpping this link's Solid
00429     //  (as the link Solid may be transformed from the link origin), and the next link's
00430     //  group.
00431     ref<SpatialTransform> linkTransform( NewObj SpatialTransform() );
00432     linkTransform->setChild( links[l] ); // wrap link in a SpatialTransform
00433     ref<SpatialGroup> linkGroup( NewObj SpatialGroup() );
00434     linkGroup->add(linkTransform); // add it to the link group
00435     linkGroup->setImplicitConfiguration(linkTransform); // the configuration of the link group is synonymous with the linkTransform
00436     if (l > 0) linkGroups[l-1]->add(linkGroup); // add the linkGroup to the previous link's linkGroup
00437     linkGroups.push_back(linkGroup); // stash it into the link group array
00438     
00439     if (l == 0)
00440       baseSolid = links[l];
00441     else
00442       if (l == chain.size())
00443         endSolid = links[l];
00444   }
00445 }
00446 
00447 
00448 
00449 void SimulatedSerialManipulator::positionLinks(const SimulatedSerialManipulator::TransformInfo& transformInfo)
00450 {
00451   Assert(links.size() == chain.size()+1); // links must already have been created
00452 
00453 //  const Transform& mountTransform(transformInfo.mountTransform);
00454 
00455   mountToBaseSolid = transformInfo.mountToBaseSolid;
00456   eeToEESolid = transformInfo.eeToEESolid;
00457   
00458   
00459   // some convenient aliases
00460   const array<Transform>& SLT( transformInfo.SLT );   // transforms from the link's Solid coord. frame to the link frame
00461   const array<Transform>& T( transformInfo.T );
00462 
00463   //Transform baseTransform(manipulatorDescr.getBaseTransform());
00464     
00465   for (Int l=0; l<=chain.size(); l++) { // for each link
00466 
00467     ref<SpatialGroup> linkGroup(linkGroups[l]);
00468     SpatialGroup::iterator firstChild = linkGroup->begin();
00469 
00470     // set the transform from link origin to Solid origin first,
00471     // so that the Solid is properly configured when SpatialTransform configuration is set
00472     ref<SpatialTransform> linkSpatialTransform( narrow_ref<SpatialTransform>( *firstChild ) );
00473     linkSpatialTransform->setTransform( SLT[l] );
00474     
00475     // set SpatialTransform configuration (hence configuring its Solid child, and implicitly the linkGroup)
00476     linkSpatialTransform->setConfiguration( T[l] ); 
00477     
00478   } // for each link
00479   
00480 }
00481 
00482 
00483 
00484 void SimulatedSerialManipulator::disableCollisions(const array<ref<physics::Collidable> >& collidables, 
00485                                                    const array<ref<physics::Collidable> >& proximityCollidables)
00486 {
00487   Assert(solidSystem);
00488   Assert(links.size() == chain.size()+1); // links must already have been created
00489   
00490   ref<CollisionCuller> cc(solidSystem->getCollisionCuller());
00491   bool hasProxSensors = manipulatorDescr->hasLinkProximitySensors();
00492   
00493   bool disableNextWithPrev = false;   // if true, disabled collisions between link's l & l-2 (in addition to the
00494                                       // usual disable between l & l-1.  This occurs when link l-1 has a length of 0 (coincident origins)
00495   
00496   for (Int l=1; l<=chain.size(); l++) { // for each link
00497     // disable collision detection between consecutive links
00498     cc->collisionEnable(false,collidables[l-1],collidables[l]);
00499     
00500     // and between link Solid Collidables & their corresponding proximity sensor Collidable
00501     if (hasProxSensors) {
00502       cc->collisionEnable(false,collidables[l], proximityCollidables[l]);
00503 
00504       cc->collisionEnable(false,collidables[l-1],proximityCollidables[l]);
00505       cc->collisionEnable(false,proximityCollidables[l-1],collidables[l]); 
00506     
00507 //!!!debug reduce link-link prox hits
00508 /*    if (l>=2 && l < proximityCollidables.size()-2) {
00509       cc->collisionEnable(false,collidables[l],proximityCollidables[l+1]);
00510       cc->collisionEnable(false,collidables[l],proximityCollidables[l+2]);
00511       cc->collisionEnable(false,collidables[l-1],proximityCollidables[l+1]);
00512       cc->collisionEnable(false,collidables[l-1],proximityCollidables[l+2]);
00513       cc->collisionEnable(false,collidables[l-2],proximityCollidables[l]);
00514       cc->collisionEnable(false,collidables[l-2],proximityCollidables[l+1]);
00515       cc->collisionEnable(false,collidables[l-2],proximityCollidables[l+2]);
00516     }*/
00517 //!!! 
00518 //!!! debug - eliminate link-link prox hits
00519       for(Int pl=0; pl<proximityCollidables.size(); pl++)
00520         cc->collisionEnable(false,collidables[l], proximityCollidables[pl]);
00521 //!!!
00522     }
00523 
00524     if (disableNextWithPrev) {
00525       cc->collisionEnable(false,collidables[l-2],collidables[l]);
00526       if (hasProxSensors) cc->collisionEnable(false,collidables[l-2],proximityCollidables[l]);
00527       disableNextWithPrev = false;
00528     }
00529 
00530     if (linkLengths[l]<=0.05)
00531        disableNextWithPrev = true; // don't collide link l+1 with l-1 as they will be close on account of this link l being 0 length
00532     
00533   }  
00534   
00535 //!!! eliminate base prox hits
00536 if (hasProxSensors)
00537   for(Int pl=0; pl<proximityCollidables.size(); pl++)
00538     cc->collisionEnable(false,collidables[0], proximityCollidables[pl]);
00539 //!!!
00540 }
00541 
00542 
00543 void SimulatedSerialManipulator::attachJoints(const SimulatedSerialManipulator::TransformInfo& transformInfo)
00544 {
00545   if (links.size() < 2) return; // no joints
00546 
00547   // alias
00548   const array<Transform>& T( transformInfo.T );     // accumulated transformations for each link (transforms from frame l to base frame)
00549   const array<Transform>& SLT( transformInfo.SLT ); 
00550   
00551   ref<ConstraintGroup> cgroup = solidSystem->createConstraintGroup();
00552   solidSystem->addConstraintGroup(cgroup);
00553   ref<Motor> motor;
00554   joints.resize(links.size()-1);
00555   
00556   for (Int l=1; l<links.size(); l++) { // for each link (except the first)
00557     // connect it to the previous link in the chain
00558   
00559     const KinematicChain::Link& link(chain[l-1]);
00560     ref<Joint> joint;
00561     
00562     // Connect using a HingeJoint for revolute joints and a SliderJoint for prismatic joints
00563     if (link.isDHType()) {
00564 //!!! check this is correct - is the link Zaxis == Solid -xaxis?? !!!      
00565       // All DH type joints have an axis of Z - which is the Solid's -ve X-axis
00566       //  The axis is the z-axis of the previous link (l-1)
00567       // (they are specified relative to link l - hence we must transform z-axis
00568       //  of link l-1 into link l's coord. frame.)  
00569       Vector3 axis( Vector3(-1,0,0) ); // untransformed Solid -ve x-axis (link z-axis)
00570       if (l>1) {
00571         axis = (T[l-1]*SLT[l-1]).rotate(axis);  // -ve x-axis of link Solid l-1 
00572         axis = inverse(T[l]*SLT[l]).rotate(axis);  // -ve x-axis of link Solid l-1 in frame of link Solid l
00573       } else { // connection to base is special case
00574         axis = T[0].rotate(Vector3(0,0,1)); // z-axis in base frame
00575         axis = inverse(T[1]*SLT[1]).rotate(axis);  // z-axis of base frame in frame of link Solid l
00576       }
00577       
00578       
00579       if (link.type() == KinematicChain::Link::Revolute) {
00580   
00581         ref<HingeJoint> hinge = solidSystem->createHingeJoint();
00582         joint = hinge;
00583         cgroup->addConstraint(hinge);
00584         joints[l-1] = joint;
00585         Assert(links[l-1]);
00586         joint->attach(links[l], links[l-1]);
00587   
00588         // the anchor is at the end of the link (toward the base - not the origin end)
00589         hinge->setAnchor( Point3(0,0,-linkLengths[l]/2) );
00590         hinge->setAxis( axis ); 
00591   
00592         // set limits
00593         if (! ((link.minLimit() <= -consts::Pi)&&(link.maxLimit() >= consts::Pi)) ) {
00594           hinge->setLowStop(link.minLimit() - Math::degToRad(1) );
00595           hinge->setHighStop(link.maxLimit() + Math::degToRad(1) );
00596           hinge->setStopRestitution(0.2);
00597         }
00598   
00599         // now attach a Motor to drive the joint
00600         motor = solidSystem->createMotor();
00601         hinge->attachMotor(1, motor);
00602   
00603       }
00604       else if (link.type() == KinematicChain::Link::Prismatic) {
00605   
00606         ref<SliderJoint> slider = solidSystem->createSliderJoint();
00607         joint = slider;
00608         cgroup->addConstraint(slider);
00609         joints[l-1] = joint;
00610         Assert(links[l-1]);
00611         joint->attach(links[l], links[l-1]);
00612   
00613         slider->setAxis( axis ); 
00614   
00615         // set limits
00616         slider->setLowStop(link.minLimit());
00617         slider->setHighStop(link.maxLimit());
00618         slider->setStopRestitution(0.2);
00619   
00620         // now attach a Motor to drive the joint
00621         motor = solidSystem->createMotor();
00622         slider->attachMotor(1, motor);
00623   
00624         Logln("Warning: Prismatic joints not fully implemented");
00625       }
00626     }
00627     else
00628       throw std::invalid_argument(Exception("unknown/unsupported joint type: " + link.type()));
00629 
00630     motor->setTargetVel(0);
00631     motor->setMaxForce(0.001); // provide a little damping
00632 
00633   } // for each link 
00634 
00635 }
00636   
00637   
00638   
00639 void SimulatedSerialManipulator::construct(const base::Point3& initialPosition, 
00640                                            const base::Orient& initialOrientation)
00641 {
00642   mountConfiguration = Transform(initialPosition, initialOrientation);
00643   
00644   linkGroups.clear();
00645   createLinks(computeLinkDimensions(manipulatorDescr->getLinkRadii()));
00646   
00647   
00648   // first construct the joint parameter vector q, based on the home positions of 
00649   //  each joint represented in the chain
00650   Assert(chain.size() > 0);
00651   Vector q(chain.dof());
00652   
00653   // note: this only works for links with 1-dof (!!!)
00654   for(Int j=0; j<chain.dof(); j++) { // for each joint
00655     const KinematicChain::Link& link(chain.linkOfVariable(j)); // get link for this joint
00656     q[j] = link.variable();
00657   }
00658 
00659   // compute the various transform matrices we need
00660   TransformInfo transformInfo( computeLinkTransforms(mountConfiguration, q) );
00661 
00662   positionLinks(transformInfo);
00663   
00664   if (dynamic) 
00665     attachJoints(transformInfo);
00666 
00667 //!!! fix up this mess with CollisionCuller/Detector/ResponseHandler  !!!!
00668 // (mostly in [ODE]SoliidSystem).  There is a need for a CollisionSystem to hold everything together
00669 //   (including perhaps Collidables too)
00670 //!!!
00671   
00672   if (!dynamic) {
00673     // replace the default CollisionResponseHandler with one that
00674     // doesn't create contacts
00675 //!!! this doesn't seem to work - comment it out for now
00676 //    ref<CollisionResponseHandler> nullHandler(NewObj NullCollisionResponseHandler(solidSystem->getCollisionDetector()));
00677 //    solidSystem->setCollisionResponseHandler( nullHandler );
00678   }
00679 
00680   // now create a CollisionResponseHandler to handle collisions between
00681   //  the proximity CollidableBodies and oher objects and insert it into
00682   //  the collision chain before the final handler
00683   ref<ProximityCollisionResponseHandler> proximityHandler(NewObj ProximityCollisionResponseHandler(ref<SimulatedSerialManipulator>(this),
00684                                                                                                    solidSystem->getCollisionDetector() ));
00685   proximityHandler->addPotentialCollisionListener( solidSystem->getCollisionResponseHandler() );
00686   solidSystem->setCollisionResponseHandler( proximityHandler );
00687   
00688 }
00689 
00690 
00691 
00692 
00693 // Spatial
00694 
00695 void SimulatedSerialManipulator::setPosition(const Point3& pos)       
00696 { 
00697   Transform baseTransform(manipulatorDescr->getBaseTransform());
00698   mountConfiguration = inverse(baseTransform)*linkGroups[0]->getConfiguration();
00699   mountConfiguration.setTranslationComponent(pos);
00700   linkGroups[0]->setConfiguration(mountConfiguration); 
00701   
00702   // re-position the tool at the ee-end, if necessary (static simulation only)
00703   if (!dynamic && toolGrasped) {
00704     Transform eeConfig( getEEPosition(), getEEOrientation() );
00705     proximityTool->setConfiguration( eeConfig );
00706   }
00707   
00708 }
00709 
00710 Point3 SimulatedSerialManipulator::getPosition() const                  
00711 {
00712   Transform baseTransform(manipulatorDescr->getBaseTransform());
00713   mountConfiguration = inverse(baseTransform)*linkGroups[0]->getConfiguration();
00714   
00715   return mountConfiguration.getTranslation(); 
00716 }
00717 
00718 void SimulatedSerialManipulator::setOrientation(const Orient& orient) 
00719 { 
00720   Transform baseTransform(manipulatorDescr->getBaseTransform());
00721   mountConfiguration = inverse(baseTransform)*linkGroups[0]->getConfiguration();
00722   mountConfiguration.setRotationComponent(orient);
00723   linkGroups[0]->setConfiguration(mountConfiguration); 
00724 
00725   // re-position the tool at the ee-end, if necessary (static simulation only)
00726   if (!dynamic && toolGrasped) {
00727     Transform eeConfig( getEEPosition(), getEEOrientation() );
00728     proximityTool->setConfiguration( eeConfig );
00729   }
00730 }
00731 
00732 Orient SimulatedSerialManipulator::getOrientation() const               
00733 { 
00734   Transform baseTransform(manipulatorDescr->getBaseTransform());
00735   mountConfiguration = inverse(baseTransform)*linkGroups[0]->getConfiguration();
00736 
00737   return mountConfiguration.getRotation(); 
00738 }
00739 
00740 void SimulatedSerialManipulator::setConfiguration(const base::Transform& configuration) 
00741 { 
00742   Transform baseTransform(manipulatorDescr->getBaseTransform());
00743   mountConfiguration = configuration;
00744   linkGroups[0]->setConfiguration(mountConfiguration*baseTransform); 
00745 
00746   // re-position the tool at the ee-end, if necessary (static simulation only)
00747   if (!dynamic && toolGrasped) {
00748     Transform eeConfig( getEEPosition(), getEEOrientation() );
00749     proximityTool->setConfiguration( eeConfig );
00750   }
00751 }
00752 
00753 base::Transform SimulatedSerialManipulator::getConfiguration() const    
00754 { 
00755   Transform baseTransform(manipulatorDescr->getBaseTransform());
00756   mountConfiguration = inverse(baseTransform)*linkGroups[0]->getConfiguration();
00757   return mountConfiguration;
00758 }
00759 
00760 
00761 
00762 
00763 base::Point3 SimulatedSerialManipulator::getEEPosition() const
00764 {
00765   // the end-effector frame is co-incident with the end of the ee solid
00766 
00767   // get the vector offset from ee origin to ee solid origin
00768   Vector3 eeToEESolidOffset( eeToEESolid.getTranslation() );
00769   // now express it in the world frame
00770   Vector3 eeToEESolidOffsetWorld( endSolid->getOrientation().rotate(eeToEESolidOffset) );
00771   // add it to the end solid origin to get the ee origin
00772 
00773   return endSolid->getPosition() + eeToEESolidOffsetWorld;
00774 }
00775 
00776 
00777 base::Orient SimulatedSerialManipulator::getEEOrientation() const
00778 {
00779   Matrix3 eeToEESolidOrient(eeToEESolid.getRotation());
00780   return base::Orient(  endSolid->getOrientation() * Orient(eeToEESolidOrient).getQuat4() );
00781 }
00782 
00783 
00784 
00785 bool SimulatedSerialManipulator::checkProximity(ref<SimulatedTool> tool)
00786 {
00787   if (toolGrasped) 
00788     return (tool == proximityTool);
00789     
00790   // compare the end-effector position/orient with that of the tool
00791   //  If it is within tolerance, return true and record the tool in proximityTool
00792   Point3 eePos(getEEPosition());
00793   if ( (eePos- tool->getPosition()).length() < proximityDistance ) {
00794     Vector3 eeOrient(getEEOrientation().getVector3(Orient::EulerRPY));
00795     Vector3 toolOrient( tool->getOrientation().getVector3(Orient::EulerRPY));
00796     Vector3 eeAngDiff( Math::angleDifference(toolOrient.x,eeOrient.x),
00797                        Math::angleDifference(toolOrient.y,eeOrient.y),
00798                        Math::angleDifference(toolOrient.z,eeOrient.z) );
00799     if (    (Math::abs(eeAngDiff.x) < proximityAngle)
00800          && (Math::abs(eeAngDiff.y) < proximityAngle)
00801          && (Math::abs(eeAngDiff.z) < proximityAngle) ) {
00802       proximityTool = tool;
00803       return true;
00804     }
00805 
00806   }
00807   
00808   return false;
00809 }
00810 
00811 
00812 
00813 
00814 bool SimulatedSerialManipulator::graspTool()
00815 {
00816   if (toolGrasped) return true; // tool already in grasp
00817 
00818   if (!proximityTool) return false; // no tool to grasp
00819   
00820   // recheck that the last tool indicated in proximity is still there
00821   if (!checkProximity(proximityTool)) return false; // no longer in proximity
00822 
00823   // first position the tool exactly in position/orient to be grasped
00824   proximityTool->setPositionOrientation( getEEPosition(), getEEOrientation() );
00825   
00826   // now attach it
00827   proximityTool->attachTo( endSolid );
00828   
00829   linkGroups[linkGroups.size()-1]->add(proximityTool);
00830 
00831   // disable collision detection between the first link of the tool and the ee
00832   //                                     the ee link and the tool first link sensor
00833   //                                     the ee link sensor and the tool first link
00834   ref<CollisionCuller> cc(solidSystem->getCollisionCuller());
00835   ref<Collidable> eeCollidable( collidables[collidables.size()-1] );
00836   ref<Collidable> eeProxCollidable( proximityCollidables[proximityCollidables.size()-1] );
00837   ref<Collidable> toolLinkCollidable( proximityTool->getFirstLinkCollidable() );
00838   ref<Collidable> toolLinkProxCollidable( proximityTool->getFirstLinkProximitySensorCollidable() );
00839   Assert(eeCollidable && eeProxCollidable && toolLinkCollidable && toolLinkProxCollidable);
00840   cc->collisionEnable(false, eeCollidable, toolLinkCollidable );
00841   cc->collisionEnable(false, eeProxCollidable, toolLinkCollidable );
00842   cc->collisionEnable(false, eeCollidable, toolLinkProxCollidable );
00843   toolGrasped = true;
00844 
00845   return true;
00846 }
00847 
00848 
00849 void SimulatedSerialManipulator::releaseGrasp()
00850 {
00851   if (!toolGrasped) return;
00852 
00853   proximityTool->detatch();
00854   linkGroups[linkGroups.size()-1]->remove(proximityTool);
00855   
00856   // re-enable collisions between the first link of the tool and the ee
00857   Assert(solidSystem); Assert(collidables.size()>0);
00858   ref<CollisionCuller> cc(solidSystem->getCollisionCuller());
00859   ref<Collidable> eeCollidable( collidables[collidables.size()-1] );
00860   cc->collisionEnable(true, eeCollidable, proximityTool->getFirstLinkCollidable() );
00861   
00862   
00863   toolGrasped = false;
00864 }
00865 
00866 
00867 
00868 ref<physics::Collidable> SimulatedSerialManipulator::createCollidable(CollidableFlags flags)
00869 {
00870   ref<CollisionCuller> cc(solidSystem->getCollisionCuller());
00871   ref<CollisionDetector> cd(solidSystem->getCollisionDetector());
00872 
00873   linkProximitySurfPosition.resize(links.size());
00874   
00875   collidables.resize(links.size()); // collidables for each link
00876   proximityCollidables.resize(links.size());  // proximity sensor for each link
00877   ref<CollidableGroup> linkCollidableGroup = cc->createCollidableGroup();
00878   proximityCollidableGroup = cc->createCollidableGroup();
00879   
00880   const array<Real>& linkRadii( manipulatorDescr->getLinkRadii() );
00881   
00882   // create Collidables for each link (one that is connected to the Solid
00883   //  and optionally one for the proximity sensor)
00884   for(Int l=0; l<links.size(); l++) {
00885     // Collidable for link Solid
00886     collidables[l] = links[l]->createCollidable(flags);
00887     linkCollidableGroup->addCollidable( collidables[l] );
00888     if (l==0) collidables[l]->setName("baseLink");
00889     
00890     if (manipulatorDescr->hasLinkProximitySensors()) {
00891 
00892       // Collidable for proximity around each link
00893       
00894       // get link geometry info
00895       ref<const Shape> linkShape( links[l]->getShape() );
00896       Real linkHeight;
00897       Real linkRadius;
00898       if (manipulatorDescr->hasGeometry()) {
00899         linkHeight = narrow_ref<const Capsule>(linkShape)->height(); // capsule!!!
00900         linkRadius = linkRadii[l];
00901       }
00902       else {
00903         linkHeight = narrow_ref<const Capsule>(linkShape)->height(); // capsule!!!
00904         linkRadius = narrow_ref<const Capsule>(linkShape)->radius(); // capsule!!!
00905       }
00906       
00907       Real proxHeight = linkHeight;
00908 //!!!! just for video      
00909       Real proxRadius = /*linkRadius +*/ manipulatorDescr->linkProximitySensorRange();
00910       ref<const Capsule> collisionShape(NewObj Capsule(proxHeight, proxRadius));
00911       linkProximitySurfPosition[l] = linkRadius;
00912 
00913       ref<Collidable> pbody( links[l]->createCollidable(collisionShape, flags) );
00914       pbody->setInterpenetrationIsNormal(true); // the link solid is normally inside the proximity Collidable
00915       pbody->setUserClass(SensorCollidableClass); // cull sensor-sensor collision checks
00916 
00917       if (l!=0)
00918         pbody->setName( pbody->getName()+" Sensor" );
00919       else
00920         pbody->setName("baseLink Sensor");
00921 
00922 //VisualDebugUtil::addDebugObject(linkShape, links[l]->getName(), links[l]->getConfiguration(),Color4("yellow",0.2));//!!!
00923 //disable colision capsule display: VisualDebugUtil::addDebugObject(collisionShape, pbody->getName(), links[l]->getConfiguration(),Color4("lime green",0.15));//!!!
00924     // ref self so we can identify our Collidable quickly in ProximityCollisionResponseHandler
00925       pbody->setUserData(ref<SimulatedSerialManipulator>(this)); 
00926       proximityCollidables[l] = pbody;
00927       proximityCollidableGroup->addCollidable( proximityCollidables[l] );
00928     }
00929     
00930   }
00931 
00932   proximityCollidableGroup->setChildIntercollisionEnabled(false);
00933   proximityCollidableGroup->setUserClass(SensorCollidableClass);
00934   
00935   disableCollisions(collidables, proximityCollidables);
00936   
00937   ref<CollidableGroup> collidableGroup = cc->createCollidableGroup();
00938   collidableGroup->addCollidable( linkCollidableGroup );
00939   if (manipulatorDescr->hasLinkProximitySensors()) 
00940     collidableGroup->addCollidable( proximityCollidableGroup );
00941   
00942   return collidableGroup;
00943 }
00944 
00945 
00946 
00947 Real SimulatedSerialManipulator::getClosestObjectDistance(Int link) const 
00948 { 
00949   if (linkProximity.size()>0) {
00950     Assert(link < linkProximity.size());
00951     return linkProximity[link].dist; 
00952   }
00953   else 
00954     return maxDist+1.0; 
00955 }
00956 
00957 base::Vector3 SimulatedSerialManipulator::getClosestObjectDirection(Int link) const 
00958 {
00959   if (linkProximity.size()>0) {
00960     Assert(link < linkProximity.size());
00961     return linkProximity[link].dir;
00962   }
00963   else
00964     return Vector3();
00965 }
00966 
00967 Real SimulatedSerialManipulator::getClosestObjectSensorPosition(Int link) const 
00968 { 
00969   if (linkProximity.size()>0) {
00970     Assert(link < linkProximity.size());
00971     return linkProximity[link].intersect;
00972   } 
00973   else 
00974     return 0;
00975 }
00976 
00977 
00978 
00979 
00980 void SimulatedSerialManipulator::handleCollision(ref<physics::CollisionState> collisionState) 
00981 {
00982   typedef SimulatedSerialManipulator::ProximityData ProximityData;
00983 
00984   // figure out proximity info for ControlInterface
00985 
00986   bool firstIsSensor = (collisionState->collidable1->getUserData() == ref<SimulatedSerialManipulator>(this));
00987   
00988   // find the corresponding link
00989   Int l=0;
00990   bool found = false;
00991   CollidableGroup::const_iterator sc( proximityCollidableGroup->begin() );
00992   CollidableGroup::const_iterator send( proximityCollidableGroup->end() );
00993   while ((sc != send) && !found) {
00994     if (*sc == (firstIsSensor?collisionState->collidable1:collisionState->collidable2) )
00995       found = true;
00996     else {
00997       ++sc; ++l;
00998     }
00999   }
01000 
01001 //!!! handle base problem
01002 if (l < 3) return;  
01003   
01004   ref<const CollidableBody> body1( narrow_ref<const CollidableBody>(collisionState->collidable1) );
01005   ref<const CollidableBody> body2( narrow_ref<const CollidableBody>(collisionState->collidable2) );
01006   
01007   //!!!!
01008 //  String name1(body1->getName());
01009 //  String name2(body2->getName());
01010 //  if ((name1.find("Multi") != String::npos) || (name2.find("Multi") != String::npos)) {
01011 //    Debugcln(DJ,"SimSerManip::handleCollision():" << body1->getName() << " and " << body2->getName());  
01012 //  }
01013   //!!!!
01014 
01015   // now we compute the distance from the axis of the Solid (actually a segment
01016   //  running along the axis) and the obstacle
01017   ref<const Solid> linkSolid( narrow_ref<const Solid>( links[l] ) );
01018   Transform T( linkSolid->getConfiguration() );
01019   Real length( linkLengths[l] );
01020   Segment3 linkSeg( T*Point3(0,0,-length/2.0), T*Point3(0,0,length/2.0) );
01021   
01022   //  now determine distance between the obstacle and the link segment
01023   ref<const Shape> obstacleShape( (firstIsSensor?body2:body1)->getShape() );
01024   Transform obstacleT( (firstIsSensor?body2:body1)->getConfiguration() );
01025   // shortest degment between them
01026   Segment3 seg( obstacleShape->shortestSegmentBetween(obstacleT, linkSeg) );
01027 
01028   Real dist = seg.length();
01029   Vector3 direction( seg.s - seg.e ); if (dist > 0) direction.normalize();
01030   Real intersect = (seg.e - linkSeg.s).length();
01031   ProximityData proxData(dist, intersect,  direction); 
01032   linkProximity[l] = proxData;
01033   
01034 
01035   if (!firstIsSensor) base::swap(body1, body2);
01036   
01037 //!!! debug  
01038 //Debugln(DJ,"proximity between " << body1->getName() << " and " << body2->getName());
01039 //Debugcln(DJ,"seg between " << body1->getName() << " and " << body2->getName() << " is " << seg << " len=" << seg.length());
01040 
01041   // try to visualize the proximity data  
01042   Transform c;
01043   c.setToTranslation( seg.s + 0.5*(seg.e-seg.s) );
01044   Matrix3 R; R.setIdentity();
01045   if (!seg.e.equals(seg.s)) {
01046     Vector3 z( seg.e - seg.s ); z.normalize();
01047     Vector3 x(1,0,0);
01048     if (x.equals(z) || x.equals(-z)) x = Vector3(0,1,0);
01049     if (x.equals(z) || x.equals(-z)) x = Vector3(0,0,1);
01050     if (x.equals(z) || x.equals(-z)) x = Vector3(1,1,0);
01051     Vector3 y( cross(x,z) ); y.normalize();
01052     x = cross( y,z ); x.normalize();
01053     R.setColumn(1,x);
01054     R.setColumn(2,y);
01055     R.setColumn(3,z);
01056   }
01057   c.setRotationComponent( R );
01058   VisualDebugUtil::addDebugCylinderObject(dist, 0.005, body1->getName()+"proxseg", c, gfx::Color4("yellow"));
01059   
01060 /*  
01061   // try to visualize the push-away direction
01062   {
01063     Real L = 0.00611899; // push away dist
01064     Point3 p(0.824874,1.36352,0.540932); // push away point
01065     Vector3 n(0.893771,0.448523,-0); // push away direction
01066     n.normalize();
01067     c = Transform();
01068     c.setToTranslation( p - 0.5*L*n);
01069     Matrix3 R; R.setIdentity();
01070     Vector3 z( n ); z.normalize();
01071     Vector3 x(1,0,0);
01072     if (x.equals(z) || x.equals(-z)) x = Vector3(0,1,0);
01073     if (x.equals(z) || x.equals(-z)) x = Vector3(0,0,1);
01074     if (x.equals(z) || x.equals(-z)) x = Vector3(1,1,0);
01075     Vector3 y( cross(x,z) ); y.normalize();
01076     x = cross( y,z ); x.normalize();
01077     R.setColumn(1,x);
01078     R.setColumn(2,y);
01079     R.setColumn(3,z);
01080     c.setRotationComponent( R );
01081     VisualDebugUtil::addDebugCapsuleObject(L, 0.01, "pushpoint1", c, gfx::Color4("cyan"));
01082   }  
01083 */  
01084 //disable collision capsule red display:  VisualDebugUtil::setColor(body1->getName(), Color4("red",0.15)); 
01085 //!!!
01086 }
01087 

Generated on Thu Jul 29 15:56:42 2004 for OpenSim by doxygen 1.3.6