//Write void urdfLink::createLink(bool hideCollisionLinks,bool convexDecomposeNonConvexCollidables,bool createVisualIfNone,bool& showConvexDecompositionDlg) { std::string txt("Creating link '"+name+"'..."); printToConsole(txt.c_str()); //visuals.clear(); // Visuals for (int i=0; i<visuals.size(); i++) { urdfElement &visual = visuals[i]; if(!visual.meshFilename.empty()) { std::string fname(visual.meshFilename); bool exists=true; bool useAlt=false; if (!simDoesFileExist(fname.c_str())) { fname=visual.meshFilename_alt; exists=simDoesFileExist(fname.c_str()); useAlt=true; } if (!exists) printToConsole("ERROR: the mesh file could not be found."); else visual.n = simImportShape(visual.meshExtension,fname.c_str(),0,0.0001f,1.0); if (!visual.n) { if (!useAlt) txt="ERROR: failed to create the mesh '"+visual.meshFilename+"' with extension type "+boost::lexical_cast<std::string>(visual.meshExtension); else txt="ERROR: failed to create the mesh '"+visual.meshFilename+"' or '"+visual.meshFilename_alt+"' with extension type "+boost::lexical_cast<std::string>(visual.meshExtension); printToConsole(txt.c_str()); } else visual.n = scaleShapeIfRequired(visual.n,visual.mesh_scaling); } else if (!isArrayEmpty(visual.sphere_size)) visual.n = simCreatePureShape( 1,1+2+16, visual.sphere_size, mass, NULL); else if (!isArrayEmpty(visual.cylinder_size)) visual.n = simCreatePureShape( 2,1+2+16, visual.cylinder_size, mass, NULL); else if (!isArrayEmpty(visual.box_size)) visual.n = simCreatePureShape( 0,1+2+16, visual.box_size, mass, NULL); } //collisions.clear(); //mass=0.1; //collision for (int i=0; i<collisions.size(); i++) { urdfElement &collision = collisions[i]; if(!collision.meshFilename.empty()) { std::string fname(collision.meshFilename); bool exists=true; bool useAlt=false; if (!simDoesFileExist(fname.c_str())) { fname=collision.meshFilename_alt; exists=simDoesFileExist(fname.c_str()); useAlt=true; } if (!exists) printToConsole("ERROR: the mesh file could not be found"); else collision.n = simImportShape(collision.meshExtension,fname.c_str(),0,0.0001f,1.0); if (collision.n == -1) { if (!useAlt) txt="ERROR: failed to create the mesh '"+collision.meshFilename+"' with extension type "+boost::lexical_cast<std::string>(collision.meshExtension); else txt="ERROR: failed to create the mesh '"+collision.meshFilename+"' or '"+collision.meshFilename_alt+"' with extension type "+boost::lexical_cast<std::string>(collision.meshExtension); printToConsole(txt.c_str()); } else { collision.n=scaleShapeIfRequired(collision.n,collision.mesh_scaling); if (createVisualIfNone&&(visuals.size()==0)) { // We create a visual from the collision shape (before it gets morphed hereafter): simRemoveObjectFromSelection(sim_handle_all,-1); simAddObjectToSelection(sim_handle_single,collision.n); simCopyPasteSelectedObjects(); addVisual(); currentVisual().n = simGetObjectLastSelection(); } int p; int convInts[5]={1,500,200,0,0}; // 3rd value from 100 to 500 on 5/2/2014 float convFloats[5]={100.0f,30.0f,0.25f,0.0f,0.0f}; if ( convexDecomposeNonConvexCollidables&&(simGetObjectIntParameter(collision.n,3017,&p)>0)&&(p==0) ) { int aux=1+4+8+16+64; if (showConvexDecompositionDlg) aux=1+2+8+16+64; showConvexDecompositionDlg=false; simConvexDecompose(collision.n,aux,convInts,convFloats); // we generate convex shapes! } simSetObjectIntParameter(collision.n,3003,!inertiaPresent); // we make it non-static if there is an inertia simSetObjectIntParameter(collision.n,3004,1); // we make it respondable since it is a collision object } } else if (!isArrayEmpty(collision.sphere_size)) collision.n = simCreatePureShape( 1,1+2+4+8+16*(!inertiaPresent), collision.sphere_size, mass, NULL); else if (!isArrayEmpty(collision.cylinder_size)) collision.n = simCreatePureShape( 2,1+2+4+8+16*(!inertiaPresent), collision.cylinder_size, mass, NULL); else if (!isArrayEmpty(collision.box_size)) collision.n = simCreatePureShape( 0,1+2+4+8+16*(!inertiaPresent), collision.box_size, mass, NULL); } // Hack to draw COM in the collision layer /* addCollision(); currentCollision().xyz[0] = inertial_xyz[0]; currentCollision().xyz[1] = inertial_xyz[1]; currentCollision().xyz[0] = inertial_xyz[2]; currentCollision().rpy[0] = 1.5; float dummySize[3]={0.01f,0.01f,0.01f}; currentCollision().n = simCreatePureShape( 1,1+2+16, dummySize, mass, NULL); */ // Grouping collisions shapes nLinkCollision = groupShapes(collisions); // Inertia if (inertiaPresent) { C3Vector euler; if (nLinkCollision==-1) { // we do not have a collision object. Let's create a dummy collision object, since inertias can't exist on their own in V-REP: float dummySize[3]={0.01f,0.01f,0.01f}; //nLinkCollision = simCreatePureShape( 1,1+2+4, dummySize, mass, NULL); // we make it non-respondable! nLinkCollision = simCreatePureShape( 1,1+2+16, dummySize, mass, NULL); } C7Vector inertiaFrame; inertiaFrame.X.set(inertial_xyz); inertiaFrame.Q=getQuaternionFromRpy(inertial_rpy); //simSetObjectPosition(nLinkCollision,-1,inertiaFrame.X.data); //C7Vector collisionFrame; //collisionFrame.X.set(collision_xyz); //collisionFrame.Q=getQuaternionFromRpy(collision_rpy); C7Vector collisionFrame; simGetObjectPosition(nLinkCollision,-1,collisionFrame.X.data); simGetObjectOrientation(nLinkCollision,-1,euler.data); collisionFrame.Q.setEulerAngles(euler); //C4X4Matrix x((collisionFrame.getInverse()*inertiaFrame).getMatrix()); C4X4Matrix x(inertiaFrame.getMatrix()); float i[12]={x.M(0,0),x.M(0,1),x.M(0,2),x.X(0),x.M(1,0),x.M(1,1),x.M(1,2),x.X(1),x.M(2,0),x.M(2,1),x.M(2,2),x.X(2)}; simSetShapeMassAndInertia(nLinkCollision,mass,inertia,C3Vector::zeroVector.data,i); //std::cout << "Mass: " << mass << std::endl; } else { if (nLinkCollision!=-1) { std::string txt("ERROR: found a collision object without inertia data for link '"+ name+"'. Is that link meant to be static?"); printToConsole(txt.c_str()); } } if (createVisualIfNone&&(visuals.size()==0)&&(nLinkCollision!=-1)) { // We create a visual from the collision shape (meshes were handled earlier): addVisual(); urdfElement &visual = currentVisual(); simRemoveObjectFromSelection(sim_handle_all,-1); simAddObjectToSelection(sim_handle_single,nLinkCollision); simCopyPasteSelectedObjects(); visual.n=simGetObjectLastSelection(); simSetObjectIntParameter(visual.n,3003,1); // we make it static since only visual simSetObjectIntParameter(visual.n,3004,0); // we make it non-respondable since only visual } // Set the respondable mask: if (nLinkCollision!=-1) simSetObjectIntParameter(nLinkCollision,3019,0xff00); // colliding with everything except with other objects in that tree hierarchy // Grouping shapes nLinkVisual = groupShapes(visuals); // Set the names, visibility, etc.: if (nLinkVisual!=-1) { setVrepObjectName(nLinkVisual,std::string(name+"_visual").c_str()); const float specularDiffuse[3]={0.3f,0.3f,0.3f}; if (nLinkCollision!=-1) { // if we have a collision object, we attach the visual object to it, then forget the visual object C7Vector collisionFrame; C3Vector euler; simGetObjectPosition(nLinkCollision,-1,collisionFrame.X.data); simGetObjectOrientation(nLinkCollision,-1,euler.data); collisionFrame.Q.setEulerAngles(euler); C7Vector visualFrame; simGetObjectPosition(nLinkVisual,-1,visualFrame.X.data); simGetObjectOrientation(nLinkVisual,-1,euler.data); visualFrame.Q.setEulerAngles(euler); C7Vector x(collisionFrame.getInverse()*visualFrame); simSetObjectPosition(nLinkVisual,-1,x.X.data); simSetObjectOrientation(nLinkVisual,-1,x.Q.getEulerAngles().data); simSetObjectParent(nLinkVisual,nLinkCollision,0); } } if (nLinkCollision!=-1) { setVrepObjectName(nLinkCollision,std::string(name+"_respondable").c_str()); if (hideCollisionLinks) simSetObjectIntParameter(nLinkCollision,10,256); // we "hide" that object in layer 9 } }
bool CGeometricConstraintSolver::solve(CIKGraphObjCont& graphContainer,SGeomConstrSolverParam& parameters) { if (graphContainer.identifyElements()==0) return(false); // Nothing to solve (no active joint in the mechanism) graphContainer.putElementsInPlace(); // We create a branched tree, where each extremity has a tip dummy // (which will later be constrained to its respective target dummy) CIKGraphObject* baseIKGraphObject=graphContainer.getBaseObject(); CIKGraphNode* graphIterator=baseIKGraphObject; CIKGraphNode* previousPosition=NULL; CIKGraphNode* nextPosition=NULL; C7Vector localTransformation; localTransformation.setIdentity(); CIKObjCont ikObjs; CIKJoint* lastJoint=NULL; CIKJoint* treeHandle=NULL; // Some precalculations of some fixed rotations: C4X4Matrix tmpRot; tmpRot.setIdentity(); tmpRot.M(0,0)=-1.0f; tmpRot.M(2,2)=-1.0f; C7Vector rotY180(tmpRot.getTransformation()); tmpRot.M.clear(); tmpRot.M(0,0)=1.0f; tmpRot.M(2,1)=1.0f; tmpRot.M(1,2)=-1.0f; C7Vector rotX90(tmpRot.getTransformation().Q,C3Vector(0.0f,0.0f,0.0f)); tmpRot.M.clear(); tmpRot.M(2,0)=-1.0f; tmpRot.M(1,1)=1.0f; tmpRot.M(0,2)=1.0f; C7Vector rotY90(tmpRot.getTransformation().Q,C3Vector(0.0f,0.0f,0.0f)); tmpRot.M.clear(); tmpRot.M(1,0)=1.0f; tmpRot.M(0,1)=-1.0f; tmpRot.M(2,2)=1.0f; C7Vector rotZ90(tmpRot.getTransformation().Q,C3Vector(0.0f,0.0f,0.0f)); std::vector<CIKGraphNode*> graphObjectsToBeExplored; graphObjectsToBeExplored.push_back(baseIKGraphObject); std::vector<CIKJoint*> lastJoints; lastJoints.push_back(NULL); std::vector<CIKGraphNode*> previousPositions; previousPositions.push_back(NULL); std::vector<C7Vector> localTransformations; localTransformations.push_back(localTransformation); int explorationID=0; while (graphObjectsToBeExplored.size()!=0) { graphIterator=graphObjectsToBeExplored.back(); graphObjectsToBeExplored.pop_back(); lastJoint=lastJoints.back(); lastJoints.pop_back(); previousPosition=previousPositions.back(); previousPositions.pop_back(); localTransformation=localTransformations.back(); localTransformations.pop_back(); bool doIt=(graphIterator->explorationID==-1); bool goingDown=false; bool closeComplexLoop=false; while (doIt) { if (graphIterator->explorationID==-1) graphIterator->explorationID=explorationID; explorationID++; C7Vector previousCT; if (previousPosition!=NULL) { if (previousPosition->type==IK_GRAPH_JOINT_TYPE) previousCT=((CIKGraphObject*)graphIterator)->cumulativeTransformation; else previousCT=((CIKGraphObject*)previousPosition)->cumulativeTransformation; } else { previousCT=baseIKGraphObject->cumulativeTransformation; localTransformation=previousCT; } if (graphIterator->type==IK_GRAPH_JOINT_TYPE) { // Joint: we have to introduce a joint CIKGraphJoint* graphJoint=(CIKGraphJoint*)graphIterator; if (!graphJoint->disabled) { C7Vector sphTr; sphTr.setIdentity(); sphTr.Q=graphJoint->sphericalTransformation; CIKJoint* newIKJoint; if (graphJoint->jointType==IK_GRAPH_SPHERICAL_JOINT_TYPE) { int dataValueBase=10*graphJoint->nodeID; CIKJoint* avatarParent; if (graphJoint->topObject==(CIKGraphObject*)previousPosition) { // From tip to base C7Vector rel(localTransformation*rotY180); newIKJoint=new CIKJoint(graphJoint,rel,false,false); if (lastJoint==NULL) { treeHandle=newIKJoint; lastJoint=treeHandle; ikObjs.addRoot(lastJoint); } else { ikObjs.addChild(lastJoint,newIKJoint); lastJoint=newIKJoint; } avatarParent=ikObjs.getJointWithData(dataValueBase+3); if (avatarParent!=NULL) // This joint is used twice (going up and going down) avatarParent->addAvatar(lastJoint); lastJoint->data=dataValueBase+3; rel=rotX90; newIKJoint=new CIKJoint(graphJoint,rel,false,false); ikObjs.addChild(lastJoint,newIKJoint); lastJoint=newIKJoint; avatarParent=ikObjs.getJointWithData(dataValueBase+2); if (avatarParent!=NULL) // This joint is used twice (going up and going down) avatarParent->addAvatar(lastJoint); lastJoint->data=dataValueBase+2; rel=rotY90; newIKJoint=new CIKJoint(graphJoint,rel,false,false); ikObjs.addChild(lastJoint,newIKJoint); lastJoint=newIKJoint; avatarParent=ikObjs.getJointWithData(dataValueBase+1); if (avatarParent!=NULL) // This joint is used twice (going up and going down) avatarParent->addAvatar(lastJoint); lastJoint->data=dataValueBase+1; rel=rotX90*rotZ90.getInverse()*sphTr.getInverse()*rotY180; newIKJoint=new CIKJoint(graphJoint,rel,true,false); lastJoint->topJoint=newIKJoint; // This is mainly needed by the joint-limitation part! ikObjs.addChild(lastJoint,newIKJoint); lastJoint=newIKJoint; lastJoint->active=false; // Inactive for now (we can activate it later) avatarParent=ikObjs.getJointWithData(dataValueBase+0); if (avatarParent!=NULL) // This joint is used twice (going up and going down) avatarParent->addAvatar(lastJoint); lastJoint->data=dataValueBase+0; localTransformation=rotY180; } else { // From base to tip C7Vector rel(localTransformation); newIKJoint=new CIKJoint(graphJoint,rel,false,true); if (lastJoint==NULL) { treeHandle=newIKJoint; lastJoint=treeHandle; ikObjs.addRoot(lastJoint); } else { ikObjs.addChild(lastJoint,newIKJoint); lastJoint=newIKJoint; } lastJoint->active=false; // Inactive for now (we can activate it later) avatarParent=ikObjs.getJointWithData(dataValueBase+0); if (avatarParent!=NULL) // This joint is used twice (going up and going down) avatarParent->addAvatar(lastJoint); lastJoint->data=dataValueBase+0; rel=sphTr*rotY90; newIKJoint=new CIKJoint(graphJoint,rel,false,true); ikObjs.addChild(lastJoint,newIKJoint); lastJoint=newIKJoint; avatarParent=ikObjs.getJointWithData(dataValueBase+1); if (avatarParent!=NULL) // This joint is used twice (going up and going down) avatarParent->addAvatar(lastJoint); lastJoint->data=dataValueBase+1; rel=rotX90.getInverse(); newIKJoint=new CIKJoint(graphJoint,rel,false,true); ikObjs.addChild(lastJoint,newIKJoint); lastJoint=newIKJoint; avatarParent=ikObjs.getJointWithData(dataValueBase+2); if (avatarParent!=NULL) // This joint is used twice (going up and going down) avatarParent->addAvatar(lastJoint); lastJoint->data=dataValueBase+2; rel=rotY90.getInverse()*rotZ90.getInverse(); newIKJoint=new CIKJoint(graphJoint,rel,true,true); newIKJoint->topJoint=newIKJoint; // Top-joint is itself! ikObjs.addChild(lastJoint,newIKJoint); lastJoint=newIKJoint; avatarParent=ikObjs.getJointWithData(dataValueBase+3); if (avatarParent!=NULL) // This joint is used twice (going up and going down) avatarParent->addAvatar(lastJoint); lastJoint->data=dataValueBase+3; localTransformation.setIdentity(); } } else { if (graphJoint->topObject==(CIKGraphObject*)previousPosition) { // From tip to base C7Vector rel(localTransformation*rotY180); newIKJoint=new CIKJoint(graphJoint,rel,false,false); localTransformation=rotY180; } else { // From base to tip C7Vector rel(localTransformation); newIKJoint=new CIKJoint(graphJoint,rel,false,false); localTransformation.setIdentity(); } if (lastJoint==NULL) { treeHandle=newIKJoint; lastJoint=treeHandle; ikObjs.addRoot(lastJoint); } else { ikObjs.addChild(lastJoint,newIKJoint); lastJoint=newIKJoint; } int dataValue=10*graphJoint->nodeID+0; CIKJoint* avatarParent=ikObjs.getJointWithData(dataValue); if (avatarParent!=NULL) // This joint is used twice (going up and going down) avatarParent->addAvatar(lastJoint); lastJoint->data=dataValue; } } else { // In case a graph-joint is disabled: if (graphJoint->topObject==(CIKGraphObject*)previousPosition) { // From tip to base localTransformation=localTransformation*graphJoint->getDownToTopTransformation().getInverse(); } else { // From base to tip localTransformation=localTransformation*graphJoint->getDownToTopTransformation(); } } } else { CIKGraphObject* theObject=(CIKGraphObject*)graphIterator; if (theObject->objectType==IK_GRAPH_LINK_OBJECT_TYPE) { // Link if (previousPosition!=NULL) { if (theObject->linkPartner!=previousPosition) localTransformation=localTransformation*previousCT.getInverse()*theObject->cumulativeTransformation; // If (theObject->linkPartner==previousPosition) then we don't do anything! } } else { // Here we have a dummy we have to assign to a configuration or a passive object // We treat all cases first as passive objects: if (previousPosition!=NULL) { localTransformation=localTransformation*previousCT.getInverse()*theObject->cumulativeTransformation; if ( (theObject->objectType==IK_GRAPH_TIP_OBJECT_TYPE)&&(lastJoint!=NULL) ) { // This is a valid dummy-tip! CIKDummy* newIKDummy=new CIKDummy(localTransformation,theObject->targetCumulativeTransformation); ikObjs.addChild(lastJoint,newIKDummy); newIKDummy->constraints=(IK_X_CONSTRAINT|IK_Y_CONSTRAINT|IK_Z_CONSTRAINT); newIKDummy->dampingFactor=1.0f; newIKDummy->loopClosureDummy=false; if (graphIterator->getConnectionNumber()==1) break; } } } } int unexploredSize=graphIterator->getNumberOfUnexplored(); if ( (unexploredSize==0)||goingDown||closeComplexLoop ) { if ( (graphIterator->getConnectionNumber()==1)&&(!closeComplexLoop) ) break; // This is a rare case where we have an endpoint without a tip-dummy mobile-part if (closeComplexLoop) { CIKDummy* tipDummy=new CIKDummy(localTransformation,baseIKGraphObject->cumulativeTransformation); ikObjs.addChild(lastJoint,tipDummy); break; } nextPosition=graphIterator->getExploredWithSmallestExplorationID(); if ( (nextPosition->explorationID==0)&&(!goingDown) ) { // The loop can now be closed (simple loop with each joint present at most once) previousCT=((CIKGraphObject*)graphIterator)->cumulativeTransformation; localTransformation=localTransformation*previousCT.getInverse()*((CIKGraphObject*)nextPosition)->cumulativeTransformation; CIKDummy* tipDummy=new CIKDummy(localTransformation,baseIKGraphObject->cumulativeTransformation); ikObjs.addChild(lastJoint,tipDummy); break; } if ( (nextPosition->explorationID==0)&&goingDown ) closeComplexLoop=true; goingDown=true; } else if ((graphIterator->getNeighbourWithExplorationID(0)!=NULL)&&(!goingDown)&&(previousPosition->explorationID!=0)) { // Here we have to close the loop too! // We first put unexplored paths onto the stack: for (int i=0;i<unexploredSize;i++) { // We throw unexplored nodes onto the exploration stack: graphObjectsToBeExplored.push_back(graphIterator->getUnexplored(i)); lastJoints.push_back(lastJoint); previousPositions.push_back(graphIterator); localTransformations.push_back(localTransformation); } nextPosition=graphIterator->getExploredWithSmallestExplorationID(); previousCT=((CIKGraphObject*)previousPosition)->cumulativeTransformation; localTransformation=localTransformation*previousCT.getInverse()*((CIKGraphObject*)nextPosition)->cumulativeTransformation; CIKDummy* tipDummy=new CIKDummy(localTransformation,baseIKGraphObject->cumulativeTransformation); ikObjs.addChild(lastJoint,tipDummy); break; } else { if (previousPosition==NULL) { // This is the start. We should always explore first two links which belong together // or the 3 objects making up a joint! nextPosition=NULL; for (int i=0;i<unexploredSize;i++) { CIKGraphNode* nextPositionTmp=graphIterator->getUnexplored(i); if ( (((CIKGraphObject*)graphIterator)->linkPartner==nextPositionTmp)|| (nextPositionTmp->type==IK_GRAPH_JOINT_TYPE) ) nextPosition=nextPositionTmp; else { graphObjectsToBeExplored.push_back(graphIterator->getUnexplored(i)); lastJoints.push_back(lastJoint); previousPositions.push_back(graphIterator); localTransformations.push_back(localTransformation); if (nextPosition==NULL) nextPosition=graphIterator->getUnexplored(i); } } } else { nextPosition=graphIterator->getUnexplored(0); for (int i=1;i<unexploredSize;i++) { // We throw unexplored nodes onto the exploration stack: graphObjectsToBeExplored.push_back(graphIterator->getUnexplored(i)); lastJoints.push_back(lastJoint); previousPositions.push_back(graphIterator); localTransformations.push_back(localTransformation); } } } previousPosition=graphIterator; graphIterator=nextPosition; } } solveHierarchy(&ikObjs,parameters); for (int i=0;i<int(ikObjs.allObjects.size());i++) { CIKObject* it=ikObjs.allObjects[i]; if (it->objectType==IK_JOINT_TYPE) { CIKJoint* theJoint=(CIKJoint*)it; if (theJoint->avatarParent==NULL) { if (theJoint->spherical) { if (theJoint->topSpherical) { float a0=theJoint->parameter; float a1=((CIKJoint*)theJoint->parent)->parameter; float a2=((CIKJoint*)theJoint->parent->parent)->parameter; float a3=((CIKJoint*)theJoint->parent->parent->parent)->parameter; if (theJoint->sphericalUp) { theJoint->graphJoint->sphericalTransformation=C4Vector(a3,C3Vector(0.0f,0.0f,1.0f))*theJoint->graphJoint->sphericalTransformation*C4Vector(C3Vector(a2,a1,a0)); } else { theJoint->graphJoint->sphericalTransformation=C4Vector(a0,C3Vector(0.0f,0.0f,1.0f))*theJoint->graphJoint->sphericalTransformation*C4Vector(C3Vector(a1,a2,a3)); } } } else theJoint->graphJoint->parameter=theJoint->parameter; } } } graphContainer.actualizeAllTransformations(); graphContainer.putElementsInPlace(); return(true); }