00001
00002
00003
00004
00005
00006
00007
00008 #include "wire/util/ObjectModelParser.h"
00009 #include "wire/core/ClassModel.h"
00010 #include "wire/storage/KnowledgeDatabase.h"
00011
00012 #include <problib/pdfs/Uniform.h>
00013 #include <problib/pdfs/PMF.h>
00014
00015 using namespace std;
00016
00017 namespace mhf {
00018
00019 ObjectModelParser::ObjectModelParser(const std::string& filename) : filename_(filename),
00020 object_model_loader_(new pluginlib::ClassLoader<IStateEstimator>("wire_core", "IStateEstimator")) {
00021
00022 }
00023
00024 ObjectModelParser::~ObjectModelParser() {
00025
00026
00027 }
00028
00029 std::string ObjectModelParser::getErrorMessage() const {
00030 return parse_errors_.str();
00031 }
00032
00033 string ObjectModelParser::getPropertyValue(const TiXmlElement* elem, string prop_name, double& value, stringstream& error, bool optional) {
00034 const TiXmlElement* p = elem->FirstChildElement(prop_name);
00035 if (p) {
00036 return p->Attribute("value", &value);
00037 }
00038 if (!optional) {
00039 error << "Could not find property '" << prop_name << "' of element '" << elem->Value() << "'" << endl;
00040 }
00041 return "";
00042 }
00043
00044 bool ObjectModelParser::getAttributeValue(const TiXmlElement* elem, string att_name, string& att_value, stringstream& error) {
00045 if (!elem) return false;
00046
00047 const char* value = elem->Attribute(att_name.c_str());
00048 if (!value) {
00049 error << "Could not find attribute '" << att_name << "' of element '" << elem->Value() << "'" << endl;
00050 return false;
00051 }
00052
00053 att_value = value;
00054 return true;
00055 }
00056
00057 bool ObjectModelParser::getAttributeValue(const TiXmlElement* elem, string att_name, double& att_value, stringstream& error) {
00058 if (!elem) return false;
00059
00060 const char* value = elem->Attribute(att_name.c_str(), &att_value);
00061
00062 if (!value) {
00063 error << "Could not find attribute '" << att_name << "' of element '" << elem->Value() << "'" << endl;
00064 return false;
00065 }
00066
00067 return true;
00068 }
00069
00070 bool ObjectModelParser::hasAttributeValue(const TiXmlElement* elem, string att_name, string att_value) {
00071 if (!elem) return false;
00072
00073 const char* value = elem->Attribute(att_name.c_str());
00074 if (!value) return false;
00075
00076 string valueStr = value;
00077 return (att_value == valueStr);
00078 }
00079
00080 pbl::PDF* ObjectModelParser::parsePDF(const TiXmlElement* pdf_elem, std::stringstream& error) {
00081 const char* pdf_type = pdf_elem->Attribute("type");
00082 if (pdf_type) {
00083 if (string(pdf_type) == "uniform") {
00084 double dim = 0;
00085 double density = 0;
00086 if (getAttributeValue(pdf_elem, "dimensions", dim, error)
00087 && getAttributeValue(pdf_elem, "density", density, error)) {
00088 return new pbl::Uniform((int)dim, density);
00089 }
00090 } else if (string(pdf_type) == "discrete") {
00091 double domain_size;
00092 if (getAttributeValue(pdf_elem, "domain_size", domain_size, error)) {
00093 return new pbl::PMF((int)domain_size);
00094 }
00095 } else {
00096 error << "Unknown pdf type: " << pdf_type << endl;
00097 }
00098 } else {
00099 error << "PDF specification should contain 'type' attribute" << endl;
00100 }
00101 return 0;
00102 }
00103
00104 bool ObjectModelParser::parseStateEstimator(ClassModel* obj_model, const TiXmlElement* elem, std::stringstream& error) {
00105
00106
00107 string attribute_name, model_type;
00108 if (!getAttributeValue(elem, "attribute", attribute_name, error)
00109 | !getAttributeValue(elem, "model", model_type, error)) {
00110 return false;
00111 }
00112
00113 Attribute attribute = AttributeConv::attribute(attribute_name);
00114
00115 if (!object_model_loader_->isClassAvailable(model_type)){
00116 std::vector<std::string> classes = object_model_loader_->getDeclaredClasses();
00117 for(unsigned int i = 0; i < classes.size(); ++i){
00118 if(model_type == object_model_loader_->getName(classes[i])){
00119
00120 ROS_WARN("Planner specifications should now include the package name. You are using a deprecated API. Please switch from %s to %s in your yaml file.",
00121 model_type.c_str(), classes[i].c_str());
00122 model_type = classes[i];
00123 break;
00124 }
00125 }
00126 }
00127
00128 IStateEstimator* estimator;
00129
00130 if (object_model_loader_->isClassAvailable(model_type)) {
00131 estimator = object_model_loader_->createClassInstance(model_type)->clone();
00132 } else {
00133 error << "Unknown model: " << model_type << endl;
00134 return false;
00135 }
00136
00137
00138 const TiXmlElement* param = elem->FirstChildElement("param");
00139 while (param) {
00140 const char* param_name = param->Attribute("name");
00141
00142 if (param_name) {
00143 bool v_bool;
00144 int v_int;
00145 double v_double;
00146
00147 bool set_param_ok = true;
00148 if (param->QueryDoubleAttribute("value", &v_double) == TIXML_SUCCESS) {
00149 set_param_ok = estimator->setParameter(string(param_name), v_double);
00150 } else if (param->QueryIntAttribute("value", &v_int) == TIXML_SUCCESS) {
00151 set_param_ok = estimator->setParameter(string(param_name), (double)v_int);
00152 } else if (param->QueryBoolAttribute("value", &v_bool) == TIXML_SUCCESS) {
00153 set_param_ok = estimator->setParameter(string(param_name), v_bool);
00154 } else {
00155 const char* v_str = param->Attribute("value");
00156 if (v_str) {
00157 set_param_ok = estimator->setParameter(string(param_name), string(v_str));
00158 } else {
00159 error << "State estimator parameters should always have a 'name' and 'value' attribute." << endl;
00160 }
00161 }
00162
00163 if (!set_param_ok) {
00164 error << "Unknown parameter for estimator '" << model_type << "': " << param_name << endl;
00165 }
00166
00167 } else {
00168 error << "State estimator parameters should always have a 'name' and 'value' attribute." << endl;
00169 }
00170
00171 param = param->NextSiblingElement("param");
00172 }
00173
00174 const TiXmlElement* pnew = elem->FirstChildElement("pnew");
00175 if (pnew) {
00176 pbl::PDF* pdf_new = parsePDF(pnew, error);
00177 if (pdf_new) {
00178 obj_model->setNewPDF(attribute, *pdf_new);
00179
00180 estimator->update(*pdf_new, 0);
00181
00182 delete pdf_new;
00183 } else {
00184 return false;
00185 }
00186 } else {
00187 error << "Estimator specification does not contain 'pnew'." << endl;
00188 return false;
00189 }
00190
00191 const TiXmlElement* pclutter = elem->FirstChildElement("pclutter");
00192 if (pnew) {
00193 pbl::PDF* pdf_clutter = parsePDF(pclutter, error);
00194 if (pdf_clutter) {
00195 obj_model->setClutterPDF(attribute, *pdf_clutter);
00196
00197 delete pdf_clutter;
00198 } else {
00199 return false;
00200 }
00201 } else {
00202 error << "Estimator specification does not contain 'pclutter'." << endl;
00203 return false;
00204 }
00205
00206 obj_model->setEstimator(attribute, *estimator);
00207
00208 return true;
00209 }
00210
00211 bool ObjectModelParser::getStateEstimatorParameter(const TiXmlElement* elem, const string& param_name, double& value) {
00212
00213 const TiXmlElement* param = elem->FirstChildElement("param");
00214 while (param) {
00215 const char* v = param->Attribute("name");
00216 if (v && (string)v == param_name) {
00217 param->Attribute("value", &value);
00218 return true;
00219 }
00220 param = param->NextSiblingElement("param");
00221 }
00222
00223 return false;
00224 }
00225
00226 bool ObjectModelParser::parse(KnowledgeDatabase& knowledge_db) {
00227
00228 TiXmlDocument doc(filename_);
00229 doc.LoadFile();
00230
00231 if (doc.Error()) {
00232 ROS_ERROR_STREAM("While parsing '" << filename_ << "': " << endl << endl << doc.ErrorDesc() << " at line " << doc.ErrorRow() << ", col " << doc.ErrorCol());
00233 return false;
00234 }
00235
00236 const TiXmlElement* root = doc.RootElement();
00237
00238 double prior_new;
00239 const TiXmlElement* prior_new_elem = root->FirstChildElement("prior_new");
00240 if (prior_new_elem) {
00241 if (getAttributeValue(prior_new_elem, "value", prior_new, parse_errors_)) {
00242 knowledge_db.setPriorNew(prior_new);
00243 }
00244 } else {
00245 parse_errors_ << "Knowledge file does not contain 'prior_new'" << endl;
00246 }
00247
00248 double prior_existing;
00249 const TiXmlElement* prior_existing_elem = root->FirstChildElement("prior_existing");
00250 if (prior_existing_elem) {
00251 if (getAttributeValue(prior_existing_elem, "value", prior_existing, parse_errors_)) {
00252 knowledge_db.setPriorExisting(prior_existing);
00253 }
00254 } else {
00255 parse_errors_ << "Knowledge file does not contain 'prior_existing'" << endl;
00256 }
00257
00258 double prior_clutter;
00259 const TiXmlElement* prior_clutter_elem = root->FirstChildElement("prior_clutter");
00260 if (prior_clutter_elem) {
00261 if (getAttributeValue(prior_clutter_elem, "value", prior_clutter, parse_errors_)) {
00262 knowledge_db.setPriorClutter(prior_clutter);
00263 }
00264 } else {
00265 parse_errors_ << "Knowledge file does not contain 'prior_clutter'" << endl;
00266 }
00267
00268
00269 const TiXmlElement* class_element = root->FirstChildElement("object_class");
00270
00271
00272
00273 while(class_element) {
00274 ClassModel* class_model = 0;
00275
00276 string model_name;
00277 getAttributeValue(class_element, "name", model_name, parse_errors_);
00278
00279 cout << "Parsing model for class " << model_name << endl;
00280
00281 string base_class = "";
00282 const char* value = class_element->Attribute("base");
00283
00284 if (value) {
00285
00286 base_class = value;
00287
00288 const ClassModel* base_model = knowledge_db.getClassModel(base_class);
00289 if (base_model) {
00290 class_model = new ClassModel(*base_model);
00291 class_model->setModelName(model_name);
00292 } else {
00293 parse_errors_ << "Error in class definition of '" << model_name << "': unknown base class '" << base_class << "'." << endl;
00294 class_model = new ClassModel(model_name);
00295 }
00296 } else {
00297 class_model = new ClassModel(model_name);
00298 }
00299
00300
00301 const TiXmlElement* prop = class_element->FirstChildElement();
00302 while(prop) {
00303 string prop_name = prop->Value();
00304 if (prop_name == "behavior_model") {
00305 stringstream bh_errors;
00306 parseStateEstimator(class_model, prop, bh_errors);
00307 if (bh_errors.str() != "") {
00308 parse_errors_ << "In class description for '" << class_model->getModelName() << "': " << bh_errors.str() << endl;
00309 }
00310 } else {
00311 parse_errors_ << "In class description for '" << class_model->getModelName() << "': Unknown class property: '" << prop_name << "'" << endl;
00312 }
00313 prop = prop->NextSiblingElement();
00314 }
00315
00316 knowledge_db.addClassModel(class_model->getModelName(), class_model);
00317
00318 class_element = class_element->NextSiblingElement("object_class");
00319 }
00320
00321 if (parse_errors_.str() != "") {
00322 return false;
00323 }
00324
00325 return true;
00326 }
00327
00328 }