00001 #include "robot_instance/RobotInstanceFactory.h"
00002
00003 using namespace std;
00004 using namespace log4cpp;
00005
00012 void RobotInstanceFactory::populateRobotInstanceFromFile(RobotInstancePtr instance, const std::string& configPath, const std::string& configSafetyPath, const std::string& filenameNoPath)
00013 {
00014 if (not instance)
00015 {
00016 instance = boost::make_shared<RobotInstance>();
00017 }
00018
00019 instance->nodeTokenMap.clear();
00020 instance->mechanismRegisterMap.clear();
00021 instance->mechanismClassFileMap.clear();
00022 instance->mechanismJointFileMap.clear();
00023 instance->mechanismClassSafetyFileMap.clear();
00024 instance->mechanismCommandMap.clear();
00025 instance->mechanismControlMap.clear();
00026 instance->mechanisms.clear();
00027 instance->devices.clear();
00028 instance->commandableJoints.clear();
00029 instance->channelTypeMap.clear();
00030 instance->mechanismTypeMap.clear();
00031 instance->mechanismJointsMap.clear();
00032 instance->mechanismActuatorsMap.clear();
00033 instance->mechanismNodeMap.clear();
00034 instance->mechanismScheduleMap.clear();
00035 instance->jointScheduleNodeMap.clear();
00036 instance->actuatorScheduleNodeMap.clear();
00037 instance->deviceNodeMap.clear();
00038 instance->deviceScheduleMap.clear();
00039 instance->deviceRegisterMap.clear();
00040 instance->jointTypeMap.clear();
00041 instance->jointCommandPathMap.clear();
00042 instance->componentCpfsMap.clear();
00043 instance->deviceCalFileMap.clear();
00044 instance->deviceTypeMap.clear();
00045 instance->crew.clear();
00046
00047 instance->configurationBasePath = configPath + "/";
00048 instance->configurationSafetyBasePath = configSafetyPath + "/";
00049
00050 std::string filename = instance->configurationSafetyBasePath + RobotInstance::INSTANCE_PATH + filenameNoPath;
00051
00052
00053 TiXmlDocument file(filename.c_str());
00054 bool loadOkay = file.LoadFile();
00055
00056 if (!loadOkay)
00057 {
00058 stringstream err;
00059 err << "Failed to load file [" << filename << "]";
00060 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::FATAL, err.str());
00061 throw runtime_error(err.str());
00062 }
00063
00064 TiXmlHandle doc(&file);
00065 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::INFO, "RobotInstance file [" + filename + "] successfully loaded.");
00066
00067
00068 TiXmlHandle robotInstanceElement(doc.FirstChildElement("RobotInstance"));
00069
00070 if (robotInstanceElement.ToElement())
00071 {
00072 instance->robotInstance = Private::getAttribute(robotInstanceElement, "id");
00073 }
00074 else
00075 {
00076 stringstream err;
00077 err << "The file " << filename << " has no element named [RobotInstance]";
00078 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::ERROR, err.str());
00079 throw runtime_error(err.str());
00080 }
00081
00082
00083 TiXmlHandle componentPropertiesElement(robotInstanceElement.FirstChildElement("ComponentProperties"));
00084
00085 if (componentPropertiesElement.ToElement())
00086 {
00087 TiXmlHandle currentComponentElement = 0;
00088 TiXmlHandle currentCpfElement = 0;
00089 string currentComponentName;
00090
00091 std::vector< std::pair<std::string, std::string> > cpfFiles;
00092
00093
00094 currentComponentElement = componentPropertiesElement.FirstChild("ComponentCpfs");
00095
00096 while (currentComponentElement.ToElement())
00097 {
00098 currentComponentName = Private::getAttribute(currentComponentElement, "id");
00099
00100
00101 cpfFiles.clear();
00102 currentCpfElement = currentComponentElement.FirstChild("ComponentCpf");
00103
00104 while (currentCpfElement.ToElement())
00105 {
00106 cpfFiles.push_back(std::make_pair(Private::getAttribute(currentCpfElement, "value"), Private::getAttribute(currentCpfElement, "type")));
00107
00108 currentCpfElement = currentCpfElement.ToElement()->NextSiblingElement("ComponentCpf");
00109 }
00110
00111
00112 instance->componentCpfsMap[currentComponentName] = cpfFiles;
00113
00114 currentComponentElement = currentComponentElement.ToElement()->NextSiblingElement("ComponentCpfs");
00115 }
00116 }
00117
00118
00119 TiXmlHandle machineNameElement(robotInstanceElement.FirstChildElement("MachineName"));
00120
00121 if (machineNameElement.ToElement())
00122 {
00123 instance->machineName = Private::getAttribute(machineNameElement, "id");
00124 }
00125 else
00126 {
00127 stringstream err;
00128 err << "The file " << filename << " has no element named [MachineName]";
00129 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::ERROR, err.str());
00130 throw runtime_error(err.str());
00131 }
00132
00133
00134 TiXmlHandle crewElement(robotInstanceElement.FirstChildElement("Crew"));
00135
00136 if (crewElement.ToElement())
00137 {
00138 TiXmlHandle currentMemberElement = 0;
00139 string currentMemberName;
00140
00141
00142 currentMemberElement = crewElement.FirstChild("Member");
00143
00144 while (currentMemberElement.ToElement())
00145 {
00146 currentMemberName = Private::getAttribute(currentMemberElement, "id");
00147
00148
00149 instance->crew.push_back(currentMemberName);
00150
00151 currentMemberElement = currentMemberElement.ToElement()->NextSiblingElement("Member");
00152 }
00153 }
00154
00155
00156 TiXmlHandle kinematicModelElement(robotInstanceElement.FirstChildElement("KinematicModelFile"));
00157
00158 if (kinematicModelElement.ToElement())
00159 {
00160 instance->kinematicModelFile = Private::getAttribute(kinematicModelElement, "id");
00161 }
00162
00163
00164 TiXmlHandle dynamicModelElement(robotInstanceElement.FirstChildElement("DynamicModelFile"));
00165
00166 if (dynamicModelElement.ToElement())
00167 {
00168 instance->dynamicModelFile = Private::getAttribute(dynamicModelElement, "id");
00169 }
00170
00171
00172 TiXmlHandle masterTokenFileElement(robotInstanceElement.FirstChildElement("MasterTokenFile"));
00173
00174 if (masterTokenFileElement.ToElement())
00175 {
00176 instance->masterTokenFile = Private::getAttribute(masterTokenFileElement, "id");
00177
00178 }
00179
00180
00181 TiXmlHandle nodesElement(robotInstanceElement.FirstChildElement("Nodes"));
00182
00183 if (nodesElement.ToElement())
00184 {
00185 TiXmlHandle currentNodeElement = 0;
00186 string currentNodeName;
00187 string currentNodeToken;
00188
00189
00190 currentNodeElement = nodesElement.FirstChild("Node");
00191
00192 while (currentNodeElement.ToElement())
00193 {
00194 currentNodeName = Private::getAttribute(currentNodeElement, "id");
00195
00196 instance->nodeTokenMap[currentNodeName] = Private::getAttribute(currentNodeElement, "token");
00197
00198 currentNodeElement = currentNodeElement.ToElement()->NextSiblingElement("Node");
00199 }
00200 }
00201
00202
00203 TiXmlHandle channelsElement(robotInstanceElement.FirstChildElement("ChannelModes"));
00204
00205 if (nodesElement.ToElement())
00206 {
00207 TiXmlHandle currentChannelElement = 0;
00208 string currentChannelName;
00209 string currentChannelType;
00210
00211
00212 currentChannelElement = channelsElement.FirstChild("Channel");
00213
00214 while (currentChannelElement.ToElement())
00215 {
00216 currentChannelName = Private::getAttribute(currentChannelElement, "id");
00217
00218 currentChannelType = Private::getAttribute(currentChannelElement, "type");
00219 instance->channelTypeMap[currentChannelName] = currentChannelType;
00220
00221 currentChannelElement = currentChannelElement.ToElement()->NextSiblingElement("Channel");
00222 }
00223 }
00224
00225
00226 TiXmlHandle mechanismsElement(robotInstanceElement.FirstChildElement("Mechanisms"));
00227
00228 if (mechanismsElement.ToElement())
00229 {
00230 TiXmlHandle currentMechanismElement = 0;
00231 TiXmlHandle jointsElement = 0;
00232 TiXmlHandle currentJointElement = 0;
00233 TiXmlHandle actuatorsElement = 0;
00234 TiXmlHandle currentActuatorElement = 0;
00235 TiXmlHandle schedulesElement = 0;
00236 TiXmlHandle currentScheduleElement = 0;
00237 string currentMechanismName;
00238 string currentMechanismType;
00239 string currentJointName;
00240 string currentJointNameFQ;
00241 string currentJointType;
00242 string currentActuatorName;
00243 string currentActuatorNameFQ;
00244 string currentActuatorNode;
00245 string currentActuatorSchedule;
00246
00247
00248 currentMechanismElement = mechanismsElement.FirstChild("Mechanism");
00249
00250 while (currentMechanismElement.ToElement())
00251 {
00252 currentMechanismName = Private::getAttribute(currentMechanismElement, "id");
00253 instance->mechanisms.push_back(currentMechanismName);
00254
00255 currentMechanismType = Private::getAttribute(currentMechanismElement, "type");
00256 instance->mechanismTypeMap[currentMechanismName] = currentMechanismType;
00257
00258 instance->mechanismRegisterMap[currentMechanismName] = Private::getSubelementAttribute(currentMechanismElement, "RegisterFile", "id", false);
00259
00260 if (instance->mechanismRegisterMap[currentMechanismName] == "")
00261 {
00262 instance->mechanismRegisterMap.erase(currentMechanismName);
00263 }
00264
00265 instance->mechanismClassFileMap[currentMechanismName] = Private::getSubelementAttribute(currentMechanismElement, "ClassFile", "id");
00266 instance->mechanismJointFileMap[currentMechanismName] = Private::getSubelementAttribute(currentMechanismElement, "JointFile", "id");
00267 instance->mechanismClassSafetyFileMap[currentMechanismName] = Private::getSubelementAttribute(currentMechanismElement, "ClassSafetyFile", "id");
00268 instance->mechanismJointSafetyFileMap[currentMechanismName] = Private::getSubelementAttribute(currentMechanismElement, "JointSafetyFile", "id");
00269 instance->mechanismCommandMap[currentMechanismName] = Private::getSubelementAttribute(currentMechanismElement, "CommandApiMapFile", "id");
00270 instance->mechanismControlMap[currentMechanismName] = Private::getSubelementAttribute(currentMechanismElement, "ControlApiMapFile", "id");
00271 instance->mechanismSetpointMap[currentMechanismName] = Private::getSubelementAttribute(currentMechanismElement, "SetpointFile", "id", false);
00272
00273 if (instance->mechanismSetpointMap[currentMechanismName] == "")
00274 {
00275 instance->mechanismSetpointMap.erase(currentMechanismName);
00276 }
00277
00278 if (currentMechanismType == "simple")
00279 {
00280 instance->mechanismNodeMap[currentMechanismName] = Private::getSubelementAttribute(currentMechanismElement, "Node", "id");
00281 instance->mechanismScheduleMap[currentMechanismName] = Private::getSubelementAttribute(currentMechanismElement, "ScheduleFile", "id");
00282 instance->jointTypeMap[currentMechanismName] = "active";
00283 instance->jointCommandPathMap[currentMechanismName] = Private::getAttribute(currentMechanismElement, "commandPath");
00284 instance->commandableJoints.push_back(currentMechanismName);
00285 instance->mechanismJointsMap[currentMechanismName].push_back(currentMechanismName);
00286 }
00287 else if (currentMechanismType == "complex")
00288 {
00289
00290 jointsElement = currentMechanismElement.FirstChildElement("Joints");
00291
00292 if (jointsElement.ToElement())
00293 {
00294
00295 currentJointElement = jointsElement.FirstChild("Joint");
00296
00297 while (currentJointElement.ToElement())
00298 {
00299 currentJointName = Private::getAttribute(currentJointElement, "id");
00300
00301 currentJointNameFQ = currentMechanismName + StringUtilities::TOKEN_DELIMITER + currentJointName;
00302
00303 currentJointType = Private::getAttribute(currentJointElement, "type");
00304 instance->jointTypeMap[currentJointNameFQ] = currentJointType;
00305
00306 if (currentJointType == "active")
00307 {
00308 instance->mechanismJointsMap[currentMechanismName].push_back(currentJointNameFQ);
00309 instance->commandableJoints.push_back(currentJointNameFQ);
00310 }
00311 else if (currentJointType != "passive")
00312 {
00313 stringstream err;
00314 err << "Joint " << currentJointNameFQ << " has unknown type [" << currentJointType << "]. Defaulting to passive.";
00315 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::WARN, err.str());
00316 }
00317
00318 instance->mechanismAllJointsMap[currentMechanismName].push_back(currentJointNameFQ);
00319 instance->allJoints.push_back(currentJointNameFQ);
00320
00321 instance->jointCommandPathMap[currentJointNameFQ] = Private::getAttribute(currentMechanismElement, "commandPath");
00322
00323 schedulesElement = currentJointElement.FirstChildElement("ScheduleFiles");
00324
00325 if (schedulesElement.ToElement())
00326 {
00327 currentScheduleElement = schedulesElement.FirstChild("ScheduleFile");
00328
00329 while (currentScheduleElement.ToElement())
00330 {
00331 instance->jointScheduleNodeMap[currentJointNameFQ].push_back(make_pair(Private::getAttribute(currentScheduleElement, "id"), Private::getAttribute(currentScheduleElement, "node")));
00332
00333 currentScheduleElement = currentScheduleElement.ToElement()->NextSiblingElement("ScheduleFile");
00334 }
00335 }
00336 else
00337 {
00338 stringstream err;
00339 err << "The file " << filename << " has no element named [ScheduleFiles]";
00340 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::ERROR, err.str());
00341 throw runtime_error(err.str());
00342 }
00343
00344 currentJointElement = currentJointElement.ToElement()->NextSiblingElement("Joint");
00345 }
00346 }
00347 else
00348 {
00349 stringstream err;
00350 err << "The file " << filename << " has no element named [Joints]";
00351 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::ERROR, err.str());
00352 throw runtime_error(err.str());
00353 }
00354
00355
00356 actuatorsElement = currentMechanismElement.FirstChildElement("Actuators");
00357
00358 if (actuatorsElement.ToElement())
00359 {
00360
00361 currentActuatorElement = actuatorsElement.FirstChild("Actuator");
00362
00363 while (currentActuatorElement.ToElement())
00364 {
00365 currentActuatorName = Private::getAttribute(currentActuatorElement, "id");
00366
00367 currentActuatorNameFQ = currentMechanismName + StringUtilities::TOKEN_DELIMITER + currentActuatorName;
00368
00369 instance->mechanismActuatorsMap[currentMechanismName].push_back(currentActuatorNameFQ);
00370
00371 schedulesElement = currentActuatorElement.FirstChildElement("ScheduleFiles");
00372
00373 if (schedulesElement.ToElement())
00374 {
00375 currentScheduleElement = schedulesElement.FirstChild("ScheduleFile");
00376
00377 while (currentScheduleElement.ToElement())
00378 {
00379 instance->actuatorScheduleNodeMap[currentActuatorNameFQ].push_back(make_pair(Private::getAttribute(currentScheduleElement, "id"), Private::getAttribute(currentScheduleElement, "node")));
00380
00381 currentScheduleElement = currentScheduleElement.ToElement()->NextSiblingElement("ScheduleFile");
00382 }
00383 }
00384 else
00385 {
00386 stringstream err;
00387 err << "The file " << filename << " has no element named [ScheduleFiles]";
00388 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::ERROR, err.str());
00389 throw runtime_error(err.str());
00390 }
00391
00392 currentActuatorElement = currentActuatorElement.ToElement()->NextSiblingElement("Actuator");
00393 }
00394 }
00395 else
00396 {
00397 stringstream err;
00398 err << "The file " << filename << " has no element named [Actuators]";
00399 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::ERROR, err.str());
00400 throw runtime_error(err.str());
00401 }
00402 }
00403
00404 currentMechanismElement = currentMechanismElement.ToElement()->NextSiblingElement("Mechanism");
00405 }
00406 }
00407
00408
00409 TiXmlHandle devicesElement(robotInstanceElement.FirstChildElement("Devices"));
00410
00411 if (devicesElement.ToElement())
00412 {
00413 TiXmlHandle currentDeviceElement = 0;
00414 string currentDeviceName;
00415 string currentDeviceNode;
00416 string currentDeviceSchedule;
00417
00418
00419 currentDeviceElement = devicesElement.FirstChild("Device");
00420
00421 while (currentDeviceElement.ToElement())
00422 {
00423 currentDeviceName = Private::getAttribute(currentDeviceElement, "id");
00424
00425 instance->devices.push_back(currentDeviceName);
00426
00427 instance->deviceNodeMap[currentDeviceName] = Private::getAttribute(currentDeviceElement, "node");
00428 instance->deviceScheduleMap[currentDeviceName] = Private::getAttribute(currentDeviceElement, "schedule");
00429 instance->deviceRegisterMap[currentDeviceName] = Private::getAttribute(currentDeviceElement, "register", false);
00430
00431 if (instance->deviceRegisterMap[currentDeviceName] == "")
00432 {
00433 instance->deviceRegisterMap.erase(currentDeviceName);
00434 }
00435
00436 instance->deviceCalFileMap[currentDeviceName] = Private::getAttribute(currentDeviceElement, "calFile", false);
00437
00438 if (instance->deviceCalFileMap[currentDeviceName] == "")
00439 {
00440 instance->deviceCalFileMap.erase(currentDeviceName);
00441 }
00442
00443 instance->deviceTypeMap[currentDeviceName] = Private::getAttribute(currentDeviceElement, "type", false);
00444
00445 if (instance->deviceTypeMap[currentDeviceName] == "")
00446 {
00447 instance->deviceTypeMap.erase(currentDeviceName);
00448 }
00449
00450 currentDeviceElement = currentDeviceElement.ToElement()->NextSiblingElement("Device");
00451 }
00452 }
00453
00454 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::NOTICE, "RobotInstance file [" + filename + "] successfully parsed.");
00455 }
00456
00462 RobotInstancePtr RobotInstanceFactory::createRobotInstanceFromFile(const std::string& configPath, const std::string& configSafetyPath, const string& filename)
00463 {
00464 RobotInstancePtr instance = boost::make_shared<RobotInstance>();
00465
00466 populateRobotInstanceFromFile(instance, configPath, configSafetyPath, filename);
00467
00468 return instance;
00469 }
00470
00478 const string RobotInstanceFactory::Private::getAttribute(TiXmlHandle handle, const string& attribute, bool required)
00479 {
00480 if (handle.ToElement()->Attribute(attribute))
00481 {
00482 return *(handle.ToElement()->Attribute(attribute));
00483 }
00484 else
00485 {
00486 if (required)
00487 {
00488 stringstream err;
00489 err << "The attribute [" << attribute << "] was not found for element [" << handle.ToElement()->ValueStr() << "]";
00490 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::ERROR, err.str());
00491 throw runtime_error(err.str());
00492 }
00493
00494 return "";
00495 }
00496 }
00497
00505 const string RobotInstanceFactory::Private::getSubelementAttribute(TiXmlHandle handle, const string& subelementName, const string& attribute, bool required)
00506 {
00507 if (handle.FirstChildElement(subelementName).ToElement())
00508 {
00509 return Private::getAttribute(handle.FirstChildElement(subelementName), attribute, required);
00510 }
00511 else
00512 {
00513 if (required)
00514 {
00515 stringstream err;
00516 err << "No [" << subelementName << "] subelement found for element [" << handle.ToElement()->ValueStr() << "]";
00517 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::INFO, err.str());
00518 throw runtime_error(err.str());
00519 }
00520
00521 return "";
00522 }
00523 }
00524
00525 const string RobotInstanceFactory::Private::getNodeFile(TiXmlHandle handle, const string& subelementName, const string& defaultFileName)
00526 {
00527 try
00528 {
00529 return Private::getSubelementAttribute(handle, subelementName, "id");
00530 }
00531 catch (runtime_error& e)
00532 {
00533 if (defaultFileName.size() > 0)
00534 {
00535 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::INFO, "No [" + subelementName + "] element found for [" + getAttribute(handle, "id") + "], using default value.");
00536 return defaultFileName;
00537 }
00538 else
00539 {
00540 stringstream err;
00541 err << "No [" << subelementName << "] element found and no default value to use";
00542 NasaCommonLogging::Logger::log("gov.nasa.configuration.RobotInstanceFactory", Priority::ERROR, err.str());
00543 throw runtime_error(err.str());
00544 }
00545 }
00546 }