/*! This function is the equivalent of the Grasp Force Optimization, but done with
  the quasi-static formulation cast as a Quadratic Program.
  
  It can perform four types of computation:
  - contact force existence: are there contact forces that balance out on the object
  - contact force optimization: what are the optimal contact forces (as far as possible
    from the edges of the friction cones) that balance out on the object
  - grasp force existence: are there joint forces which produce contact forces which 
    balance out on the object
  - grasp force optimization: what are the optimal joint forces, producing contact
    forces that are as far as possible from the edges of the friction cones and 
    balance out on the object.
   See individual computation routines for more details.
  
  There might exist cases of grasps that are reported as form-closed where grasp force
  existence fails, as this function also asks that the contact forces that balance
  the object must be possible to apply from actuated DOF's.
  
  For now, this function displays the computed contact forces on the contacts, 
  rather than returning them. It also copies the computed joint forces in the
  matrix \a robotTau which is assumed to be large enough for all the joints of
  the robot and use the robot's numbering scheme.
  
  Return codes: 0 is success, >0 means problem is unfeasible, no equilibrium forces
  exist; <0 means error in computation 
*/
int 
Grasp::computeQuasistaticForcesAndTorques(Matrix *robotTau, int computation)
{
	//use the pre-set list of contacts. This includes contacts on the palm, but
	//not contacts with other objects or obstacles
	std::list<Contact*> contacts;
	contacts.insert(contacts.begin(),contactVec.begin(), contactVec.end());
	//if there are no contacts we are done
	if (contacts.empty()) return 0;

        //get only the joints on chains that make contact;
	std::list<Joint*> joints = getJointsOnContactChains();

	//build the Jacobian and the other matrices that are needed.
	//this is the same as in the equilibrium function above.
	Matrix J(contactJacobian(joints, contacts));
	Matrix D(Contact::frictionForceBlockMatrix(contacts));
	Matrix F(Contact::frictionConstraintsBlockMatrix(contacts));
	Matrix R(Contact::localToWorldWrenchBlockMatrix(contacts));

	Matrix N(Contact::normalForceSumMatrix(contacts));

	//grasp map that relates contact amplitudes to object wrench G = S*R*D
	Matrix G(graspMapMatrix(R,D));

	//matrix that relates contact forces to joint torques JTD = JTran * D
	Matrix JTran(J.transposed());
	Matrix JTD(JTran.rows(), D.cols());
	matrixMultiply(JTran, D, JTD);

	// vectors of unknowns
	Matrix beta( D.cols(), 1);
	Matrix tau( (int)joints.size(), 1);

	double objVal;
	/* This is the core computation. There are many ways of combining the 
	   optimization criterion and the constraints. Four of them are presented 
	   here, each encapsulated in its own helper function.
        */

        int result;
        switch(computation)
        {
        case GRASP_FORCE_EXISTENCE:
          result = graspForceExistence(JTD, D, F, G, beta, tau, &objVal);
          break;
        case GRASP_FORCE_OPTIMIZATION:
          result = graspForceOptimization(JTD, D, F, G, beta, tau, &objVal);
          break;
        case CONTACT_FORCE_EXISTENCE:
          result = contactForceExistence(F, N, G, beta, &objVal);
          matrixMultiply(JTD, beta, tau);
          break;
        case CONTACT_FORCE_OPTIMIZATION:
          result = contactForceOptimization(F, N, G, beta, &objVal);
          matrixMultiply(JTD, beta, tau);
          break;
        default:
          DBGA("Unknown computation type requested");
          return -1;
        }

	if (result) {
		if( result > 0) {
			DBGA("Grasp: problem unfeasible");
		} else {
			DBGA("Grasp: solver error");
		}
		return result;
	}
	DBGA("Optimization solved; objective: " << objVal);

	DBGP("beta:\n" << beta);
	DBGP("tau:\n" << tau);
	DBGP("Joint forces sum: " << tau.elementSum());

	Matrix Gbeta(G.rows(), beta.cols());
	matrixMultiply(G, beta, Gbeta);
	DBGP("Total object wrench:\n" << Gbeta);

	//retrieve contact wrenches in local contact coordinate systems
	Matrix cWrenches(D.rows(), 1);
	matrixMultiply(D, beta, cWrenches);
	DBGP("Contact forces:\n " << cWrenches);

	//compute object wrenches relative to object origin and expressed in world coordinates
	Matrix objectWrenches(R.rows(), cWrenches.cols());
	matrixMultiply(R, cWrenches, objectWrenches);
	DBGP("Object wrenches:\n" << objectWrenches);

	//display them on the contacts and accumulate them on the object
	displayContactWrenches(&contacts, cWrenches);
	accumulateAndDisplayObjectWrenches(&contacts, objectWrenches);

	//set the robot joint values for the return
	std::list<Joint*>::iterator it;
	int jc;
	for(it=joints.begin(), jc=0; it!=joints.end(); it++,jc++) {
		robotTau->elem( (*it)->getNum(), 0 ) = 1.0 * tau.elem(jc,0);
	}

	//sanity check: contact forces balance joint forces

	//sanity check: resultant object wrench is 0

	return 0;
}
/*! One possible version of the GFO problem.

	Given a matrix of joint torques applied to the robot joints, this will check
	if there exists a set of legal contact forces that balance them. If so, it
	will compute the set of contact forces that adds up to the wrench of least
	magnitude on the object.

	For now, this output of this function is to set the computed contact forces
	on each contact as dynamic forces, and also to accumulate the resulting
	wrench on the object in its external wrench accumulator.

	Return codes: 0 is success, >0 means finger slip, no legal contact forces 
	exist; <0 means error in computation 
*/
int 
Grasp::computeQuasistaticForces(const Matrix &robotTau)
{
	//WARNING: for now, this ignores contacts on the palm. That might change in the future

	//for now, if the hand is touching anything other then the object, abort
	for (int c=0; c<hand->getNumChains(); c++) {
		if ( hand->getChain(c)->getNumContacts(NULL) !=
			hand->getChain(c)->getNumContacts(object) ) {
				DBGA("Hand contacts not on object");
				return 1;
			}
	}

	std::list<Contact*> contacts;
	std::list<Joint*> joints;

	bool freeChainForces = false;
	for(int c=0; c<hand->getNumChains(); c++) {
		//for now, we look at all contacts
		std::list<Contact*> chainContacts = hand->getChain(c)->getContacts(object);
		contacts.insert(contacts.end(), chainContacts.begin(), chainContacts.end());
		if (!chainContacts.empty()) {
			std::list<Joint*> chainJoints = hand->getChain(c)->getJoints();
			joints.insert(joints.end(), chainJoints.begin(), chainJoints.end());
		} else {
			//the chain has no contacts
			//check if any joint forces are not 0
			Matrix chainTau = hand->getChain(c)->jointTorquesVector(robotTau);
			//torque units should be N * 1.0e6 * mm
			if (chainTau.absMax() > 1.0e3) {
				DBGA("Joint torque " << chainTau.absMax() << " on chain " << c 
									 << " with no contacts");
				freeChainForces = true;
			}
		}
	}
	//if there are no contacts, nothing to compute!
	if (contacts.empty()) return 0;

	//assemble the joint forces matrix
	Matrix tau((int)joints.size(), 1);
	int jc; std::list<Joint*>::iterator jit;
	for (jc=0, jit = joints.begin(); jit!=joints.end(); jc++,jit++) {
		tau.elem(jc,0) = robotTau.elem( (*jit)->getNum(), 0 );
	}
	//if all the joint forces we care about are zero, do an early exit 
	//as zero contact forces are guaranteed to balance the chain
	//we should probably be able to use a much larger threshold here, if
	//units are what I think they are
	if (tau.absMax() < 1.0e-3) {
		return 0;
	}

	//if there are forces on chains with no contacts, we have no hope to balance them
	if (freeChainForces) {
		return 1;
	}

	Matrix J(contactJacobian(joints, contacts));
	Matrix D(Contact::frictionForceBlockMatrix(contacts));
	Matrix F(Contact::frictionConstraintsBlockMatrix(contacts));
	Matrix R(Contact::localToWorldWrenchBlockMatrix(contacts));

	//grasp map G = S*R*D
	Matrix G(graspMapMatrix(R, D));

	//left-hand equality matrix JTD = JTran * D
	Matrix JTran(J.transposed());
	Matrix JTD(JTran.rows(), D.cols());
	matrixMultiply(JTran, D, JTD);

	//matrix of zeroes for right-hand of friction inequality
	Matrix zeroes(Matrix::ZEROES<Matrix>(F.rows(), 1));

	//matrix of unknowns
	Matrix c_beta(D.cols(), 1);

	//bounds: all variables greater than 0
	Matrix lowerBounds(Matrix::ZEROES<Matrix>(D.cols(),1));
	Matrix upperBounds(Matrix::MAX_VECTOR(D.cols()));

	//solve QP
	double objVal;
	int result = factorizedQPSolver(G, JTD, tau, F, zeroes, lowerBounds, upperBounds, 
									c_beta, &objVal);
	if (result) {
		if( result > 0) {
			DBGP("Grasp: problem unfeasible");
		} else {
			DBGA("Grasp: QP solver error");
		}
		return result;
	}

	//retrieve contact wrenchs in local contact coordinate systems
	Matrix cWrenches(D.rows(), 1);
	matrixMultiply(D, c_beta, cWrenches);
	DBGP("Contact wrenches:\n" << cWrenches);

	//compute wrenches relative to object origin and expressed in world coordinates
	Matrix objectWrenches(R.rows(), cWrenches.cols());
	matrixMultiply(R, cWrenches, objectWrenches);
	DBGP("Object wrenches:\n" << objectWrenches);

	//display them on the contacts and accumulate them on the object
	displayContactWrenches(&contacts, cWrenches);
	accumulateAndDisplayObjectWrenches(&contacts, objectWrenches);

	//simple sanity check: JT * c = tau
	Matrix fCheck(tau.rows(), 1);
	matrixMultiply(JTran, cWrenches, fCheck);
	for (int j=0; j<tau.rows(); j++) {
		//I am not sure this works well for universal and ball joints
		double err = fabs(tau.elem(j, 0) - fCheck.elem(j,0));
		//take error as a percentage of desired force, if force is non-zero
		if ( fabs(tau.elem(j,0)) > 1.0e-2) {
			err = err / fabs(tau.elem(j, 0));
		} else {
			//for zero desired torque, out of thin air we pull an error threshold of 1.0e2
			//which is 0.1% of the normal range of torques at 1.0e6
			if (err < 1.0e2) err = 0;
		}
		// 0.1% error is considered too much
		if (  err > 1.0e-1) {
			DBGA("Desired torque not obtained on joint " << j << ", error " << err << 
				" out of " << fabs(tau.elem(j, 0)) );
			return -1;
		}
	}

	//complex sanity check: is object force same as QP optimization result?
	//this is only expected to work if all contacts are on the same object
	double* extWrench = object->getExtWrenchAcc();
	vec3 force(extWrench[0], extWrench[1], extWrench[2]);
	vec3 torque(extWrench[3], extWrench[4], extWrench[5]);
	//take into account the scaling that has taken place
	double wrenchError = objVal*1.0e-6 - (force.len_sq() + torque.len_sq()) * 1.0e6;
	//units here are N * 1.0e-6; errors should be in the range on miliN
	if (wrenchError > 1.0e3) {
		DBGA("Wrench sanity check error: " << wrenchError);
		return -1;
	}
	return 0;
}
예제 #3
0
/*! This function is the equivalent of the Grasp Force Optimization, but done with
	the quasi-static formulation cast as a Quadratic Program.

	It will attempt to compute both the feasible contact forces and joint torques
	that produce a 0 resultant wrench on the object, and keep the contact forces
	as far as possible from the boundaries of the friction cones. This implicitly
	assumes that the grasp has form-closure, in other words, some combination of 
	legal contact forces exists that produces 0 wrench on the object.

	There might exist cases of grasps that are reported as form-closed where this
	function fails, as this function also asks that the contact forces that balance
	the object must be possible to apply from actuated DOF's.

	For now, this function displays the computed contact forces on the contacts, 
	rather than returning them. It also copies the computed joint forces in the
	matrix \a robotTau which is assumed to be large enough for all the joints of
	the robot and use the robot's numbering scheme.

	Return codes: 0 is success, >0 means problem is unfeasible, no equilibrium forces
	exist; <0 means error in computation 
*/
int 
Grasp::computeQuasistaticForcesAndTorques(Matrix *robotTau, Matrix * objWrench, double * objectiveValue)
{
	//use the pre-set list of contacts. This includes contacts on the palm, but
	//not contacts with other objects or obstacles
	std::list<Contact*> contacts;
	contacts.insert(contacts.begin(),contactVec.begin(), contactVec.end());
	//if there are no contacts we are done
	if (contacts.empty()) return 0;

	//retrieve all the joints of the robot, but only if their chains have contacts on
	//them. Joints on chains with no contact have a trivial 0 solution so they only
	//make the problem larger for no good reason.
	//we could go even further and only keep the joints that come *before* the contacts
	//in the chain
	std::list<Joint*> joints;
	for (int c=0; c<hand->getNumChains(); c++) {
		if (hand->getChain(c)->getNumContacts(object) != 0) {
			std::list<Joint*> chainJoints = hand->getChain(c)->getJoints();
			joints.insert(joints.end(), chainJoints.begin(), chainJoints.end());
		}
	}

	//build the Jacobian and the other matrices that are needed.
	//this is the same as in the equilibrium function above.
	Matrix J(contactJacobian(joints, contacts));
	Matrix D(Contact::frictionForceBlockMatrix(contacts));
	Matrix F(Contact::frictionConstraintsBlockMatrix(contacts));
	Matrix R(Contact::localToWorldWrenchBlockMatrix(contacts));

	Matrix N(Contact::normalForceSumMatrix(contacts));

	//grasp map that relates contact amplitudes to object wrench G = S*R*D
	Matrix G(graspMapMatrix(R,D));

	//matrix that relates contact forces to joint torques JTD = JTran * D
	Matrix JTran(J.transposed());
	Matrix JTD(JTran.rows(), D.cols());
	matrixMultiply(JTran, D, JTD);

	// vectors of unknowns
	Matrix beta( D.cols(), 1);
	Matrix tau( (int)joints.size(), 1);

	double objVal;
	/* This is the core computation. There are many ways of combining the 
	   optimization criterion and the constraints. Four of them are presented 
	   here, each encapsulated in its own helper function.
   */

	//int result = graspForceExistence(JTD, D, F, G, beta, tau, &objVal);

	//int result = graspForceOptimization(JTD, D, F, G, beta, tau, &objVal, objWrench);

	//int result = contactForceExistence(F, N, G, beta, &objVal);
	//if(result)
	// return result;
	//matrixMultiply(JTD, beta, tau);

	int result = contactForceOptimization(F, N, G, beta, &objVal, objWrench);
	matrixMultiply(JTD, beta, tau);

	if (result) {
		if( result > 0) {
			DBGA("Grasp: problem unfeasible");
		} else {
			DBGA("Grasp: solver error");
		}
		return result;
	}
	DBGP("Optimization solved; objective: " << objVal);

	DBGP("beta:\n" << beta);
	DBGP("tau:\n" << tau);
	DBGP("Joint forces sum: " << tau.elementSum());

	Matrix Gbeta(G.rows(), beta.cols());
	matrixMultiply(G, beta, Gbeta);
	DBGP("Total object wrench:\n" << Gbeta);

	//retrieve contact wrenches in local contact coordinate systems
	Matrix cWrenches(D.rows(), 1);
	matrixMultiply(D, beta, cWrenches);
	DBGP("Contact forces:\n " << cWrenches);

	//compute object wrenches relative to object origin and expressed in world coordinates
	Matrix objectWrenches(R.rows(), cWrenches.cols());
	matrixMultiply(R, cWrenches, objectWrenches);
	DBGP("Object wrenches:\n" << objectWrenches);

	//display them on the contacts and accumulate them on the object
	displayContactWrenches(&contacts, cWrenches);
	accumulateAndDisplayObjectWrenches(&contacts, objectWrenches);
	
	//set the robot joint values for the return
	std::list<Joint*>::iterator it;
	int jc;
	for(it=joints.begin(), jc=0; it!=joints.end(); it++,jc++) {
		robotTau->elem( (*it)->getNum(), 0 ) = 1.0 * tau.elem(jc,0);
	}

	//sanity check: contact forces balance joint forces

	//sanity check: resultant object wrench is 0
	if (objectiveValue)
	  *objectiveValue = objVal;
	return 0;
}