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

robot/control/kinematics/IKORController.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: IKORController.cpp 1036 2004-02-11 20:48:55Z jungd $
00019   $Revision: 1.13 $
00020   $Date: 2004-02-11 15:48:55 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <robot/control/kinematics/IKORController>
00026 
00027 #include <robot/control/kinematics/MPPseudoInvSolver>
00028 #include <robot/control/kinematics/LeastNormIKSolver>
00029 #include <robot/control/kinematics/FullSpaceSolver>
00030 #include <robot/control/kinematics/IKOR>
00031 
00032 
00033 using robot::control::kinematics::IKORController;
00034 
00035 using base::Matrix;
00036 using base::Orient;
00037 using robot::ControlInterface;
00038 using robot::control::kinematics::LeastNormIKSolver;
00039 using robot::control::kinematics::IKOR;
00040 
00041 
00042 /// \todo optMethod, etc. should be passed as parameters (or settable via set methods)
00043 IKORController::IKORController(IKMethod method, ref<robot::Robot> robot, Int manipulatorIndex,
00044                                bool platformActive, bool orientationControl, 
00045                                base::Orient::Representation orientationRepresentation)
00046   : method(method), robot(robot), 
00047     platformActive(platformActive), orientationControl(orientationControl),
00048     orientRep(orientationRepresentation),
00049     d(0.1)
00050 {
00051   ref<const RobotDescription> rd( robot->getRobotDescription() );
00052   if (!rd->platform()->isMobile() && platformActive)
00053     throw std::invalid_argument(Exception("A fixed Platform cannot be active"));
00054 
00055   array<ref<const ManipulatorDescription> > manipulators( rd->manipulators() );
00056 
00057   if (manipulators.size() == 0)
00058     throw std::invalid_argument(Exception("Robots without a manipulator not currently supported"));
00059 
00060   if (manipulatorIndex >= manipulators.size())
00061     throw std::out_of_range(Exception("manipulatorIndex is invalid"));
00062 
00063   ref<const ManipulatorDescription> manipulator( manipulators[manipulatorIndex] );
00064 
00065   if (manipulator->type() != ManipulatorDescription::Serial)
00066     throw std::invalid_argument(Exception("Only serial manipulators are supported"));
00067 
00068   // obtain descriptions of the kinematic chains
00069   manipChain = manipulator->getKinematicChain();
00070   
00071   
00072   // if the manipulator has proximity sensors, get the interface
00073   try {
00074     proxInterface = robot->getControlInterface(String("manipulatorProximity")+base::intToString(manipulatorIndex+1));
00075   } catch (std::invalid_argument& e) {
00076     proxInterface = ref<ControlInterface>(0);
00077   }
00078   
00079 
00080   switch (method) {
00081 
00082   case LeastNorm: {
00083     ikSolver       = ref<InverseKinematicsSolver>(NewObj LeastNormIKSolver());
00084     optMethod      = LeastNormIKSolver::DefaultMethod;
00085     optCriterion   = LeastNormIKSolver::LeastNorm;
00086     optConstraints.set( LeastNormIKSolver::DefaultConstraints );
00087     
00088   }
00089   break;
00090 
00091   case FSPLagrangian: {
00092     ikSolver       = ref<InverseKinematicsSolver>(NewObj IKOR(manipChain, Vector(), platformActive));
00093     optMethod      = IKOR::Lagrangian;
00094     optCriterion   = IKOR::LeastNorm;
00095     optConstraints.set(IKOR::JointLimits);
00096     if (proxInterface != 0) 
00097       optConstraints.set(IKOR::ObstacleAvoidance);  
00098   }
00099   break;
00100 
00101   default:
00102     throw std::invalid_argument(Exception("unsupported/unknown IKMethod"));
00103   }
00104 
00105   // initialize input/outputNames for ControlInterface to return
00106   inputName.at(0) = "x";
00107   inputName.at(1) = "y";
00108   inputName.at(2) = "z";
00109   for(Int o=0; o<9; o++)
00110     inputName.at(3+o) = "o"+base::intToString(o);
00111 
00112   outputName.at(0) = "dx";
00113   outputName.at(1) = "dy";
00114   outputName.at(2) = "dz";
00115   for(Int o=0; o<9; o++)
00116     inputName.at(3+o) = "do"+base::intToString(o);
00117 
00118   x.reset(zeroVector( 3+Orient(orientRep).size() ));
00119   tx.reset(zeroVector(orientationControl?x.size():3));
00120 }
00121 
00122 
00123 
00124 void IKORController::setControlInterface(ref<ControlInterface> controlInterface) 
00125 {
00126   if (controlInterface->getType() == "JointPositionControl") {
00127     manipulatorInterface = controlInterface;
00128     // initially, set the target ee pos to the current ee pos
00129     calcEEPositionOrientation();
00130     tx = vectorRange(x,Range(0,tx.size()));
00131   }
00132   else {
00133     Logln("Ignoring useless interface - name:" << controlInterface->getName() << " type:" << controlInterface->getType());
00134   }
00135 }
00136 
00137 
00138 bool IKORController::iterate(const base::Time& time)
00139 {
00140   if (!isConnected()) return false; // nothing to control
00141   try {
00142     calcEEPositionOrientation(); // update q, x
00143     Vector x2(x);
00144     if (!orientationControl) {
00145       x2.resize(3);
00146       x2 = vectorRange(x,Range(0,3));
00147     }
00148 
00149     
00150     // read proximity sensor data (if any) from manipulator and give it to the solver so that
00151     //  obstacle constraints can be imposed as appropriate
00152     // (note that the interface provides prox data by link of the manipulator, but the
00153     //  solver expects prox data by dof variable for the chain)
00154     if (proxInterface != 0) {
00155       array<InverseKinematicsSolver::LinkProximityData> proxData( manipChain.dof() ); // elements initialize to no-proximity
00156       
00157       // indices correspond to links (including base), not parameters (some links may have 0-dof)
00158       Vector proximityInputs( proxInterface->getInputs() );
00159 
00160       // fill in proxData from proximityInputs
00161       for(Int v=0; v < manipChain.dof(); v++) { // for each platf/manip[/tool] parameter variable
00162         Int l = manipChain.linkIndexOfVariable(v); // manip[/tool] link index
00163         InverseKinematicsSolver::LinkProximityData& pd(proxData[v]);
00164         
00165         pd.distance =    proximityInputs[l*5]; // see SimulatedRobot for interface input vector description
00166         pd.direction.resize(3);
00167         pd.direction[0] = proximityInputs[l*5+1];
00168         pd.direction[1] = proximityInputs[l*5+2];
00169         pd.direction[2] = proximityInputs[l*5+3];
00170         pd.intercept   = proximityInputs[l*5+4];
00171       }
00172       
00173       ikSolver->setProximitySensorData(proxData, d);
00174 
00175     }
00176     
00177     
00178 
00179     // solve IK
00180     Vector dx = tx-x2;
00181     Matrix J( manipChain.getJacobian(q, orientationControl) );
00182     Vector dq( ikSolver->solve(dx, x2, q, J, optMethod, optCriterion, optConstraints, orientRep) );
00183 
00184 
00185     manipulatorInterface->setOutputs(q+dq); // set joint variables
00186     
00187   } catch (std::exception& e) {
00188     // just log errors and keep going
00189     Logln("Warning: controller error:" << e.what());
00190   }
00191   
00192   return false;
00193 }
00194 
00195 
00196 base::array<std::pair<String,String> > IKORController::controlInterfaces() const
00197 {
00198   array<std::pair<String, String> > a;
00199   
00200   a.push_back(std::make_pair<String,String>("manipulatorEEPosition","EndEffectorPositionControl"));
00201   a.push_back(std::make_pair<String,String>("manipulatorLinkPositions","LinkOriginPositions"));
00202   
00203   return a;
00204 }
00205 
00206 
00207 ref<ControlInterface> IKORController::getControlInterface(String interfaceName) throw(std::invalid_argument)
00208 {
00209   if (!isConnected())
00210     throw std::invalid_argument(Exception("unsupported interface (not yet connected)"));
00211 
00212   if (interfaceName=="") interfaceName="manipulatorEEPosition";
00213 
00214   if (interfaceName=="manipulatorEEPosition")
00215     return ref<ControlInterface>(NewObj EEPositionControlInterface(ref<IKORController>(this), "manipulatorEEPosition", "EndEffectorPositionControl")); 
00216 
00217   if (interfaceName=="manipulatorLinkPositions")
00218     return ref<ControlInterface>(NewObj LinkPositionsControlInterface(ref<IKORController>(this), "manipulatorLinkPositions","LinkOriginPositions"));
00219 
00220   throw std::invalid_argument(Exception(String("unsupported interface name:")+interfaceName));
00221 }
00222 
00223 
00224 void IKORController::calcEEPositionOrientation() 
00225 {
00226   // calculate the EE position using the current joint parameters and the forward kinematics transform (Tn)
00227   q.reset( manipulatorInterface->getInputs() ); // get joint variables
00228   Matrix T( manipChain.getForwardKinematics(q) ); // 4x4 transform to ee
00229 
00230   //  the position is the first 3 elements of column 4 of T
00231   //  the orientation is the 3x3 submatrix of T - converted into a vector
00232   //  in the representation 'orientRep'.
00233   Vector pos(3); pos = vectorRange(Vector(matrixColumn(T,3)), Range(0,3));
00234   Matrix rot(3,3); rot = matrixRange(T, Range(0,3), Range(0,3));
00235   Vector orient( Orient(rot).getVector(orientRep) );
00236   x.resize(3+Orient::size(orientRep));
00237   vectorRange(x, Range(0,3)) = pos;
00238   vectorRange(x, Range(3,x.size())) = orient;
00239 }
00240 
00241 
00242 base::array<base::String> IKORController::inputName; 
00243 base::array<base::String> IKORController::outputName;
00244 
00245 
00246 
00247 // class EEPositionControlInterface
00248 
00249 inline Int IKORController::EEPositionControlInterface::inputSize() const
00250 {
00251   return 3+Orient(c->orientRep).size(); // always provide pos & orient, even when not controlling orientation
00252 }
00253 
00254 String IKORController::EEPositionControlInterface::inputName(Int i) const
00255 {
00256   if (i>=inputSize())
00257     throw std::out_of_range(Exception("index out of range"));
00258 
00259   return c->inputName[i];
00260 }
00261 
00262 Real IKORController::EEPositionControlInterface::getInput(Int i) const 
00263 {
00264   if (i>=inputSize())
00265     throw std::out_of_range(Exception("index out of range"));
00266 
00267   c->calcEEPositionOrientation();
00268   return c->x[i];
00269 }
00270 
00271 const base::Vector& IKORController::EEPositionControlInterface::getInputs() const 
00272 {
00273   c->calcEEPositionOrientation();
00274   return c->x;
00275 }
00276 
00277 inline Int IKORController::EEPositionControlInterface::outputSize() const
00278 {
00279   return (c->orientationControl?inputSize():3);
00280 }
00281 
00282 String IKORController::EEPositionControlInterface::outputName(Int i) const
00283 {
00284   if (i>=outputSize())
00285     throw std::out_of_range(Exception("index out of range"));
00286 
00287   return c->inputName[i];
00288 }
00289 
00290 void IKORController::EEPositionControlInterface::setOutput(Int i, Real value) 
00291 {
00292   if (i>=outputSize())
00293     throw std::out_of_range(Exception("index out of range"));
00294 
00295   c->calcEEPositionOrientation();
00296   c->tx[i] = value;
00297 }
00298 
00299 void IKORController::EEPositionControlInterface::setOutputs(const Vector& values) 
00300 {
00301   if (values.size() != outputSize())
00302     throw std::out_of_range(Exception("dimension not equal to output dimension"));
00303   
00304   c->calcEEPositionOrientation();
00305   c->tx = values;
00306 }
00307 
00308 
00309 
00310 
00311 // class LinkPositionsControlInterface
00312 
00313 inline Int IKORController::LinkPositionsControlInterface::inputSize() const
00314 {
00315   return c->manipChain.dof()*3; // no. joints * 3 (i.e. x,y,z)
00316 }
00317 
00318 String IKORController::LinkPositionsControlInterface::inputName(Int i) const
00319 {
00320   if (i>=inputSize())
00321     throw std::out_of_range(Exception("index out of range"));
00322 
00323   Int j = i/3;
00324   Int c = i - (j*3);
00325   String coord( (c==0)?"x":((c==1)?"y":"z") );
00326   return coord+base::intToString(j);
00327 }
00328 
00329 Real IKORController::LinkPositionsControlInterface::getInput(Int i) const 
00330 {
00331   if (i>=inputSize())
00332     throw std::out_of_range(Exception("index out of range"));
00333 
00334   const Vector& linkPositions( getInputs() );
00335   return linkPositions[i];
00336 }
00337 
00338 
00339 /// \todo fix for q.size() != chain.size()
00340 const base::Vector& IKORController::LinkPositionsControlInterface::getInputs() const 
00341 {
00342   // get positions of all joints
00343   //  convert from an array<Vector> to a flat Vector
00344   c->q.reset( c->manipulatorInterface->getInputs() );
00345   array<Vector> jointPositions( c->manipChain.getLinkOrigins(c->q) );
00346   c->linkPositions.resize(jointPositions.size()*3);
00347   for(Int j=0; j<jointPositions.size(); j++) {
00348     c->linkPositions[3*j]   = jointPositions[j][0]; // x
00349     c->linkPositions[3*j+1] = jointPositions[j][1]; // y
00350     c->linkPositions[3*j+2] = jointPositions[j][2]; // z
00351   }
00352   return c->linkPositions;
00353 }
00354 
00355 inline Int IKORController::LinkPositionsControlInterface::outputSize() const
00356 {
00357   return 0;
00358 }
00359 
00360 String IKORController::LinkPositionsControlInterface::outputName(Int i) const
00361 {
00362   throw std::out_of_range(Exception("index out of range (interface has no outputs)"));
00363 }
00364 
00365 void IKORController::LinkPositionsControlInterface::setOutput(Int i, Real value) 
00366 {
00367   throw std::out_of_range(Exception("index out of range (interface has no outputs)"));
00368 }
00369 
00370 void IKORController::LinkPositionsControlInterface::setOutputs(const Vector& values) 
00371 {
00372   if (values.size() != 0)
00373     throw std::out_of_range(Exception("dimension not equal to output dimension (0 - no outputs)"));
00374 }

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