void BallJointConstraint::updateDynamics(Eigen::MatrixXd & _J1, Eigen::VectorXd & _C, Eigen::VectorXd & _CDot, int _rowIndex) {
    getJacobian();
    _J1.block(_rowIndex, 0, 3, mBodyNode1->getSkeleton()->getNumGenCoords()) = mJ1;
    Eigen::Vector3d worldP1 = mBodyNode1->getWorldTransform() * mOffset1;
    Eigen::VectorXd qDot1 = mBodyNode1->getSkeleton()->get_dq();
    _C.segment(_rowIndex, 3) = worldP1 - mOffset2;
    _CDot.segment(_rowIndex, 3) = mJ1 * qDot1;
}
示例#2
0
void PointConstraint::updateDynamics(std::vector<Eigen::MatrixXd> & _J, Eigen::VectorXd & _C, Eigen::VectorXd & _CDot, int _rowIndex) {
    getJacobian();
    dynamics::Skeleton *skel = mBody->getSkeleton();
    _J[mSkelIndex].block(_rowIndex, 0, 3, skel->getDOF()) = mJ;
    Eigen::Vector3d worldP = mBody->getWorldTransform() * mOffset;
    Eigen::VectorXd qDot = skel->get_dq();
    _C.segment(_rowIndex, 3) = worldP - mTarget;
    _CDot.segment(_rowIndex, 3) = mJ * qDot;
}
示例#3
0
 void PointConstraint::updateDynamics(std::vector<Eigen::MatrixXd> & _J, Eigen::VectorXd & _C, Eigen::VectorXd & _CDot, int _rowIndex) {
     getJacobian();
     SkeletonDynamics *skel = (SkeletonDynamics*)mBody->getSkel();
     _J[mSkelIndex].block(_rowIndex, 0, 3, skel->getNumDofs()) = mJ;
     Vector3d worldP = xformHom(mBody->getWorldTransform(), mOffset);
     VectorXd qDot = skel->getQDotVector();
     _C.segment(_rowIndex, 3) = worldP - mTarget;
     _CDot.segment(_rowIndex, 3) = mJ * qDot;
 }
示例#4
0
double Jacobian::getManipulabilityMeasure(const Eigen::VectorXd& joint_values)
{
  ROS_ASSERT(initialized_);

  Eigen::MatrixXd jac;

  getJacobian(joint_values, jac);

  Eigen::MatrixXd JJT = jac * jac.transpose();
  return sqrt(JJT.determinant());

}
示例#5
0
void ContactDynamics::updateNBMatrices() {
    mN = MatrixXd::Zero(getNumTotalDofs(), getNumContacts());
    mB = MatrixXd::Zero(getNumTotalDofs(), getNumContacts() * getNumContactDirections());
    for (int i = 0; i < getNumContacts(); i++) {
        Contact& c = mCollisionChecker->getContact(i);
        Vector3d p = c.point;
        int skelID1 = mBodyIndexToSkelIndex[c.collisionNode1->getIndex()];
        int skelID2 = mBodyIndexToSkelIndex[c.collisionNode2->getIndex()];

        Vector3d N21 = c.normal;
        Vector3d N12 = -c.normal;
        MatrixXd B21 = getTangentBasisMatrix(p, N21);
        MatrixXd B12 = -B21;

        if (!mSkels[skelID1]->getImmobileState()) {
            int index1 = mIndices[skelID1];
            int NDOF1 = c.collisionNode1->getBodyNode()->getSkel()->getNumDofs();
            //    Vector3d N21 = c.normal;
            MatrixXd J21t = getJacobian(c.collisionNode1->getBodyNode(), p);
            mN.block(index1, i, NDOF1, 1).noalias() = J21t * N21;
            //B21 = getTangentBasisMatrix(p, N21);
            mB.block(index1, i * getNumContactDirections(), NDOF1, getNumContactDirections()).noalias() = J21t * B21;
        }

        if (!mSkels[skelID2]->getImmobileState()) {
            int index2 = mIndices[skelID2];
            int NDOF2 = c.collisionNode2->getBodyNode()->getSkel()->getNumDofs();
            //Vector3d N12 = -c.normal;
            //if (B21.rows() == 0)
            //  B12 = getTangentBasisMatrix(p, N12);
            //else
            //   B12 = -B21;
            MatrixXd J12t = getJacobian(c.collisionNode2->getBodyNode(), p);
            mN.block(index2, i, NDOF2, 1).noalias() = J12t * N12;
            mB.block(index2, i * getNumContactDirections(), NDOF2, getNumContactDirections()).noalias() = J12t * B12;

        }
    }
}
示例#6
0
    void ClosedLoopConstraint::updateDynamics(std::vector<Eigen::MatrixXd> & _J, Eigen::VectorXd & _C, Eigen::VectorXd & _CDot, int _rowIndex) {
        getJacobian();
        _J[mSkelIndex2].block(_rowIndex, 0, 3, mBody2->getSkel()->getNumDofs()).setZero();
        _J[mSkelIndex1].block(_rowIndex, 0, 3, mBody1->getSkel()->getNumDofs()) = mJ1;
        _J[mSkelIndex2].block(_rowIndex, 0, 3, mBody2->getSkel()->getNumDofs()) += mJ2;

        Vector3d worldP1 = xformHom(mBody1->getWorldTransform(), mOffset1);
        Vector3d worldP2 = xformHom(mBody2->getWorldTransform(), mOffset2);
        VectorXd qDot1 = ((SkeletonDynamics*)mBody1->getSkel())->getPoseVelocity();
        VectorXd qDot2 = ((SkeletonDynamics*)mBody2->getSkel())->getPoseVelocity();
        _C.segment(_rowIndex, 3) = worldP1 - worldP2;
        _CDot.segment(_rowIndex, 3) = mJ1 * qDot1 + mJ2 * qDot2;
    }
示例#7
0
void BallJointConstraint::updateDynamics(Eigen::MatrixXd & _J1, Eigen::MatrixXd & _J2, Eigen::VectorXd & _C, Eigen::VectorXd & _CDot, int _rowIndex) {
    getJacobian();
    _J2.block(_rowIndex, 0, 3, mBodyNode2->getSkeleton()->getNumGenCoords()).setZero();
    _J1.block(_rowIndex, 0, 3, mBodyNode1->getSkeleton()->getNumGenCoords()) = mJ1;
    _J2.block(_rowIndex, 0, 3, mBodyNode2->getSkeleton()->getNumGenCoords()) += mJ2;

    Eigen::Vector3d worldP1 = mBodyNode1->getWorldTransform() * mOffset1;
    Eigen::VectorXd qDot1 = ((dynamics::Skeleton*)mBodyNode1->getSkeleton())->getGenVels();
    Eigen::VectorXd worldP2 = mBodyNode2->getWorldTransform() * mOffset2;
    Eigen::VectorXd qDot2 = ((dynamics::Skeleton*)mBodyNode2->getSkeleton())->getGenVels();
    
    _C.segment(_rowIndex, 3) = worldP1 - worldP2;
    _CDot.segment(_rowIndex, 3) = mJ1 * qDot1 + mJ2 * qDot2;
}
示例#8
0
math::Jacobian
TemplatedJacobianNode<NodeType>::getJacobian(
    const Eigen::Vector3d& _offset,
    const Frame* _inCoordinatesOf) const
{
  if(this == _inCoordinatesOf)
    return getJacobian(_offset);
  else if(_inCoordinatesOf->isWorld())
    return getWorldJacobian(_offset);

  Eigen::Isometry3d T = getTransform(_inCoordinatesOf);
  T.translation() = - T.linear() * _offset;

  return math::AdTJac(T, static_cast<const NodeType*>(this)->getJacobian());
}
示例#9
0
void ClosedLoopConstraint::updateDynamics(std::vector<Eigen::MatrixXd>* _J,
                                          Eigen::VectorXd* _C,
                                          Eigen::VectorXd* _CDot,
                                          int _rowIndex)
{
  getJacobian();
  _J->at(mSkelIndex2).block(_rowIndex, 0, 3,
                            mBody2->getSkeleton()->getNumGenCoords()).setZero();
  _J->at(mSkelIndex1).block(_rowIndex, 0, 3,
                            mBody1->getSkeleton()->getNumGenCoords()) = mJ1;
  _J->at(mSkelIndex2).block(_rowIndex, 0, 3,
                            mBody2->getSkeleton()->getNumGenCoords()) += mJ2;

  Eigen::Vector3d worldP1 = mBody1->getWorldTransform() * mOffset1;
  Eigen::Vector3d worldP2 = mBody2->getWorldTransform() * mOffset2;
  Eigen::VectorXd qDot1 = mBody1->getSkeleton()->get_dq();
  Eigen::VectorXd qDot2 = mBody2->getSkeleton()->get_dq();
  _C->segment(_rowIndex, 3) = worldP1 - worldP2;
  _CDot->segment(_rowIndex, 3) = mJ1 * qDot1 + mJ2 * qDot2;
}
bool OrientVectorToVectorTask::getCommand(ControlModel & model, TaskCommand & command)
{
    // Get the latest joint state information
    Vector Q(model.getNumDOFs());
    Vector Qd(model.getNumDOFs());  
    model.getLatestFullState(Q, Qd);

    // Get orientation of the local body vector in the world frame
    Rbody = RigidBodyDynamics::CalcBodyWorldOrientation(model.rbdlModel(), Q, bodyId_, false);  // TODO: Use Latest State

    if (tare)
    {
        CONTROLIT_INFO_RT << "Taring the goal orientation!";
        goalVector_ = Rbody.transpose() * bodyFrameVector_;   // assumes goalVector_ is in world coordinate frame
        tare = 0;
    }
  
    // Just in case, normalize the current and goal vectors
    bodyFrameVector_.normalize();
    goalVector_.normalize();
  
    // Check if latched status has been updated
    updateLatch(&model);
  
    getJacobian(Jtloc);
  
  
    // Compute the goal vector in the frameName_ coordinate frame
    // goalHeading = goalVector_;
    paramGoalHeading->set(goalVector_); // sets member variable "goalHeading"
  
    if(frameId_ != -1) // The goal vector is in robot frame, either latched or not
    {
        if(isLatched)
            Rframe = latchedRotation;
        else
            Rframe = RigidBodyDynamics::CalcBodyWorldOrientation(model.rbdlModel(), Q, frameId_, false);  // TODO: Use Latest State
    
        goalHeading = Rframe.transpose() * goalVector_;
    }
  
    // Get the heading in the frameName_ coordinate frame
    actualHeading = Rbody.transpose() * bodyFrameVector_;
    paramActualHeading->set(actualHeading);
  
    // Compute the error (goal heading - current heading)
    /*if (goalHeading.cols() != actualHeading.cols() || goalHeading.rows() != actualHeading.rows())
    {
        CONTROLIT_ERROR << "Matrix size error:\n"
                        << "  - goalHeading =\n" << goalHeading << "\n" 
                        << "  - goalVector =\n" << goalVector_ << "\n"
                        << "  - frameId_ = " << frameId_ << "\n"
                        << "  - RFrame =\n" << Rframe << "\n"
                        << "  - actualHeading=\n" << actualHeading;
    }*/
    e0 = goalHeading - actualHeading;

    // Compute the angle between the goal heading and current heading.
    // The equation is cos^-1(goalHeading dot actualHeading / (|goalHeading| * |actualHeading|)).
    double error = std::acos(goalHeading.dot(actualHeading) / (goalHeading.norm() * actualHeading.norm()))
        * 180 / 3.141592653589793238463;
    paramErrorAngle->set(error);
  
    // Set the command type
    command.type = commandType_;
  
    // Compute the command
    // The goal velocity is zero, thus the velocity error is -Jtloc * Qd.
    controller->computeCommand(e0, -Jtloc * Qd, command.command, this);
  
    Vector base_vector;
    base_vector.setZero(3);

    Vector tran_BodyToBase = RigidBodyDynamics::CalcBodyToBaseCoordinates(model.rbdlModel(), Q, bodyId_, base_vector, false);

    // If we are able to grab the lock on visualizationPublisher,
    // publish the visualization markers.
    if (visualizationPublisher.trylock())
    {
        // Create a marker showing the goal vector
        visualizationPublisher.msg_.markers[0].header.stamp = ros::Time::now();
        visualizationPublisher.msg_.markers[0].points[0].x = tran_BodyToBase[0];
        visualizationPublisher.msg_.markers[0].points[0].y = tran_BodyToBase[1];
        visualizationPublisher.msg_.markers[0].points[0].z =tran_BodyToBase[2];

        visualizationPublisher.msg_.markers[0].points[1].x = tran_BodyToBase[0] + goalHeading(0);
        visualizationPublisher.msg_.markers[0].points[1].y = tran_BodyToBase[1] + goalHeading(1);
        visualizationPublisher.msg_.markers[0].points[1].z = tran_BodyToBase[2] + goalHeading(2);

        // Create a marker showing the current heading
        visualizationPublisher.msg_.markers[1].header.stamp = ros::Time::now();
        visualizationPublisher.msg_.markers[1].points[1].x = bodyFrameVector_(0);
        visualizationPublisher.msg_.markers[1].points[1].y = bodyFrameVector_(1);
        visualizationPublisher.msg_.markers[1].points[1].z = bodyFrameVector_(2);

        // Publish the MarkerArray
        visualizationPublisher.unlockAndPublish();

    }
  
    return true;
}
示例#11
0
//==============================================================================
void EndEffector::updateWorldJacobian() const
{
  mWorldJacobian = math::AdRJac(getWorldTransform(), getJacobian());

  mIsWorldJacobianDirty = false;
}
void JtATIController::updateHook()
{
    if(use_ft_sensor && port_ftdata.read(wrench_msg) != RTT::NewData)
        return;
    
    if(!updateState()) return;
    
    jnt_trq_cmd.setZero();
    
    if(0)
    {
        getMassMatrix(mass);
        
        id_dyn_solver->JntToMass(jnt_pos_kdl,mass_kdl);
        
        RTT::log(RTT::Warning) << "mass : \n"<<mass<<RTT::endlog();
        RTT::log(RTT::Warning) << "mass_kdl : \n"<<mass_kdl.data<<RTT::endlog();
    }
    

    if(use_ft_sensor){
        if(use_kdl){
            // remove B(q,qdot)
            jnt_vel_kdl.data.setZero();
            // Get the Wrench in the last segment's frame
            tf::wrenchMsgToKDL(wrench_msg.wrench,wrench_kdl);
            f_ext_kdl.back() = wrench_kdl;
            // Get The full dynamics with external forces
            id_rne_solver->CartToJnt(jnt_pos_kdl,jnt_vel_kdl,jnt_acc_kdl,f_ext_kdl,jnt_trq_kdl);
            // Get Joint Gravity torque
            id_dyn_solver->JntToGravity(jnt_pos_kdl,gravity_kdl);
            // remove G(q)
            jnt_trq_cmd = jnt_trq_kdl.data - gravity_kdl.data;
            RTT::log(RTT::Debug) << "Adding FT data    : \n"<<jnt_trq_cmd.transpose()<<RTT::endlog();
        
        }else{
            // Get Jacobian with KRC
            getJacobian(J_tip_base);
            getCartesianPosition(cart_pos);
            tf::poseMsgToKDL(cart_pos,tool_in_base_frame);
            tf::poseMsgToEigen(cart_pos,tool_in_base_frame_eigen);
            J_tip_base.changeBase(tool_in_base_frame.M);
            
            RTT::log(RTT::Debug) << "J : \n"<<J_tip_base.data<<RTT::endlog();
            
            
            // Get Jacobian with KDL
            jnt_to_jac_solver->JntToJac(jnt_pos_kdl,J_kdl,kdl_chain.getNrOfSegments());
            
            RTT::log(RTT::Debug) << "J_kdl : \n"<<J_kdl.data<<RTT::endlog();
            
            tf::wrenchMsgToEigen(wrench_msg.wrench,wrench);
            //tf::wrenchMsgToKDL(wrench_msg.wrench,wrench_kdl);
            wrench_kdl = tool_in_base_frame.M * wrench_kdl;
            ///tf::wrenchKDLToEigen(wrench_kdl,wrench);
            jnt_trq_cmd = J_tip_base.data.transpose() * wrench;
        
        }
    }
    
    if(use_kdl_gravity)
    {
        getGravityTorque(jnt_grav);
        id_dyn_solver->JntToGravity(jnt_pos_kdl,gravity_kdl);
        jnt_trq_cmd += kg.asDiagonal() * gravity_kdl.data - jnt_grav;
        RTT::log(RTT::Debug) << "Adding gravity    : \n"<<(kg.asDiagonal() * gravity_kdl.data - jnt_grav).transpose()<<RTT::endlog();
    }
    
    if(compensate_coriolis)
    {
        id_dyn_solver->JntToCoriolis(jnt_pos_kdl,jnt_vel_kdl,coriolis_kdl);
        jnt_trq_cmd -= coriolis_kdl.data.asDiagonal()*jnt_vel;
        RTT::log(RTT::Debug) << "Removing Coriolis    : \n"<<(coriolis_kdl.data.asDiagonal()*jnt_vel).transpose()<<RTT::endlog();
    }
    
    if(add_damping)
    {
        jnt_trq_cmd -= kd.asDiagonal() * jnt_vel;
        RTT::log(RTT::Debug) << "Adding damping    : \n"<<-(kd.asDiagonal() * jnt_vel).transpose()<<RTT::endlog();
    }

    RTT::log(RTT::Debug) << "jnt_trq_cmd    : \n"<<jnt_trq_cmd.transpose()<<RTT::endlog(); 

    sendJointTorque(jnt_trq_cmd);
}
示例#13
0
void ChompOptimizer::calculateCollisionIncrements()
{
  double potential;
  double vel_mag_sq;
  double vel_mag;
  Eigen::Vector3d potential_gradient;
  Eigen::Vector3d normalized_velocity;
  Eigen::Matrix3d orthogonal_projector;
  Eigen::Vector3d curvature_vector;
  Eigen::Vector3d cartesian_gradient;


  collision_increments_.setZero(num_vars_free_, num_joints_);

  int startPoint = 0;
  int endPoint = free_vars_end_;

  // In stochastic descent, simply use a random point in the trajectory, rather than all the trajectory points.
  // This is faster and guaranteed to converge, but it may take more iterations in the worst case.
  if(parameters_->getUseStochasticDescent())
  {
    startPoint =  (int)(((double)random() / (double)RAND_MAX)*(free_vars_end_ - free_vars_start_) + free_vars_start_);
    if(startPoint < free_vars_start_) startPoint = free_vars_start_;
    if(startPoint > free_vars_end_) startPoint = free_vars_end_;
    endPoint = startPoint;
  }
  else
  {
    startPoint = free_vars_start_;
  }

  for(int i = startPoint; i <= endPoint; i++)
  {
    for(int j = 0; j < num_collision_points_; j++)
    {
      potential = collision_point_potential_[i][j];

      if(potential < 0.0001)
        continue;

      potential_gradient = -collision_point_potential_gradient_[i][j];

      vel_mag = collision_point_vel_mag_[i][j];
      vel_mag_sq = vel_mag * vel_mag;

      // all math from the CHOMP paper:

      normalized_velocity = collision_point_vel_eigen_[i][j] / vel_mag;
      orthogonal_projector = Eigen::Matrix3d::Identity() - (normalized_velocity * normalized_velocity.transpose());
      curvature_vector = (orthogonal_projector * collision_point_acc_eigen_[i][j]) / vel_mag_sq;
      cartesian_gradient = vel_mag * (orthogonal_projector * potential_gradient - potential * curvature_vector);

      // pass it through the jacobian transpose to get the increments
      getJacobian(i, collision_point_pos_eigen_[i][j], collision_point_joint_names_[i][j] ,jacobian_);

      if(parameters_->getUsePseudoInverse())
      {
        calculatePseudoInverse();
        collision_increments_.row(i - free_vars_start_).transpose() -= jacobian_pseudo_inverse_ * cartesian_gradient;
      }
      else
      {
        collision_increments_.row(i - free_vars_start_).transpose() -= jacobian_.transpose() * cartesian_gradient;
      }

      /*
        if(point_is_in_collision_[i][j])
        {
        break;
        }
      */
    }
  }
  //cout << collision_increments_ << endl;
}
示例#14
0
CIKChain::CIKChain(CIKDummy* tip,float interpolFact,int jointNbToExclude)
{
	tooltip=tip;
	chainIsValid=true;
	// interpolFact is the interpolation factor we use to compute the target pose:
	// interpolPose=tooltipPose*(1-interpolFact)+targetPose*interpolFact
	// We get the jacobian and the rowJointIDs:
	C4X4Matrix oldMatr;
	int theConstraints=tip->constraints;
	tip->baseReorient.setIdentity();
	CMatrix* Ja=NULL;

	if (tip->loopClosureDummy)
	{
		// The purpose of the following code is to have tip and target dummies reoriented
		// and the appropriate constraints calculated automatically (only for loop closure dummies!)
		tip->constraints=0;
		int posDimensions=0;
		int orDimensions=0;
		C3Vector firstJointZAxis(0.0f,0.0f,1.0f);
		C4X4Matrix firstJointCumul;
		// here we reorient tip and targetCumulativeMatrix
		// 1. We find the first revolute joint:
		CIKObject* iterat=tip->parent;
		while (iterat!=NULL)
		{
			if ( (iterat->objectType==IK_JOINT_TYPE)&&((CIKJoint*)iterat)->revolute&&((CIKJoint*)iterat)->active )
				break;
			iterat=iterat->parent;
		}
		if (iterat!=NULL)
		{ // We have the first revolute joint from tip
			orDimensions=1;
			CIKObject* firstJoint=iterat;
			firstJointCumul=C4X4Matrix(firstJoint->getCumulativeTransformationPart1(true).getMatrix());
			firstJointZAxis=firstJointCumul.M.axis[2];
			C3Vector normalVect;
			// We search for a second revolute joint which is not aligned with the first one:
			iterat=iterat->parent;
			while (iterat!=NULL)
			{
				if ( (iterat->objectType==IK_JOINT_TYPE)&&((CIKJoint*)iterat)->revolute&&((CIKJoint*)iterat)->active )
				{
					C4X4Matrix secondJointCumul(iterat->getCumulativeTransformationPart1(true).getMatrix());
					C3Vector secondJointZAxis(secondJointCumul.M.axis[2]);
					if (fabs(firstJointZAxis*secondJointZAxis)<0.999999f) // Approx. 0.08 degrees
					{
						normalVect=(firstJointZAxis^secondJointZAxis).getNormalized();
						if (firstJointZAxis*secondJointZAxis<0.0f)
							secondJointZAxis=secondJointZAxis*-1.0f;
						firstJointZAxis=((firstJointZAxis+secondJointZAxis)/2.0f).getNormalized();
						break;
					}
				}
				iterat=iterat->parent;
			}
			if (iterat!=NULL)
			{
				orDimensions=2;
				// We search for a third revolute joint which is not orthogonal with normalVect:
				iterat=iterat->parent;
				while (iterat!=NULL)
				{
					if ( (iterat->objectType==IK_JOINT_TYPE)&&((CIKJoint*)iterat)->revolute&&((CIKJoint*)iterat)->active )
					{
						C4X4Matrix thirdJointCumul(iterat->getCumulativeTransformationPart1(true).getMatrix());
						C3Vector thirdJointZAxis(thirdJointCumul.M.axis[2]);
						if (fabs(normalVect*thirdJointZAxis)>0.0001f) // Approx. 0.005 degrees
						{
							orDimensions=3;
							break;
						}
					}
					iterat=iterat->parent;
				}
			}
		}			
		if ( (orDimensions==1)||(orDimensions==2) )
		{
			// We align the tip dummy's z axis with the joint axis 
			// (and do the same transformation to targetCumulativeMatrix)

			C4Vector rot(C4X4Matrix(firstJointZAxis).M.getQuaternion());
			C4Vector tipParentInverse(tip->getParentCumulativeTransformation(true).Q.getInverse());
			C4Vector tipNewLocal(tipParentInverse*rot);
			C4Vector postTr(tip->getLocalTransformation(true).Q.getInverse()*tipNewLocal);
			tip->transformation.Q=tipNewLocal;
			C7Vector postTr2;
			postTr2.setIdentity();
			postTr2.Q=postTr;
			tip->targetCumulativeTransformation=tip->targetCumulativeTransformation*postTr2;
		}
		Ja=getJacobian(tip,oldMatr,rowJoints,jointNbToExclude);
		C3Vector posV;
		for (int i=0;i<Ja->cols;i++)
		{
			// 1. Position space:
			C3Vector vc((*Ja)(0,i),(*Ja)(1,i),(*Ja)(2,i));
			float l=vc.getLength();
			if (l>0.0001f) // 0.1 mm
			{
				vc=vc/l;
				if (posDimensions==0)
				{
					posV=vc;
					posDimensions++;
				}
				else if (posDimensions==1)
				{
					if (fabs(posV*vc)<0.999999f) // Approx. 0.08 degrees
					{
						posV=(posV^vc).getNormalized();
						posDimensions++;
					}
				}
				else if (posDimensions==2)
				{
					if (fabs(posV*vc)>0.0001f) // Approx. 0.005 degrees
						posDimensions++;
				}
			}
		}
		if (posDimensions!=3)
		{
			if (posDimensions!=0)
			{
				C4X4Matrix aligned(posV);
				tip->baseReorient=aligned.getInverse().getTransformation();
				for (int i=0;i<Ja->cols;i++)
				{
					posV(0)=(*Ja)(0,i);
					posV(1)=(*Ja)(1,i);
					posV(2)=(*Ja)(2,i);
					posV=tip->baseReorient.Q*posV; // baseReorient.X is 0 anyway...
					(*Ja)(0,i)=posV(0);
					(*Ja)(1,i)=posV(1);
					(*Ja)(2,i)=posV(2);
				}
				oldMatr=tip->baseReorient.getMatrix()*oldMatr;
			
				if (posDimensions==1)
					tip->constraints+=IK_Z_CONSTRAINT;
				else
					tip->constraints+=(IK_X_CONSTRAINT+IK_Y_CONSTRAINT);
			}
		}
		else
			tip->constraints+=(IK_X_CONSTRAINT+IK_Y_CONSTRAINT+IK_Z_CONSTRAINT);

		int doF=Ja->cols;
		if (orDimensions==1)
		{
			if (doF-posDimensions>=1)
				tip->constraints+=IK_GAMMA_CONSTRAINT;
		}
		else if (orDimensions==2)
		{
			if (doF-posDimensions>=1) // Is this correct?
				tip->constraints+=IK_GAMMA_CONSTRAINT;
		}
		else if (orDimensions==3)
		{
			if (doF-posDimensions>=3)
				tip->constraints+=(IK_ALPHA_BETA_CONSTRAINT|IK_GAMMA_CONSTRAINT);
		}
		
		theConstraints=tip->constraints;
	}
	else
		Ja=getJacobian(tip,oldMatr,rowJoints,jointNbToExclude);

	if (Ja==NULL)
	{ // Error or not enough joints (effJoint=joints-jointNbToExclude) to get a Jacobian
		delete Ja;
		// We create dummy objects (so that we don't get an error when destroyed)
		matrix=new CMatrix(0,0);
		errorVector=new CMatrix(0,1);
		chainIsValid=false;
		return;
	}
	// oldMatr now contains the cumulative transf. matr. of tooltip relative to base
	C4X4Matrix oldMatrInv(oldMatr.getInverse());
	int doF=Ja->cols;
	int equationNumber=0;

	C4X4Matrix m;
	C4X4Matrix targetCumulativeMatrix((tip->baseReorient*tip->targetCumulativeTransformation).getMatrix());
	m.buildInterpolation(oldMatr,targetCumulativeMatrix,interpolFact);
	// We prepare matrix and errorVector and their respective sizes:
	if (theConstraints&IK_X_CONSTRAINT)
		equationNumber++;
	if (theConstraints&IK_Y_CONSTRAINT)
		equationNumber++;
	if (theConstraints&IK_Z_CONSTRAINT)
		equationNumber++;
	if (theConstraints&IK_ALPHA_BETA_CONSTRAINT)
		equationNumber=equationNumber+2;
	if (theConstraints&IK_GAMMA_CONSTRAINT)
		equationNumber++;
	matrix=new CMatrix(equationNumber,doF);
	errorVector=new CMatrix(equationNumber,1);
	// We set up the position/orientation errorVector and the matrix:
	
	float positionWeight=1.0f;
	float orientationWeight=1.0f;
	int pos=0;
	if (theConstraints&IK_X_CONSTRAINT)
	{
		for (int i=0;i<doF;i++)
			(*matrix)(pos,i)=(*Ja)(0,i);
		(*errorVector)(pos,0)=(m.X(0)-oldMatr.X(0))*positionWeight;
		pos++;
	}
	if (theConstraints&IK_Y_CONSTRAINT)
	{
		for (int i=0;i<doF;i++)
			(*matrix)(pos,i)=(*Ja)(1,i);
		(*errorVector)(pos,0)=(m.X(1)-oldMatr.X(1))*positionWeight;
		pos++;
	}
	if (theConstraints&IK_Z_CONSTRAINT)
	{
		for (int i=0;i<doF;i++)
			(*matrix)(pos,i)=(*Ja)(2,i);
		(*errorVector)(pos,0)=(m.X(2)-oldMatr.X(2))*positionWeight;
		pos++;
	}

	if (theConstraints&IK_ALPHA_BETA_CONSTRAINT)
	{
		for (int i=0;i<doF;i++)
		{
			(*matrix)(pos,i)=(*Ja)(3,i);
			(*matrix)(pos+1,i)=(*Ja)(4,i);
		}
		C4X4Matrix diff(oldMatrInv*m);
		C3Vector euler(diff.M.getEulerAngles());
		(*errorVector)(pos,0)=euler(0)*orientationWeight/IK_DIVISION_FACTOR;
		(*errorVector)(pos+1,0)=euler(1)*orientationWeight/IK_DIVISION_FACTOR;
		pos=pos+2;
	}
	if (theConstraints&IK_GAMMA_CONSTRAINT)
	{
		for (int i=0;i<doF;i++)
			(*matrix)(pos,i)=(*Ja)(5,i);
		C4X4Matrix diff(oldMatrInv*m);
		C3Vector euler(diff.M.getEulerAngles());
		(*errorVector)(pos,0)=euler(2)*orientationWeight/IK_DIVISION_FACTOR;
		pos++;
	}

	delete Ja; // We delete the jacobian!
}