00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <robot/sim/IKORTest>
00026
00027 #include <base/Externalizer>
00028 #include <base/externalization_error>
00029 #include <base/Expression>
00030 #include <base/Matrix>
00031 #include <base/VDirectory>
00032 #include <base/VFile>
00033
00034 #include <robot/sim/BasicEnvironment>
00035 #include <robot/control/kinematics/FullSpaceSolver>
00036 #include <robot/control/kinematics/IKOR>
00037
00038
00039 using robot::sim::IKORTest;
00040
00041 using base::Vector;
00042 using base::Orient;
00043 using base::Time;
00044 using base::PathName;
00045 using base::VFile;
00046 using base::VDirectory;
00047 using base::externalization_error;
00048 using base::Path;
00049 using base::Trajectory;
00050 using base::dom::DOMNode;
00051 using base::dom::DOMElement;
00052 using robot::sim::BasicEnvironment;
00053 using robot::sim::SimulatedBasicEnvironment;
00054 using robot::control::kinematics::FullSpaceSolver;
00055 using robot::control::kinematics::InverseKinematicsSolver;
00056 using robot::control::kinematics::FullSpaceSolver;
00057 using robot::control::kinematics::IKOR;
00058
00059
00060
00061
00062
00063 IKORTest::IKORTest(ref<base::VFile> testSpecification,
00064 ref<base::VFileSystem> fs, ref<base::Cache> cache)
00065 : filesystem(fs), cache(cache)
00066 {
00067
00068 env = ref<SimulatedBasicEnvironment>(NewObj SimulatedBasicEnvironment(filesystem, cache, "IKORTest"));
00069
00070 load(testSpecification, testSpecification->extension(),1.0);
00071 }
00072
00073
00074 void IKORTest::setEnvironment(ref<BasicEnvironment> env)
00075 {
00076 if (instanceof(*env, SimulatedBasicEnvironment))
00077 this->env = narrow_ref<SimulatedBasicEnvironment>(env);
00078 else
00079 throw std::invalid_argument(Exception("BasicEnvironment env didn't come from IKORTest (i.e. isn't a SimulatedBasicEnvironment)"));
00080 }
00081
00082
00083 void IKORTest::saveResults(bool saveTrajFiles, PathName alternateOutputFileName)
00084 {
00085 if (saveTrajFiles) {
00086
00087 for(Int i=0; i<tests.size();i++)
00088 tests[i].saveResult(filesystem);
00089 }
00090
00091
00092 PathName outputName( alternateOutputFileName );
00093 if (outputName.empty())
00094 outputName = PathName(inputPath + PathName(getName()+"_results.xml"));
00095 Logln("Saving complete test specification and results to file '" << outputName.str() << "'.");
00096
00097 ref<VDirectory> outDir( filesystem->getDirectory(outputName.path()) );
00098 ref<VFile> outputFile( outDir->createFile(outputName.name()) );
00099 save(outputFile, outputFile->extension(),1.0);
00100 outputFile->close();
00101 }
00102
00103
00104 void IKORTest::externalize(base::Externalizer& e, String format, Real version)
00105 {
00106 if (format == "") format = "xml";
00107
00108 if (!formatSupported(format,version,e.ioType()))
00109 throw std::invalid_argument(Exception(String("format ")+format+" v"+base::realToString(version)+" unsupported"));
00110
00111 if (format == "xml") {
00112
00113 if (e.isInput()) {
00114
00115 inputPath = e.getArchivePath();
00116
00117 DOMNode* context = e.context();
00118
00119 DOMElement* ikortestElem = e.getFirstElement(context, "ikortest");
00120
00121 setName( e.getDefaultedElementAttribute(ikortestElem, "name", "ikortest") );
00122
00123
00124 e.pushContext(ikortestElem);
00125 env->externalize(e, format, version);
00126
00127 if (env->numRobots() == 0)
00128 throw externalization_error(Exception("the test environment must contain at least one robot (for testing)"));
00129
00130 env->setDynamic(false);
00131
00132
00133 testRobotIndex = testManipulatorIndex = 0;
00134 DOMElement* robotElem = e.getFirstChildElement(ikortestElem, "testrobot",false);
00135 if (robotElem) {
00136 array<String> robotElemStrings = e.splitAtDelimiter( e.getContainedText(robotElem), ',');
00137 if (robotElemStrings.size()>2)
00138 throw externalization_error(Exception("expected '[<robotname>|<robot_env_index>],[<manipulator_name>|<manipulator_index>]' text within element 'testrobot'"));
00139
00140
00141 String robotName(e.removeChar(robotElemStrings[0],' '));
00142 bool found=false;
00143 Int index=0;
00144 while ((index < env->numRobots()) && !found) {
00145 found = (env->getRobot(index)->getRobotDescription()->getName() == robotName);
00146 if (!found) index++;
00147 }
00148 if (!found) {
00149 if (e.isNumeric(robotName))
00150 testRobotIndex = base::stringToInt(robotName);
00151 else
00152 throw externalization_error(Exception(String("robot name specified in element 'testrobot' ('")+robotName+"'), not found in environment."));
00153 if (testRobotIndex >= env->numRobots())
00154 throw externalization_error(Exception(String("robot index specified in element 'testrobot' is out-of-range - should be [0..")+base::intToString(env->numRobots()-1)+"]."));
00155 }
00156 else
00157 testRobotIndex = index;
00158
00159
00160
00161 ref<const RobotDescription> rd(env->getRobot(testRobotIndex)->getRobotDescription());
00162 if (rd->manipulators().size() == 0)
00163 throw externalization_error(Exception(String("robot specified in element 'testrobot' ('")+rd->getName()+"'), must have a manipulator (for testing)."));
00164
00165 if (robotElemStrings.size()==2) {
00166 String manipName(e.removeChar(robotElemStrings[1],' '));
00167 bool found=false;
00168 Int index=0;
00169 while ((index < rd->manipulators().size()) && !found) {
00170 found = (rd->manipulators()[index]->getName() == manipName);
00171 if (!found) index++;
00172 }
00173 if (!found) {
00174 if (e.isNumeric(manipName))
00175 testManipulatorIndex = base::stringToInt(manipName);
00176 else
00177 throw externalization_error(Exception(String("robot manipulator name specified in element 'testrobot' ('")+manipName+"'), isn't on robot '"+rd->getName()+"'."));
00178 if (testManipulatorIndex >= rd->manipulators().size())
00179 throw externalization_error(Exception(String("manipulator index specified in element 'testrobot' for robot '")+rd->getName()+"' is out-of-range - should be [0.."+base::intToString(rd->manipulators().size()-1)+"]."));
00180 }
00181 else
00182 testManipulatorIndex = index;
00183 }
00184
00185 }
00186
00187
00188
00189 DOMElement* testElem = e.getFirstChildElement(ikortestElem, "test");
00190 while (testElem) {
00191
00192 Test test;
00193 test.externalize(e, format, version);
00194
00195 tests.push_back(test);
00196
00197 testElem = e.getFirstChildElement(ikortestElem, "test", false);
00198 }
00199
00200
00201
00202 displayObstacles = true;
00203 displayAxes = true;
00204 displayEEPath = false;
00205 displayPlatform = true;
00206 displayStepMod = 1;
00207 lookAtTarget = Vector3(0,0,0);
00208 alpha = -250.0;
00209 theta = 14.0;
00210 d = 9.0;
00211 DOMElement* displayElem = e.getFirstChildElement(ikortestElem, "display",false);
00212 if (displayElem) {
00213
00214
00215 displayObstacles = (e.getFirstChildElement(displayElem, "obstacles",false) != 0);
00216 displayAxes = (e.getFirstChildElement(displayElem, "axes",false) != 0);
00217 displayPlatform = (e.getFirstChildElement(displayElem, "platform",false) != 0);
00218 displayEEPath = (e.getFirstChildElement(displayElem, "eepath",false) != 0);
00219 DOMElement* displayStepModElem = e.getFirstChildElement(displayElem, "stepmod",false);
00220 if (displayStepModElem != 0) {
00221 displayStepMod = Int(base::stringToInt( e.getContainedText(displayStepModElem,true) ));
00222 if (displayStepMod == 0) displayStepMod=1;
00223 }
00224
00225
00226 DOMElement* cameraElem = e.getFirstChildElement(displayElem, "camera",false);
00227 if (cameraElem) {
00228 lookAtTarget = e.toVector3(e.getElementAttribute(cameraElem, "target",true));
00229 alpha = base::stringToReal(e.getElementAttribute(cameraElem, "alpha",true));
00230 theta = base::stringToReal(e.getElementAttribute(cameraElem, "theta",true));
00231 d = base::stringToReal(e.getElementAttribute(cameraElem, "d",true));
00232 }
00233 }
00234
00235
00236 e.popContext();
00237
00238 e.removeElement(ikortestElem);
00239 }
00240 else {
00241
00242 DOMElement* ikortestElem = e.createElement("ikortest");
00243 e.setElementAttribute(ikortestElem,"name",getName());
00244
00245
00246 DOMElement* robotElem = e.createElement("testrobot",false);
00247 String testRobotString( env->getRobot(testRobotIndex)->getRobotDescription()->getName() );
00248 if (testManipulatorIndex != 0)
00249 testRobotString += String(",")+env->getRobot(testRobotIndex)->getRobotDescription()->manipulators()[testManipulatorIndex]->getName();
00250 e.appendText(robotElem, testRobotString);
00251 e.appendNode(ikortestElem, robotElem);
00252 e.appendBreak(ikortestElem);
00253
00254 e.pushContext(ikortestElem);
00255
00256
00257
00258
00259 e.appendBreak(ikortestElem);
00260 env->externalize(e, format, version);
00261 e.appendBreak(ikortestElem);
00262
00263
00264 for(Int i=0; i<tests.size();i++) {
00265 tests[i].externalize(e, format, version);
00266 e.appendBreak(ikortestElem);
00267 }
00268
00269
00270
00271 DOMElement* displayElem = e.createElement("display");
00272
00273
00274 if (displayObstacles) e.appendNode(displayElem, e.createElement("obstacles"));
00275 if (displayAxes) e.appendNode(displayElem, e.createElement("axes"));
00276 if (displayPlatform) e.appendNode(displayElem, e.createElement("platform"));
00277 if (displayEEPath) e.appendNode(displayElem, e.createElement("eepath"));
00278 if (displayStepMod>1) {
00279 DOMElement* displayStepModElem = e.createElement("stepmod",false);
00280 e.appendText(displayStepModElem, base::intToString(displayStepMod));
00281 e.appendBreak(displayElem);
00282 e.appendNode(displayElem, displayStepModElem);
00283 }
00284
00285
00286 DOMElement* cameraElem = e.createElement("camera");
00287 e.setElementAttribute(cameraElem,"target", e.toString(lookAtTarget));
00288 e.setElementAttribute(cameraElem, "alpha", base::realToString(alpha));
00289 e.setElementAttribute(cameraElem, "theta", base::realToString(theta));
00290 e.setElementAttribute(cameraElem, "d", base::realToString(d));
00291 e.appendNode(displayElem,cameraElem);
00292
00293 e.appendNode(ikortestElem, displayElem);
00294
00295 e.popContext();
00296
00297 e.appendElement(ikortestElem);
00298 e.appendBreak(ikortestElem);
00299
00300 }
00301
00302 }
00303 }
00304
00305
00306
00307
00308
00309
00310
00311 IKORTest::Test::Test(const String& name)
00312 : Named(name), initialConfigSpecified(false), toolAttached(false),
00313 timeIntervalSpecified(false), orientationControl(false), jointWeightsSpecified(false),
00314 resultsPresent(false), testCompleted(false), displayRangeSpecified(false)
00315 {
00316 }
00317
00318
00319
00320 void IKORTest::Test::saveResult(ref<base::VFileSystem> filesystem, PathName alternateOutputFileName)
00321 {
00322
00323 PathName outputPathName( alternateOutputFileName );
00324 if (alternateOutputFileName.empty())
00325 outputPathName = outputFileName;
00326
00327 PathName outputPath( outputPathName.path() );
00328 if (!outputPathName.isAbsolute())
00329 outputPath = inputFilePath;
00330 PathName outputName(outputPathName.name());
00331
00332
00333 String nameString( outputName.str() );
00334 Int pos = nameString.find("$test", 0);
00335 if (pos != String::npos ) {
00336 nameString.replace( pos, 5, getName() );
00337 outputName = PathName(nameString);
00338 }
00339
00340 ref<VDirectory> outDir( filesystem->getDirectory(outputPath) );
00341
00342 ref<VFile> jtrajFile( outDir->createFile(outputName) );
00343 jtraj = ManipulatorJointTrajectory(qs,times);
00344 String p(testCompleted?" ":" *partial* ");
00345 Logln("Saving" << p << "joint trajectory file '" << jtrajFile->pathName().str() << "'.");
00346 jtraj.save(jtrajFile);
00347 jtrajFile->close();
00348 }
00349
00350
00351
00352
00353
00354 void IKORTest::Test::externalize(base::Externalizer& e, String format, Real version)
00355 {
00356 if (format == "") format = "xml";
00357
00358 if (!formatSupported(format,version,e.ioType()))
00359 throw std::invalid_argument(Exception(String("format ")+format+" v"+base::realToString(version)+" unsupported"));
00360
00361 if (format == "xml") {
00362
00363 if (e.isInput()) {
00364
00365 DOMNode* context = e.context();
00366
00367 DOMElement* testElem = e.getFirstChildElement(context, "test");
00368 setName( e.getDefaultedElementAttribute(testElem, "name", "test") );
00369
00370 DOMElement* toolElem = e.getFirstChildElement(testElem, "attachedtool",false);
00371 if (toolElem) {
00372 toolAttached = true;
00373 toolName = e.getContainedText(toolElem);
00374 }
00375 else
00376 toolAttached = false;
00377
00378 DOMElement* configElem = e.getFirstChildElement(testElem, "initialconfig",false);
00379 if (configElem) {
00380 initialConfigSpecified = true;
00381 String configText = e.getContainedText(configElem);
00382 initq = e.toVector(configText);
00383 }
00384 else
00385 initialConfigSpecified = false;
00386
00387
00388 DOMElement* weightElem = e.getFirstChildElement(testElem, "jointweights",false);
00389 if (weightElem) {
00390 jointWeightsSpecified = true;
00391 String weightText = e.getContainedText(weightElem);
00392 jointWeights = e.toVector(weightText);
00393 }
00394 else {
00395 jointWeightsSpecified = false;
00396 jointWeights = Vector();
00397 }
00398
00399
00400
00401
00402 DOMElement* trajElem = e.getFirstChildElement(testElem, "trajectory",false);
00403 if (!trajElem) {
00404 trajElem = e.getFirstChildElement(testElem, "path",false);
00405 if (!trajElem)
00406 throw externalization_error(Exception("either <trajectory> or <path> expected in 'test' element"));
00407 }
00408
00409 String frameString = e.getDefaultedElementAttribute(trajElem, "frame", "");
00410 bool frameSpecified = (frameString != "");
00411
00412 String maxdxString = e.getDefaultedElementAttribute(trajElem, "maxdx", "default");
00413 if (maxdxString != "default") {
00414 maxdx = base::stringToReal(maxdxString);
00415 maxdxSpecified = true;
00416 }
00417 else
00418 maxdxSpecified = false;
00419
00420
00421 String timeString = e.getDefaultedElementAttribute(trajElem, "timeinterval", "default");
00422 if (timeString != "default") {
00423 timeString = e.removeChar(timeString,' ');
00424 array<String> timeElts = e.splitAtDelimiter(timeString,':');
00425 if (timeElts.size() == 1) {
00426 timeInterval.resize(3);
00427 timeInterval[0] = 0;
00428 timeInterval[1] = base::stringToReal(timeElts[0]);
00429 timeInterval[2] = -1;
00430 }
00431 else if (timeElts.size() == 2) {
00432 timeInterval.resize(3);
00433 timeInterval[0] = base::stringToReal(timeElts[0]);
00434 timeInterval[1] = base::stringToReal(timeElts[1]);
00435 timeInterval[2] = -1;
00436 }
00437 else if (timeElts.size() == 3) {
00438 if (maxdxSpecified)
00439 throw externalization_error(Exception(String("can't specify both the delta component of the 'timeinterval' attribute and a 'maxdx' attribute of the '<path>' or '<trajectory>' element - one or the other.")));
00440
00441 timeInterval.resize(3);
00442 timeInterval[0] = base::stringToReal(timeElts[0]);
00443 timeInterval[1] = base::stringToReal(timeElts[1]);
00444 timeInterval[2] = base::stringToReal(timeElts[2]);
00445 }
00446 else
00447 throw externalization_error(Exception(String("invalid value for 'timeinterval' attribute for element '")
00448 + e.elementTagName(trajElem) + "' - must be '<starttime>:<endtime>' or '<duration>' or '<starttime>:<endtime>:<stepsize>'"));
00449 timeIntervalSpecified = true;
00450 }
00451 else
00452 timeIntervalSpecified = false;
00453
00454
00455 e.pushContext(testElem);
00456 traj.externalize(e, format, version);
00457 e.popContext();
00458
00459
00460
00461 if (!frameSpecified) {
00462 if (traj.getCoordFrame() != "")
00463 frameString = traj.getCoordFrame();
00464 else
00465 frameString = "world";
00466 }
00467
00468 frame = Robot::coordFrame(frameString);
00469 if (frame == Robot::UnknownFrame)
00470 throw externalization_error(Exception(String("invalid value for 'frame' attribute ")
00471 + " - must be 'ee', 'eebase', 'base', 'mount', 'platform' or 'world'."));
00472
00473
00474
00475 DOMElement* solnElem = e.getFirstChildElement(testElem, "solution");
00476
00477 orientationControl = (e.getDefaultedElementAttribute(solnElem, "orientationcontrol", "true") == "true");
00478
00479 String method = e.getDefaultedElementAttribute(solnElem, "solnmethod", "pseudoinv");
00480 if (method == "pseudoinv")
00481 solutionMethod = PseudoInverse;
00482 else if (method== "fullspace")
00483 solutionMethod = FullSpace;
00484 else
00485 throw externalization_error(Exception("the 'solnmethod' attribute of the 'solution' element must be either: 'pseudoinv' or 'fullspace'"));
00486
00487 String optmethod = e.getDefaultedElementAttribute(solnElem, "optmethod",
00488 String((solutionMethod==PseudoInverse)?"pseudoinv":"lagrangian"));
00489 if (optmethod == "pseudoinv") {
00490 if (solutionMethod == FullSpace)
00491 throw externalization_error(Exception("the solution method is full space parameterizaton; which is incompatible with apseudo inverse optimization method (as that is implicit via the pseudo inverse solution method)"));
00492 optMethod = InverseKinematicsSolver::PseudoInv;
00493 }
00494 else if (optmethod == "lagrangian") {
00495 if (solutionMethod == PseudoInverse)
00496 throw externalization_error(Exception("the pseudo inverse solution method is incompatible with explicit Lagrangian optimization (it implicitly performs optimization using least-norm criteria))"));
00497 optMethod = IKOR::Lagrangian;
00498 }
00499 else if (optmethod == "bangbang") {
00500 throw externalization_error(Exception("Bang-bang optimization method not currently supported"));
00501 }
00502 else if (optmethod == "simplex") {
00503 throw externalization_error(Exception("Simplex optimization method not currently supported"));
00504 }
00505 else
00506 throw externalization_error(Exception("the 'optmethod' attribute of the 'solution' element must have a value from: 'pseudoinv', 'lagrangian', 'bangbang' or 'simplex'."));
00507
00508
00509 String criteria = e.getDefaultedElementAttribute(solnElem, "criteria", "leastnorm");
00510 if (criteria == "leastnorm") {
00511 optCriteria = IKOR::LeastNorm;
00512 }
00513 else if (criteria == "leastflow") {
00514 if (solutionMethod == PseudoInverse)
00515 throw externalization_error(Exception("the pseudo inverse solution method implicitly provides a 'leastnorm' optimization criteria - hence is incompatible with 'leastflow'"));
00516 throw externalization_error(Exception("least flow optimization criteria currently unsupported"));
00517 }
00518 else
00519 throw externalization_error(Exception("the 'criteria' attribute of the 'solution' element must be either 'leastnorm' or 'leastflow'"));
00520
00521
00522
00523 DOMElement* constElem = e.getFirstChildElement(testElem, "constraints",false);
00524 if (constElem) {
00525 DOMElement* jointElem = e.getFirstChildElement(constElem, "jointlimit",false);
00526 if (jointElem) optConstraints.set(IKOR::JointLimits);
00527
00528 DOMElement* obstElem = e.getFirstChildElement(constElem, "obstacle",false);
00529 if (obstElem) optConstraints.set(IKOR::ObstacleAvoidance);
00530
00531 DOMElement* accElem = e.getFirstChildElement(constElem, "acceleration",false);
00532 if (accElem) optConstraints.set(IKOR::Acceleration);
00533
00534 DOMElement* eeimpactElem = e.getFirstChildElement(constElem, "eeimpact",false);
00535 if (eeimpactElem) optConstraints.set(IKOR::EndEffectorImpact);
00536 }
00537
00538 if ((solutionMethod == PseudoInverse) && optConstraints.any())
00539 throw externalization_error(Exception("constraints are incompatible with the pseudo inverse solution method"));
00540
00541
00542
00543 DOMElement* outputElem = e.getFirstChildElement(testElem, "output",false);
00544 String output(getName()+"_jtraj.xml");
00545 if (outputElem)
00546 output = e.getContainedText(outputElem);
00547 outputFileName = PathName(output);
00548
00549
00550
00551 DOMElement* resultElem = e.getFirstChildElement(testElem, "result",false);
00552 resultsPresent = (resultElem!=0);
00553 if (resultsPresent) {
00554 testCompleted = (e.getDefaultedElementAttribute(resultElem, "completed", "true") == "true");
00555 if (!testCompleted)
00556 failureString = e.getDefaultedElementAttribute(resultElem, "failure", "unknown");
00557
00558
00559 DOMElement* trajinfoElem = e.getFirstChildElement(resultElem, "trajectoryinfo");
00560
00561 String dataString = e.getContainedText(trajinfoElem,true);
00562 array<String> dataLines( e.splitIntoLines(dataString) );
00563 dataString = "";
00564
00565 times.clear(); qs.clear(); xs.clear(); dxs.clear(); dqs.clear();
00566
00567 for(Int i=0; i<dataLines.size(); i++) {
00568 array<String> vectorStrings( e.splitAtDelimiter(dataLines[i],',') );
00569
00570 if (!( ((i<dataLines.size()-1) && (vectorStrings.size()==5)) || ((i==dataLines.size()-1) && (vectorStrings.size()==3)) ))
00571 throw externalization_error(Exception("a line of 'trajectoryinfo' element doesn't contain the correct number of comma seperated vectors"));
00572
00573 times.push_back( Time(base::stringToReal(vectorStrings[0])) );
00574 qs.push_back( e.toVector(vectorStrings[1]) );
00575 xs.push_back( e.toVector(vectorStrings[2]) );
00576 if (i!=dataLines.size()-1) {
00577 dxs.push_back( e.toVector(vectorStrings[3]) );
00578 dqs.push_back( e.toVector(vectorStrings[4]) );
00579 }
00580
00581 }
00582
00583
00584
00585 DOMElement* jacobElem = e.getFirstChildElement(resultElem, "jacobians");
00586
00587 dataString = e.getContainedText(jacobElem,true);
00588 dataLines = e.splitIntoLines(dataString);
00589 dataString = "";
00590
00591 Js.clear();
00592
00593 for(Int i=0; i<dataLines.size(); i++) {
00594
00595 array<String> lineCompStrings( e.splitAtDelimiter(dataLines[i],',') );
00596 Time time( base::stringToReal(lineCompStrings[0]) );
00597 if (!time.equals(times[i]))
00598 throw externalization_error(Exception("time " + base::realToString(time.seconds()) + " of Jacobian in element 'jacobians' doesn't match corresponding time in 'trajectoryinfo' element."));
00599
00600 Js.push_back( e.toMatrix( lineCompStrings[1] ) );
00601 }
00602
00603 if (qs.size() != Js.size())
00604 throw externalization_error(Exception("mismatching number step in elements 'trajectoryinfo' and 'jacobians'"));
00605
00606 }
00607
00608
00609
00610 DOMElement* displayElem = e.getFirstChildElement(testElem, "display",false);
00611 displayRangeSpecified = (displayElem!=0);
00612 if (displayRangeSpecified) {
00613 displayStartIndex = base::stringToInt(e.getDefaultedElementAttribute(displayElem, "startIndex", "0"));
00614 displayEndIndex = base::stringToInt(e.getDefaultedElementAttribute(displayElem, "endIndex", base::intToString(times.size()-1)));
00615 }
00616
00617
00618 e.removeElement(testElem);
00619 }
00620 else {
00621
00622 DOMElement* testElem = e.createElement("test");
00623 e.setElementAttribute(testElem, "name", getName());
00624
00625 if (toolAttached) {
00626 DOMElement* toolElem = e.createElement("attachedtool",false);
00627 e.appendText(toolElem, toolName);
00628 e.appendNode(testElem, toolElem);
00629 e.appendBreak(testElem);
00630 }
00631
00632 if (initialConfigSpecified) {
00633 DOMElement* configElem = e.createElement("initialconfig",false);
00634 e.appendText(configElem, e.toString(initq));
00635 e.appendNode(testElem, configElem);
00636 e.appendBreak(testElem);
00637 }
00638
00639
00640 if (jointWeightsSpecified) {
00641 DOMElement* weightElem = e.createElement("jointweights",false);
00642 e.appendText(weightElem, e.toString(jointWeights));
00643 e.appendNode(testElem, weightElem);
00644 e.appendBreak(testElem);
00645 }
00646
00647
00648
00649 DOMElement* solnElem = e.createElement("solution");
00650 e.setElementAttribute(solnElem, "solnmethod", String((solutionMethod==FullSpace)?"fullspace":"pseudoinv"));
00651 if (solutionMethod!=PseudoInverse) {
00652 String optMethodString;
00653 switch (optMethod) {
00654 case InverseKinematicsSolver::PseudoInv: optMethodString="pseudoinv"; break;
00655 case IKOR::Lagrangian: optMethodString="lagrangian"; break;
00656 default: Assertm(false,"unsupported optimization method");
00657 }
00658 e.setElementAttribute(solnElem, "optmethod", optMethodString);
00659 String optCriteriaString;
00660 switch (optCriteria) {
00661 case IKOR::LeastNorm: optCriteriaString="leastnorm"; break;
00662 default: Assertm(false,"unsupported optimization criteria");
00663 }
00664 e.setElementAttribute(solnElem, "criteria", optCriteriaString);
00665 }
00666 e.setElementAttribute(solnElem, "orientationcontrol", String(orientationControl?"true":"false"));
00667
00668 e.appendNode(testElem, solnElem);
00669 e.appendBreak(testElem);
00670
00671
00672
00673 if (solutionMethod!=PseudoInverse) {
00674 DOMElement* constElem = e.createElement("constraints");
00675 bool empty = true;
00676 if (optConstraints.test(IKOR::JointLimits)) {
00677 e.appendNode(constElem, e.createElement("jointlimit",false) );
00678 empty = false;
00679 }
00680 if (optConstraints.test(IKOR::ObstacleAvoidance)) {
00681 e.appendNode(constElem, e.createElement("obstacle",false) );
00682 empty = false;
00683 }
00684 if (optConstraints.test(IKOR::Acceleration)) {
00685 e.appendNode(constElem, e.createElement("acceleration",false) );
00686 empty = false;
00687 }
00688 if (optConstraints.test(IKOR::EndEffectorImpact)) {
00689 e.appendNode(constElem, e.createElement("eeimpact",false) );
00690 empty = false;
00691 }
00692
00693 if (!empty)
00694 e.appendNode(testElem,constElem);
00695 }
00696
00697
00698
00699 DOMElement* outputElem = e.createElement("output",false);
00700 e.appendText(outputElem, outputFileName.str());
00701 e.appendNode(testElem, outputElem);
00702 e.appendBreak(testElem);
00703
00704
00705
00706 e.appendBreak(testElem);
00707
00708 e.pushContext(testElem);
00709 traj.externalize(e, format, version);
00710 e.popContext();
00711
00712 DOMElement* trajElem = e.getFirstChildElement(testElem, "trajectory");
00713
00714 e.setElementAttribute(trajElem, "frame", Robot::coordFrame(frame));
00715
00716 if (maxdxSpecified)
00717 e.setElementAttribute(trajElem, "maxdx", base::realToString(maxdx));
00718
00719 if (timeIntervalSpecified) {
00720 String timeString( base::realToString(timeInterval[0]) );
00721 if (timeInterval.size() >= 2) {
00722 timeString += String(":")+base::realToString(timeInterval[1]);
00723 if ((timeInterval.size() >= 3) && (!maxdxSpecified) && (timeInterval[2]>0))
00724 timeString += String(":")+base::realToString(timeInterval[2]);
00725 }
00726 e.setElementAttribute(trajElem, "timeinterval", timeString);
00727 }
00728
00729
00730
00731 if (resultsPresent) {
00732 e.appendBreak(testElem);
00733 DOMElement* resultElem = e.createElement("result");
00734 e.setElementAttribute(resultElem, "completed", testCompleted?"true":"false");
00735 if (!testCompleted)
00736 e.setElementAttribute(resultElem, "failure", failureString);
00737
00738
00739 DOMElement* trajinfoElem = e.createElement("trajectoryinfo");
00740
00741 e.appendComment(trajinfoElem,"time, q, x, dx, dq");
00742
00743 for(Int i=0; i<qs.size(); i++) {
00744 String line;
00745 line += base::realToString(times[i].seconds())+", ";
00746 line += e.toString(qs[i])+", ";
00747 line += e.toString(xs[i]);
00748 if (i<qs.size()-1) {
00749 line += String(", ")+e.toString(dxs[i])+", ";
00750 line += e.toString(dqs[i]);
00751 }
00752 e.appendText(trajinfoElem,line);
00753 e.appendBreak(trajinfoElem);
00754 }
00755
00756 e.appendNode(resultElem, trajinfoElem);
00757 e.appendBreak(resultElem);
00758
00759
00760 DOMElement* jacobElem = e.createElement("jacobians");
00761 e.appendComment(jacobElem,"time, J(q)");
00762
00763 Assert(qs.size() == Js.size());
00764 for(Int i=0; i<Js.size(); i++) {
00765 String line;
00766 line += base::realToString(times[i].seconds())+", ";
00767 line += e.toString(Js[i]);
00768 e.appendText(jacobElem, line);
00769 e.appendBreak(jacobElem);
00770 }
00771
00772 e.appendNode(resultElem, jacobElem);
00773
00774 e.appendNode(testElem, resultElem);
00775 e.appendBreak(testElem);
00776
00777 }
00778
00779
00780 if (displayRangeSpecified) {
00781 DOMElement* displayElem = e.createElement("display");
00782 e.setElementAttribute(displayElem, "startIndex", base::intToString(displayStartIndex));
00783 e.setElementAttribute(displayElem, "endIndex", base::intToString(displayEndIndex));
00784
00785 e.appendNode(testElem, displayElem);
00786 e.appendBreak(testElem);
00787 }
00788
00789
00790
00791
00792 e.appendElement(testElem);
00793 e.appendBreak(testElem);
00794
00795 }
00796 }
00797
00798 }