ObjectModelParser.cpp
Go to the documentation of this file.
1 /*
2  * ObjectModelParser.cpp
3  *
4  * Created on: Mar 6, 2012
5  * Author: sdries
6  */
7 
9 #include "wire/core/ClassModel.h"
11 
12 #include <problib/pdfs/Uniform.h>
13 #include <problib/pdfs/PMF.h>
14 
15 using namespace std;
16 
17 namespace mhf {
18 
19 ObjectModelParser::ObjectModelParser(const std::string& filename) : filename_(filename),
20  object_model_loader_(new pluginlib::ClassLoader<IStateEstimator>("wire_core", "IStateEstimator")) {
21 
22 }
23 
25  // TODO: change ownership of the class_loader, as it must persist throughout the whole lifetime of the world model
26  //delete object_model_loader_;
27 }
28 
30  return parse_errors_.str();
31 }
32 
33 string ObjectModelParser::getPropertyValue(const tinyxml2::XMLElement* elem, string prop_name, double& value, std::stringstream& error, bool optional) {
34  const tinyxml2::XMLElement* p = elem->FirstChildElement(prop_name.c_str());
35  if (p) {
36  return p->Attribute("value", std::to_string(value).c_str());
37  }
38  if (!optional) {
39  error << "Could not find property '" << prop_name << "' of element '" << elem->Value() << "'" << endl;
40  }
41  return "";
42 }
43 
44 bool ObjectModelParser::getAttributeValue(const tinyxml2::XMLElement* elem, string att_name, string& att_value, std::stringstream& error) {
45  if (!elem) return false;
46 
47  const char* value = elem->Attribute(att_name.c_str());
48  if (!value) {
49  error << "Could not find attribute '" << att_name << "' of element '" << elem->Value() << "'" << endl;
50  return false;
51  }
52 
53  att_value = value;
54  return true;
55 }
56 
57 bool ObjectModelParser::getAttributeValue(const tinyxml2::XMLElement* elem, string att_name, double& att_value, std::stringstream& error) {
58  if (!elem) return false;
59 
60  const char* value = elem->Attribute(att_name.c_str(), std::to_string(att_value).c_str());
61 
62  if (!value) {
63  error << "Could not find attribute '" << att_name << "' of element '" << elem->Value() << "'" << endl;
64  return false;
65  }
66 
67  return true;
68 }
69 
70 bool ObjectModelParser::hasAttributeValue(const tinyxml2::XMLElement* elem, string att_name, string att_value) {
71  if (!elem) return false;
72 
73  const char* value = elem->Attribute(att_name.c_str());
74  if (!value) return false;
75 
76  string valueStr = value;
77  return (att_value == valueStr);
78 }
79 
80 pbl::PDF* ObjectModelParser::parsePDF(const tinyxml2::XMLElement* pdf_elem, std::stringstream& error) {
81  const char* pdf_type = pdf_elem->Attribute("type");
82  if (pdf_type) {
83  if (string(pdf_type) == "uniform") {
84  double dim = 0;
85  double density = 0;
86  if (getAttributeValue(pdf_elem, "dimensions", dim, error)
87  && getAttributeValue(pdf_elem, "density", density, error)) {
88  return new pbl::Uniform((int)dim, density);
89  }
90  } else if (string(pdf_type) == "discrete") {
91  double domain_size;
92  if (getAttributeValue(pdf_elem, "domain_size", domain_size, error)) {
93  return new pbl::PMF((int)domain_size);
94  }
95  } else {
96  error << "Unknown pdf type: " << pdf_type << endl;
97  }
98  } else {
99  error << "PDF specification should contain 'type' attribute" << endl;
100  }
101  return 0;
102 }
103 
104 bool ObjectModelParser::parseStateEstimator(ClassModel* obj_model, const tinyxml2::XMLElement* elem, std::stringstream& error) {
105 
106  // check behavior model's attribute and model type
107  string attribute_name, model_type;
108  if (!getAttributeValue(elem, "attribute", attribute_name, error)
109  | !getAttributeValue(elem, "model", model_type, error)) {
110  return false;
111  }
112 
113  Attribute attribute = AttributeConv::attribute(attribute_name);
114 
115  if (!object_model_loader_->isClassAvailable(model_type)){
116  std::vector<std::string> classes = object_model_loader_->getDeclaredClasses();
117  for(unsigned int i = 0; i < classes.size(); ++i){
118  if(model_type == object_model_loader_->getName(classes[i])){
119  //if we've found a match... we'll get the fully qualified name and break out of the loop
120  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.",
121  model_type.c_str(), classes[i].c_str());
122  model_type = classes[i];
123  break;
124  }
125  }
126  }
127 
128  IStateEstimator* estimator;
129 
130  if (object_model_loader_->isClassAvailable(model_type)) {
131  estimator = object_model_loader_->createClassInstance(model_type)->clone();
132  } else {
133  error << "Unknown model: " << model_type << endl;
134  return false;
135  }
136 
137  // set estimator parameters
138  const tinyxml2::XMLElement* param = elem->FirstChildElement("param");
139  while (param) {
140  const char* param_name = param->Attribute("name");
141 
142  if (param_name) {
143  bool v_bool;
144  int v_int;
145  double v_double;
146 
147  bool set_param_ok = true;
148  if (param->QueryDoubleAttribute("value", &v_double) == tinyxml2::XML_SUCCESS) {
149  set_param_ok = estimator->setParameter(string(param_name), v_double);
150  } else if (param->QueryIntAttribute("value", &v_int) == tinyxml2::XML_SUCCESS) {
151  set_param_ok = estimator->setParameter(string(param_name), (double)v_int);
152  } else if (param->QueryBoolAttribute("value", &v_bool) == tinyxml2::XML_SUCCESS) {
153  set_param_ok = estimator->setParameter(string(param_name), v_bool);
154  } else {
155  const char* v_str = param->Attribute("value");
156  if (v_str) {
157  set_param_ok = estimator->setParameter(string(param_name), string(v_str));
158  } else {
159  error << "State estimator parameters should always have a 'name' and 'value' attribute." << endl;
160  }
161  }
162 
163  if (!set_param_ok) {
164  error << "Unknown parameter for estimator '" << model_type << "': " << param_name << endl;
165  }
166 
167  } else {
168  error << "State estimator parameters should always have a 'name' and 'value' attribute." << endl;
169  }
170 
171  param = param->NextSiblingElement("param");
172  }
173 
174  const tinyxml2::XMLElement* pnew = elem->FirstChildElement("pnew");
175  if (pnew) {
176  pbl::PDF* pdf_new = parsePDF(pnew, error);
177  if (pdf_new) {
178  obj_model->setNewPDF(attribute, *pdf_new);
179 
180  estimator->update(*pdf_new, 0);
181 
182  delete pdf_new;
183  } else {
184  return false;
185  }
186  } else {
187  error << "Estimator specification does not contain 'pnew'." << endl;
188  return false;
189  }
190 
191  const tinyxml2::XMLElement* pclutter = elem->FirstChildElement("pclutter");
192  if (pnew) {
193  pbl::PDF* pdf_clutter = parsePDF(pclutter, error);
194  if (pdf_clutter) {
195  obj_model->setClutterPDF(attribute, *pdf_clutter);
196 
197  delete pdf_clutter;
198  } else {
199  return false;
200  }
201  } else {
202  error << "Estimator specification does not contain 'pclutter'." << endl;
203  return false;
204  }
205 
206  obj_model->setEstimator(attribute, *estimator);
207 
208  return true;
209 }
210 
211 bool ObjectModelParser::getStateEstimatorParameter(const tinyxml2::XMLElement* elem, const string& param_name, double& value) {
212 
213  const tinyxml2::XMLElement* param = elem->FirstChildElement("param");
214  while (param) {
215  const char* v = param->Attribute("name");
216  if (v && (string)v == param_name) {
217  param->Attribute("value", std::to_string(value).c_str());
218  return true;
219  }
220  param = param->NextSiblingElement("param");
221  }
222 
223  return false;
224 }
225 
227 
228  tinyxml2::XMLDocument doc;
229  doc.LoadFile(filename_.c_str());
230 
231  if (doc.Error()) {
232  ROS_ERROR_STREAM("While parsing '" << filename_ << "': " << endl << endl << doc.ErrorStr() << " at line " << doc.ErrorLineNum());
233  return false;
234  }
235 
236  const tinyxml2::XMLElement* root = doc.RootElement();
237 
238  double prior_new;
239  const tinyxml2::XMLElement* prior_new_elem = root->FirstChildElement("prior_new");
240  if (prior_new_elem) {
241  if (getAttributeValue(prior_new_elem, "value", prior_new, parse_errors_)) {
242  knowledge_db.setPriorNew(prior_new);
243  }
244  } else {
245  parse_errors_ << "Knowledge file does not contain 'prior_new'" << endl;
246  }
247 
248  double prior_existing;
249  const tinyxml2::XMLElement* prior_existing_elem = root->FirstChildElement("prior_existing");
250  if (prior_existing_elem) {
251  if (getAttributeValue(prior_existing_elem, "value", prior_existing, parse_errors_)) {
252  knowledge_db.setPriorExisting(prior_existing);
253  }
254  } else {
255  parse_errors_ << "Knowledge file does not contain 'prior_existing'" << endl;
256  }
257 
258  double prior_clutter;
259  const tinyxml2::XMLElement* prior_clutter_elem = root->FirstChildElement("prior_clutter");
260  if (prior_clutter_elem) {
261  if (getAttributeValue(prior_clutter_elem, "value", prior_clutter, parse_errors_)) {
262  knowledge_db.setPriorClutter(prior_clutter);
263  }
264  } else {
265  parse_errors_ << "Knowledge file does not contain 'prior_clutter'" << endl;
266  }
267 
268 
269  const tinyxml2::XMLElement* class_element = root->FirstChildElement("object_class");
270 
271  /* PARSE ALL OBJECT MODELS */
272 
273  while(class_element) {
274  ClassModel* class_model = 0;
275 
276  string model_name;
277  getAttributeValue(class_element, "name", model_name, parse_errors_);
278 
279  cout << "Parsing model for class " << model_name << endl;
280 
281  string base_class = "";
282  const char* value = class_element->Attribute("base");
283 
284  if (value) {
285  // class derives from base class
286  base_class = value;
287 
288  const ClassModel* base_model = knowledge_db.getClassModel(base_class);
289  if (base_model) {
290  class_model = new ClassModel(*base_model);
291  class_model->setModelName(model_name);
292  } else {
293  parse_errors_ << "Error in class definition of '" << model_name << "': unknown base class '" << base_class << "'." << endl;
294  class_model = new ClassModel(model_name);
295  }
296  } else {
297  class_model = new ClassModel(model_name);
298  }
299 
300  // parse properties
301  const tinyxml2::XMLElement* prop = class_element->FirstChildElement();
302  while(prop) {
303  string prop_name = prop->Value();
304  if (prop_name == "behavior_model") {
305  stringstream bh_errors;
306  parseStateEstimator(class_model, prop, bh_errors);
307  if (bh_errors.str() != "") {
308  parse_errors_ << "In class description for '" << class_model->getModelName() << "': " << bh_errors.str() << endl;
309  }
310  } else {
311  parse_errors_ << "In class description for '" << class_model->getModelName() << "': Unknown class property: '" << prop_name << "'" << endl;
312  }
313  prop = prop->NextSiblingElement();
314  }
315 
316  knowledge_db.addClassModel(class_model->getModelName(), class_model);
317 
318  class_element = class_element->NextSiblingElement("object_class");
319  }
320 
321  if (parse_errors_.str() != "") {
322  return false;
323  }
324 
325  return true;
326 }
327 
328 }
std::string getPropertyValue(const tinyxml2::XMLElement *elem, std::string prop_name, double &value, std::stringstream &error, bool optional=false)
const ClassModel * getClassModel(const std::string &class_name) const
bool parseStateEstimator(ClassModel *obj_model, const tinyxml2::XMLElement *elem, std::stringstream &error)
std::string getErrorMessage() const
void setPriorExisting(double prior_existing)
void setPriorClutter(double prior_clutter)
eT value() const
bool param(const std::string &param_name, T &param_val, const T &default_val)
static Attribute attribute(const std::string &attribute_str)
attribute
Definition: datatypes.cpp:16
pbl::PDF * parsePDF(const tinyxml2::XMLElement *elem, std::stringstream &error)
void setPriorNew(double prior_new)
pluginlib::ClassLoader< IStateEstimator > * object_model_loader_
void addClassModel(const std::string &class_name, ClassModel *model)
Base class for all state estimators used by the world model.
bool getAttributeValue(const tinyxml2::XMLElement *elem, std::string att_name, std::string &att_value, std::stringstream &error)
#define ROS_WARN(...)
void setEstimator(const Attribute &attribute, const IStateEstimator &estimator)
Definition: ClassModel.cpp:36
virtual bool setParameter(const std::string &param, bool b)
Resets the internal state of the estimator to the given PDF.
void setNewPDF(const Attribute &attribute, const pbl::PDF &pdf)
Definition: ClassModel.cpp:28
int Attribute
Definition: datatypes.h:49
virtual void update(const pbl::PDF &z, const Time &time)=0
Updates the internal state based on measurement z.
const std::string & getModelName() const
Definition: ClassModel.cpp:44
bool getStateEstimatorParameter(const tinyxml2::XMLElement *elem, const std::string &param_name, double &value)
bool hasAttributeValue(const tinyxml2::XMLElement *elem, std::string att_name, std::string att_value)
Contains knowledge about a specific object class on where to expect new objects of that class (new) a...
Definition: ClassModel.h:57
bool parse(KnowledgeDatabase &obj_models)
void setModelName(const std::string &name)
Definition: ClassModel.cpp:40
arma_inline subview_elem1< eT, T1 > elem(const Base< uword, T1 > &a)
#define ROS_ERROR_STREAM(args)
std::stringstream parse_errors_
Definition: ClassModel.h:44
void setClutterPDF(const Attribute &attribute, const pbl::PDF &pdf)
Definition: ClassModel.cpp:32


wire_core
Author(s): Sjoerd van den Dries, Jos Elfring
autogenerated on Fri Apr 16 2021 02:32:27