OverviewUsually, various simulators such as DynamicsSimulator are used as the CORBA server, but also can be used as a library in OpenHRP3. Here, we will explain how to use it. Loading modelloadBodyFromModelLoader () is used to load model. This receives the pointer to a Body class, model URL and command line arguments, and loads model using ModelLoader server. BodyPtr body = new Body(); if(!loadBodyFromModelLoader(body, url.c_str(), argc, argv)){ cerr << "ModelLoader: " << url << " cannot be loaded" << endl; return 0; } BodyPtr expresses the robot's structure and has the following tree structures. Body + Link In Body, robot information and joint list such as model name are contained. There are three ways to retrieve their joints. How to retrieve by Joint node nameYou can retrieve joints that node indicates by passing the node name to the method link of Body class. Below is an example of retrieving right elbow of "sample.wrl": Link* link = body->link("RARM_ELBOW");How to retrieve by jointId You can retrieve joints with jointId by passing jointId to joint method. Link* link = body->joint(1);How to retrieve by linkId While jointId is an ID in model VRML, linkId is an ID by tree search order of model data. Therefore joints which have no jointId in VRML also have linkId. Link* link = body->link(1); You can retrieve a joint class Link using one of the ways above. For example, we show a program to display all joint angles. for (int i=0; i<body->numLinks(); i++) { Link* link = body->link(i); cout << link->name << " : " << link->q << endl; } Online ViewerOnline Viewer is a function which can display models via CORBA in "3DView" pane of GrxUI. When used by model calculation libraries, use OnlineViewerClient class. Here is a concrete way to use. OnlineViewer_var olv = getOnlineViewer(argc, argv); try { olv->load(body->modelName().c_str(), url.c_str()); olv->setLogName("move_ankle"); } catch (CORBA::SystemException& ex) { cerr << "Failed to connect GrxUI." << endl; return 1; } At first, pass command line arguments to getOnlineViewer method for acquisition of OnlineViewer. Next specify model name and URL, and load the model. Here assuming the model has been loaded in body by loadBodyFromModelLoader() on ahead, we get the name by Body::modelName. Finally, World State Item is created. After initialization, update the contents to display. Do this by copying data retrieved through Body-Link structure to WorldState. The next snippet of code presupposes a sample humanoid has been loaded in a library/OnlineViewer. // create WorldState WorldState world; world.characterPositions.length(1); // CharacterPosition for SampleRobot world.collisions.length(0); CharacterPosition& robot = world.characterPositions[0]; robot.characterName = CORBA::string_dup(body->modelName); world.time = 0; // copy Link to WorldState int n = body->numLinks(); robot.linkPositions.length(n); for (int i=0; i<n; i++) { Link* link = body->link(i); setVector3(link->p, robot.linkPositions[i].p); setMatrix33ToRowMajorArray(link->R, robot.linkPositions[i].R); } // Update olv->update(world); Forward Kinematics CalculationEdit the member q of Link class which represents a joint angle, and invokes Body class::calcForwardKinematics(), then the value is calculated. For example, to calculate a posture rotating 90 degrees at right elbow, write code like this: Link* elbow = body->link("RARM_ELBOW"); elbow->q += M_PI/2; body->calcForwardKinematics(); Inverse Kinematics CalculationSteps like this follow:
Link* waist = body->link("WAIST"); Link* ankle = body->link("RLEG_ANKLE_R"); JointPathPtr path = body->getJointPath(waist, ankle); Set up a position vector and a rotation matrix of the destination link, and perform inverse kinematics calculation. // move the ankle joint up linearly vector3 p = ankle->p; p(2) += 0.01; matrix33 R = identity<matrix33>(); // inverse kinematics calculation path->calcInverseKinematics(p, mat) This sets up a set of joints included in the path to make the ankle joint reside target position/posture. SamplesThe sample program of inverse kinematics is in sample/example/move_ankle of OpenHRP3. ExecutionStart GrxUI and check that OnlineViewer etc. are registered into the name service. LinuxPlease move to (OpenHRP3)/sample/example/mode_ankle and perform as follows. ./move_ankle -url (OpenHRP3)/sample/model/sample.wrl WindowsPlease move to (OpenHRP3)/sample/example/mode_ankle and create a batch file. Please describe the following contents in move_ankle.bat. Please rewrite the option of a name service if needed. set PATH=(OpenHRP3)\bin;%PATH% move_ankle -ORBInitRef NameService=corbaloc:iiop:localhost:2809/NameService -url /(OpenHRP3)\sample\model\sample.wrl Run it. move_ankle.bat Using dynamics serversYou can perform forward/inverse kinematics calculation, using model calculation libraries we have described. However, when you want to do advanced calculations such as collision check and dynamics calculations, you need to use a dynamics server directly. Here we will explain how to write a program which moves both hands closely by inverse kinematics and judges whether they touch each other by collision check. Getting serversSee CORBA initialization and getting various servers in Scheduler creation manual to get various servers: NamingService, ModelLoader, OnlineViewer, DynamicsSimulato, and set them up initially. However, for initial configuration of DynamicsSimulator, please specify the next initial posture and collision check pair. Initial postureSpecify the next array as its initial posture. double init_pos[] = {0.00E+00, -3.60E-02, 0, 7.85E-02, -4.25E-02, 0.00E+00, 1.75E-01, -3.49E-03, 0, -1.57E+00, 0.00E+00, 0.00E+00, 0.00E+00, 0.00E+00, -3.60E-02, 0, 7.85E-02, -4.25E-02, 0.00E+00, 1.75E-01, 3.49E-03, 0, -1.57E+00, 0.00E+00, 0.00E+00, 0.00E+00, 0, 0, 0}; Set this array init_pos to its joint angle. DblSequence q; q.length(DOF); for (int i=0; i<DOF; i++) { q[i] = init_pos[i]; } dynamicsSimulator->setCharacterAllLinkData("robot", DynamicsSimulator::JOINT_VALUE, q); Setting of collision check pairDblSequence6 dc, sc; dc.length(0); sc.length(0); dynamicsSimulator->registerCollisionCheckPair ("robot", "RARM_WRIST_R", "robot", "LARM_WRIST_R", 0.5, 0.5, dc, sc, 0.0); This indicates to perform collision check between the joints of both hands. Preparation of inverse kinematics calculationRecord its initial posture and move a little at once. First, prepare initial postures of both hands. Also, prepare the variable dp which represents how much to move. double RARM_p[] = {0.197403, -0.210919, 0.93732}; double RARM_R[] = {0.174891, -0.000607636, -0.984588, 0.00348999, 0.999994, 2.77917e-06, 0.984582, -0.00343669, 0.174892}; double LARM_p[] = {0.197403, 0.210919, 0.93732}; double LARM_R[] = {0.174891, 0.000607636, -0.984588, -0.00348999, 0.999994, -2.77917e-06, 0.984582, 0.00343669, 0.174892}; double dp; Simulation loopSimulation loop executes the following three processings. Inverse kinematics calculationMove one step to close both hands. LinkPosition link; link.p[0] = RARM_p[0]; link.p[1] = RARM_p[1] + dp; link.p[2] = RARM_p[2]; for (int i=0; i<9; i++) link.R[i] = RARM_R[i]; dynamicsSimulator->calcCharacterInverseKinematics(CORBA::string_dup("robot"), CORBA::string_dup("CHEST"), CORBA::string_dup("RARM_WRIST_R"), link); link.p[0] = LARM_p[0]; link.p[1] = LARM_p[1] - dp; link.p[2] = LARM_p[2]; for (int i=0; i<9; i++) link.R[i] = LARM_R[i]; dynamicsSimulator->calcCharacterInverseKinematics(CORBA::string_dup("robot"), CORBA::string_dup("CHEST"), CORBA::string_dup("LARM_WRIST_R"), link); dynamicsSimulator->calcWorldForwardKinematics(); dp += 0.001; Updating OnlineViewerUpdate display contents in OnlineViewer. It is different from a scheduler that updates time manually because time is not changed. dynamicsSimulator->getWorldState(state); state->time = dp*10; onlineViewer->update(state); Collision CheckWhen there are one or more collision points for the pair of joints which we have registered before, we quit the simulation loop. dynamicsSimulator->checkCollision(true); if (state->collisions.length() > 0) { if (state->collisions[0].points.length() > 0) { break; } } SamplesThe sample program of inverse kinematics and collision check is in sample/example/clap of OpenHRP3. ExecutionStart GrxUI and check that OnlineViewer etc. are registered into the name service. LinuxPlease move to (OpenHRP3)/sample/example/mode_ankle and perform as follows. ./clap -url (OpenHRP3)/sample/model/ -ddp 0.01 -timeK 10 WindowsPlease move to (OpenHRP3)/sample/example/mode_ankle and create a batch file. Please describe the following contents in clap.bat. Please rewrite the option of a name service if needed. set PATH=(OpenHRP3)\bin;%PATH% clap -ORBInitRef NameService=corbaloc:iiop:localhost:2809/NameService -url /(OpenHRP3)\sample\model\ -ddp 0.01 -timeK 10 Run it. clap.bat NoticeAliasAlias is when the assigned variable is also used in the right expression, so the value of the valuable causes interference during calculation. Since interference make the result inappropriate. See these links about tvmet, ublas, and their implementation. By default, tvmet does not assume interference, and it performs well. You have to care interference enough. When interference occurs, introduce a temporary variable, or wrap alias() on the assigned variable. On the other hand, ublas assumes interference by default, there is not such a problem in general. However its performance gets lost in a case where there is no interference. In such a case, wrap noalis() on the assigned variable not to copy uselessly. Expression TemplateExpression Template is to record a expression itself when the expression is given, not to calculate then, deferring to calculate until the calculation is needed. For example, an expression, a*b+c is recorded as a template like this: Add< Multiple < a , b > , c > You must care an order to calculate. Supposing n dimension square matrixes A, B, C, D, consider to assign multiply A, B, C to D. matrix You can consider these two differences. First the second statement does not store an intermediate value in a temporary area, but the first statement stores B*C and they do multiply. The first statement calculates a intermediate value and store the result in a temporary area, and again calculate a final result, so there are 2 matrix calculation and 2n^3 multiplies. The second does not store a intermediate value and actual calculation performs when the final result is stored in D, so its calculation goes like this:
Quantity of this multiply is calculated for one element of D in (n+1)n, but D has n dimension and the number of its elements is n^2, so it needs (n+1)n^3. Therefore these statements have different orders, and the second is slower than the first. When using Expression Template, please notice such a difference of orders. |