/*! Adds a virtual contact on the body \a body1, which is assumed to be the \a l-th link on the \a f-th finger of a robot. Works by first creating a traditional contact, then converting it to a virtual contact. The whole VirtualContact scheme is in bad need of an overhaul. */ void addVirtualContacts(Body *body1, int f, int l, Body *body2, ContactReport &contactSet, bool softContactsOn ) { if ( softContactsOn && body1->isElastic() ) { findSoftNeighborhoods( body1, body2, contactSet ); mergeSoftNeighborhoods(body1, body2, contactSet); } ContactReport::iterator cp; for (cp=contactSet.begin(); cp!=contactSet.end(); cp++) { Contact *c1; if ( softContactsOn && body1->isElastic() ) { c1 = new SoftContact( body1, body2, cp->b1_pos, cp->b1_normal, &(cp->nghbd1) ); c1->setMate(NULL); ((SoftContact *)c1)->setUpFrictionEdges(); } else { c1 = new PointContact(body1, body2, cp->b1_pos, cp->b1_normal); c1->setMate(NULL); } VirtualContact *vc = new VirtualContact(f, l, c1); vc->setBody(body1); body1->addVirtualContact(vc); delete c1; } }
/*! This formulation combines virtual contact energy with autograsp energy. Virtual contact energy is used to "guide" initial stages of the search and to see if we should even bother computing autograsp quality. Autograsp is a couple of orders of magnitude higher and so should work very well with later stages of the sim ann search */ double GuidedAutoGraspQualityEnergy::energy() const { //first compute regular contact energy; also count how many links are "close" to the object VirtualContact *contact; vec3 p, n, cn; double virtualError = 0; int closeContacts = 0; //collect virtual contacts first mHand->getGrasp()->collectVirtualContacts(); for (int i = 0; i < mHand->getGrasp()->getNumContacts(); i++) { contact = (VirtualContact *)mHand->getGrasp()->getContact(i); contact->getObjectDistanceAndNormal(mObject, &p, &n); double dist = p.len(); if ((-1.0 * p) % n < 0) { dist = -dist; } //BEST WORKING VERSION, strangely enough virtualError += fabs(dist); cn = -1.0 * contact->getWorldNormal(); double d = 1 - cn % n; virtualError += d * 100.0 / 2.0; if (fabs(dist) < 20 && d < 0.3) { closeContacts++; } } virtualError /= mHand->getGrasp()->getNumContacts(); //if more than 2 links are "close" go ahead and compute the true quality double volQuality = 0, epsQuality = 0; if (closeContacts >= 2) { mHand->autoGrasp(false, 1.0); //now collect the true contacts; mHand->getGrasp()->collectContacts(); if (mHand->getGrasp()->getNumContacts() >= 4) { mHand->getGrasp()->updateWrenchSpaces(); volQuality = mVolQual->evaluate(); epsQuality = mEpsQual->evaluate(); if (epsQuality < 0) { epsQuality = 0; } //QM returns -1 for non-FC grasps } DBGP("Virtual error " << virtualError << " and " << closeContacts << " close contacts."); DBGP("Volume quality: " << volQuality << " Epsilon quality: " << epsQuality); } //now add the two such that the true quality is a couple of orders of magn. bigger than virtual quality double q; if (volQuality == 0) { q = virtualError; } else { q = virtualError - volQuality * 1.0e3; } if (volQuality || epsQuality) {DBGP("Final quality: " << q);} //DBGP("Final value: " << q << std::endl); return q; }
double ContactEnergy::energy() const { /* this is if we don't want to use pre-specified contacts, but rather the closest points between each link and the object all iterations. Not necessarily needed for contact energy, but useful for GQ energy */ if (mContactType == CONTACT_LIVE && mType != ENERGY_AUTOGRASP_QUALITY && mType != ENERGY_STRICT_AUTOGRASP) { mHand->getWorld()->findVirtualContacts(mHand, mObject); DBGP("Live contacts computation"); } mHand->getGrasp()->collectVirtualContacts(); //DBGP("Contact energy computation") //average error per contact VirtualContact *contact; vec3 p, n, cn; double totalError = 0; for (int i = 0; i < mHand->getGrasp()->getNumContacts(); i++) { contact = (VirtualContact *)mHand->getGrasp()->getContact(i); contact->getObjectDistanceAndNormal(mObject, &p, NULL); double dist = p.len(); //this should never happen anymore since we're never inside the object //if ( (-1.0 * p) % n < 0) dist = -dist; //BEST WORKING VERSION, strangely enough totalError += fabs(dist); //let's try this some more //totalError += distanceFunction(dist); //cn = -1.0 * contact->getWorldNormal(); //new version cn = contact->getWorldNormal(); n = normalise(p); double d = 1 - cn % n; totalError += d * 100.0 / 2.0; } totalError /= mHand->getGrasp()->getNumContacts(); //DBGP("Contact energy: " << totalError); return totalError; }
double PotentialQualityEnergy::energy() const { mHand->getGrasp()->collectVirtualContacts(); bool verbose = false; VirtualContact *contact; vec3 p,n,cn; int count = 0; //DBGP("Potential quality energy computation") for (int i=0; i<mHand->getGrasp()->getNumContacts(); i++) { contact = (VirtualContact*)mHand->getGrasp()->getContact(i); contact->computeWrenches(true, false); contact->getObjectDistanceAndNormal(mObject, &p, NULL); n= contact->getWorldNormal(); double dist = p.len(); p = normalise(p); //idiot programmer forgot to normalise double cosTheta = n % p; double factor = potentialQualityScalingFunction(dist, cosTheta); if (verbose) { fprintf(stderr,"VC %d on finger %d link %d\n",i,contact->getFingerNum(), contact->getLinkNum()); fprintf(stderr,"Distance %f cosTheta %f\n",dist,cosTheta); fprintf(stderr,"Scaling factor %f\n\n",factor); } contact->scaleWrenches( factor ); if (factor > 0.25) { count++; contact->mark(true); } else contact->mark(false); } double gq = -1; //to make computations more efficient, we only use a 3D approximation //of the 6D wrench space std::vector<int> forceDimensions(6,0); forceDimensions[0] = forceDimensions[1] = forceDimensions[2] = 1; if (count >= 3) { mHand->getGrasp()->updateWrenchSpaces(forceDimensions); gq = mEpsQual->evaluate(); } if (verbose) { fprintf(stderr,"Quality: %f\n\n",gq); } if (count) { DBGP("Count: " << count << "; Gq: " << gq << ";"); } return -gq; return 10; }
/* Loads virtual contacts from a file for a single kinematic chain. * *@param finger - The kinematic chain describing the finger *@param filename - The file containing the virtual contacts *@param fingerNumber - This is currently only used as a sanity check. a finger number < 0 is an error condition. */ bool EigenHandLoader::loadContactData(KinematicChain * finger, QString filename, int fingerNumber) { // Open the file FILE *fp = fopen(filename.latin1(), "r"); if (!fp) { std::cout<< "Could not open contact file " << filename.latin1(); return 0; } int numContacts; VirtualContact *newContact; fscanf(fp,"%d",&numContacts); for (int i=0; i<numContacts; i++) { newContact = new VirtualContact(); newContact->readFromFile(fp); newContact->setFingerNum(fingerNumber); int f = fingerNumber; int l = newContact->getLinkNum(); if ( f >= 0) { newContact->setBody(finger->getLink(l) ); finger->getLink(l)->addVirtualContact( newContact ); } else { fprintf(stderr,"Wrong finger number on contact!!!\n"); delete newContact; continue; } newContact->computeWrenches(false,false); } return 1; }