Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

robot/sim/IKORTest.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)2003 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: IKORTest.cpp 1033 2004-02-11 20:47:52Z jungd $
00019   $Revision: 1.6 $
00020   $Date: 2004-02-11 15:47:52 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
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 //  env = ref<TestBasicEnvironment>(NewObj TestBasicEnvironment(filesystem, cache, "IKORTest"));
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     // ask each test to output its result to a seperate file
00087     for(Int i=0; i<tests.size();i++)
00088       tests[i].saveResult(filesystem);
00089   }
00090 
00091   // output the results of the all tests
00092   PathName outputName( alternateOutputFileName );
00093   if (outputName.empty())  //  (use name of ikortest with _result appended) 
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       // get environment
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); // we only do static tests
00131       
00132       // which robot (and which of its manipulators) should be used for the test
00133       testRobotIndex = testManipulatorIndex = 0; // default to first robot & first manipulator
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         // find robot
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) { // assume numerical index, not name
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         // now we have the robot, get its manipulator to be tested
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       // read each test
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       // get display related info
00202       displayObstacles = true; // defaults
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         // flags
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         // camera
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 { // output
00241 
00242       DOMElement* ikortestElem = e.createElement("ikortest");
00243       e.setElementAttribute(ikortestElem,"name",getName());
00244 
00245       // output which robot & manipulator to test
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       // output environment
00257 //!!! BUG - this is outputting the env state after the test, we want to reproduce the initial
00258 // env state for output! (somehow)
00259       e.appendBreak(ikortestElem);
00260       env->externalize(e, format, version);
00261       e.appendBreak(ikortestElem);
00262 
00263       // output each test
00264       for(Int i=0; i<tests.size();i++) {
00265         tests[i].externalize(e, format, version);
00266         e.appendBreak(ikortestElem);
00267       }
00268       
00269       
00270       // output display related info
00271       DOMElement* displayElem = e.createElement("display");
00272       
00273       // flags
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       // camera manipulator parameters
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   // write individual joint trajectory output
00323   PathName outputPathName( alternateOutputFileName );
00324   if (alternateOutputFileName.empty()) // none specified via arg 
00325     outputPathName = outputFileName; // so use filename specified in testspec file
00326   
00327   PathName outputPath( outputPathName.path() );
00328   if (!outputPathName.isAbsolute())
00329     outputPath = inputFilePath;// output filename is relative, place it in the testspec file's dir
00330   PathName outputName(outputPathName.name());
00331 
00332   // replace any occurance of the text '$test' with the test name
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       // get trajectory (accept either <trajectory> or <path>)
00401       //  also accept extra attributes for specifying the frame and possibly the time interval
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) { // T - time period only 
00426           timeInterval.resize(3); // time period
00427           timeInterval[0] = 0;
00428           timeInterval[1] = base::stringToReal(timeElts[0]);
00429           timeInterval[2] = -1; // unspecified
00430         }
00431         else if (timeElts.size() == 2) {
00432           timeInterval.resize(3); // S:E - time-start : end-time only
00433           timeInterval[0] = base::stringToReal(timeElts[0]);
00434           timeInterval[1] = base::stringToReal(timeElts[1]);
00435           timeInterval[2] = -1; // unspecified
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); // S:E:d - time-start : end-time : delta (stepsize)
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       // if frame wasn't specified in test, use frame specified by the trajectory/path (if available)
00460       //  otherwise default to "world"
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       // get solution parameters
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       // constraints
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       // get output file
00543       DOMElement* outputElem = e.getFirstChildElement(testElem, "output",false);
00544       String output(getName()+"_jtraj.xml"); // default
00545       if (outputElem) 
00546         output = e.getContainedText(outputElem);
00547       outputFileName = PathName(output);
00548 
00549       
00550       // read in any results recorded from a previous execution
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         // first trajectory info
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         // next jacobians
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           // each line consists of a time , J matrix
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       // read any display specific info
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 { // output
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       // the solution element
00649       DOMElement* solnElem = e.createElement("solution");
00650       e.setElementAttribute(solnElem, "solnmethod", String((solutionMethod==FullSpace)?"fullspace":"pseudoinv"));
00651       if (solutionMethod!=PseudoInverse) { // method, criteria implicit for 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       // constraints
00673       if (solutionMethod!=PseudoInverse) { // can't have constraints for 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       // output file
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       // output trajectory (with extra attributes)
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"); // get element so we can add custom attributes
00713 
00714       e.setElementAttribute(trajElem, "frame", Robot::coordFrame(frame)); // frame that was either in the traj or a specified override
00715       
00716       if (maxdxSpecified) 
00717         e.setElementAttribute(trajElem, "maxdx", base::realToString(maxdx));
00718 
00719       if (timeIntervalSpecified) {
00720         String timeString( base::realToString(timeInterval[0]) ); // period or start-time
00721         if (timeInterval.size() >= 2) {
00722           timeString += String(":")+base::realToString(timeInterval[1]); // start-time:end-time
00723           if ((timeInterval.size() >= 3) && (!maxdxSpecified) && (timeInterval[2]>0)) 
00724             timeString += String(":")+base::realToString(timeInterval[2]); // start-time:end-time:delta (stepsize)
00725         }
00726         e.setElementAttribute(trajElem, "timeinterval", timeString);
00727       }
00728       
00729 
00730       // output test results      
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         // first trajectory info (sequence of time, q, x, dx, dq)
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         // and the Jacobian at each step
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       // output display related info
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 }

Generated on Thu Jul 29 15:56:38 2004 for OpenSim by doxygen 1.3.6