MRPT  1.9.9
VelodyneCalibration.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "obs-precomp.h" // Precompiled headers
11 
12 #include <mrpt/config.h>
13 #include <mrpt/core/bits_math.h>
14 #include <mrpt/core/exceptions.h>
16 #include <cmath>
17 #include <fstream>
18 #include <iostream>
19 #include <map>
20 #include <sstream>
21 #if MRPT_HAS_YAMLCPP
22 #include <yaml-cpp/yaml.h>
23 #endif
24 
25 #undef _UNICODE // JLBC, for xmlParser
26 #include "xmlparser/xmlParser.h"
27 
28 // ======= Default calibration files ========================
32 // ======= End of default calibration files =================
33 
34 using namespace std;
35 using namespace mrpt::obs;
36 
37 VelodyneCalibration::PerLaserCalib::PerLaserCalib()
38 
39  = default;
40 
41 VelodyneCalibration::VelodyneCalibration() : laser_corrections(0) {}
43 {
44  XMLNode& root = *reinterpret_cast<XMLNode*>(node_ptr);
45 
46  XMLNode node_bs = root.getChildNode("boost_serialization");
47  if (node_bs.isEmpty())
48  throw std::runtime_error("Cannot find XML node: 'boost_serialization'");
49 
50  XMLNode node_DB = node_bs.getChildNode("DB");
51  if (node_DB.isEmpty())
52  throw std::runtime_error("Cannot find XML node: 'DB'");
53 
54  XMLNode node_enabled_ = node_DB.getChildNode("enabled_");
55  if (node_enabled_.isEmpty())
56  throw std::runtime_error("Cannot find XML node: 'enabled_'");
57 
58  // Clear previous contents:
59  clear();
60 
61  XMLNode node_enabled_count = node_enabled_.getChildNode("count");
62  if (node_enabled_count.isEmpty())
63  throw std::runtime_error("Cannot find XML node: 'enabled_::count'");
64  const int nEnabled = atoi(node_enabled_count.getText());
65  if (nEnabled <= 0 || nEnabled > 10000)
66  throw std::runtime_error(
67  "Senseless value found reading 'enabled_::count'");
68 
69  int enabledCount = 0;
70  for (int i = 0; i < nEnabled; i++)
71  {
72  XMLNode node_enabled_ith = node_enabled_.getChildNode("item", i);
73  if (node_enabled_ith.isEmpty())
74  throw std::runtime_error(
75  "Cannot find the expected number of XML nodes: "
76  "'enabled_::item'");
77  const int enable_val = atoi(node_enabled_ith.getText());
78  if (enable_val) ++enabledCount;
79  }
80 
81  // enabledCount = number of lasers in the LIDAR
82  this->laser_corrections.resize(enabledCount);
83 
84  XMLNode node_points_ = node_DB.getChildNode("points_");
85  if (node_points_.isEmpty())
86  throw std::runtime_error("Cannot find XML node: 'points_'");
87 
88  for (int i = 0;; ++i)
89  {
90  XMLNode node_points_item = node_points_.getChildNode("item", i);
91  if (node_points_item.isEmpty()) break;
92 
93  XMLNode node_px = node_points_item.getChildNode("px");
94  if (node_px.isEmpty())
95  throw std::runtime_error(
96  "Cannot find XML node: 'points_::item::px'");
97 
98  XMLNode node_px_id = node_px.getChildNode("id_");
99  if (node_px_id.isEmpty())
100  throw std::runtime_error(
101  "Cannot find XML node: 'points_::item::px::id_'");
102  const int id = atoi(node_px_id.getText());
103  ASSERT_ABOVEEQ_(id, 0);
104  if (id >= enabledCount) continue; // ignore
105 
107 
108  {
109  XMLNode node = node_px.getChildNode("rotCorrection_");
110  if (node.isEmpty())
111  throw std::runtime_error(
112  "Cannot find XML node: "
113  "'points_::item::px::rotCorrection_'");
114  plc->azimuthCorrection = atof(node.getText());
115  }
116  {
117  XMLNode node = node_px.getChildNode("vertCorrection_");
118  if (node.isEmpty())
119  throw std::runtime_error(
120  "Cannot find XML node: "
121  "'points_::item::px::vertCorrection_'");
122  plc->verticalCorrection = atof(node.getText());
123  }
124  {
125  XMLNode node = node_px.getChildNode("distCorrection_");
126  if (node.isEmpty())
127  throw std::runtime_error(
128  "Cannot find XML node: "
129  "'points_::item::px::distCorrection_'");
130  plc->distanceCorrection = 0.01f * atof(node.getText());
131  }
132  {
133  XMLNode node = node_px.getChildNode("vertOffsetCorrection_");
134  if (node.isEmpty())
135  throw std::runtime_error(
136  "Cannot find XML node: "
137  "'points_::item::px::vertOffsetCorrection_'");
138  plc->verticalOffsetCorrection = 0.01f * atof(node.getText());
139  }
140  {
141  XMLNode node = node_px.getChildNode("horizOffsetCorrection_");
142  if (node.isEmpty())
143  throw std::runtime_error(
144  "Cannot find XML node: "
145  "'points_::item::px::horizOffsetCorrection_'");
146  plc->horizontalOffsetCorrection = 0.01f * atof(node.getText());
147  }
148 
149  plc->sinVertCorrection =
150  std::sin(mrpt::DEG2RAD(plc->verticalCorrection));
151  plc->cosVertCorrection =
152  std::cos(mrpt::DEG2RAD(plc->verticalCorrection));
153 
158  }
159 
160  return true; // Ok
161 }
162 
163 bool VelodyneCalibration::loadFromXMLText(const std::string& xml_file_contents)
164 {
165  try
166  {
168  XMLNode root =
169  XMLNode::parseString(xml_file_contents.c_str(), nullptr, &results);
170 
171  if (results.error != eXMLErrorNone)
172  {
173  cerr << "[VelodyneCalibration::loadFromXMLText] Error parsing XML "
174  "content: "
175  << XMLNode::getError(results.error) << " at line "
176  << results.nLine << ":" << results.nColumn << endl;
177  return false;
178  }
179 
180  return internal_loadFromXMLNode(reinterpret_cast<void*>(&root));
181  }
182  catch (exception& e)
183  {
184  cerr << "[VelodyneCalibration::loadFromXMLFile] Exception:" << endl
185  << e.what() << endl;
186  return false;
187  }
188 }
189 
190 /** Loads calibration from file. \return false on any error, true on success */
191 // See reference code in:
192 // vtkVelodyneHDLReader::vtkInternal::LoadCorrectionsFile()
194  const std::string& velodyne_calibration_xml_filename)
195 {
196  try
197  {
200  velodyne_calibration_xml_filename.c_str(), nullptr, &results);
201 
202  if (results.error != eXMLErrorNone)
203  {
204  cerr << "[VelodyneCalibration::loadFromXMLFile] Error loading XML "
205  "file: "
206  << XMLNode::getError(results.error) << " at line "
207  << results.nLine << ":" << results.nColumn << endl;
208  return false;
209  }
210  return internal_loadFromXMLNode(reinterpret_cast<void*>(&root));
211  }
212  catch (exception& e)
213  {
214  cerr << "[VelodyneCalibration::loadFromXMLFile] Exception:" << endl
215  << e.what() << endl;
216  return false;
217  }
218 }
219 
221 {
222 #if MRPT_HAS_YAMLCPP
223  try
224  {
225  YAML::Node root = YAML::Load(str);
226 
227  // Clear previous contents:
228  clear();
229 
230  const auto num_lasers = root["num_lasers"].as<unsigned int>(0);
231  ASSERT_(num_lasers > 0);
232 
233  this->laser_corrections.resize(num_lasers);
234 
235  auto lasers = root["lasers"];
236  ASSERT_EQUAL_(lasers.size(), num_lasers);
237 
238  for (auto item : lasers)
239  {
240  const auto id = item["laser_id"].as<unsigned int>(9999999);
241  ASSERT_(id < num_lasers);
242 
244 
245  plc->azimuthCorrection = item["rot_correction"].as<double>();
246  plc->verticalCorrection = item["vert_correction"].as<double>();
247 
248  plc->distanceCorrection = item["dist_correction"].as<double>();
250  item["vert_offset_correction"].as<double>();
252  item["horiz_offset_correction"].as<double>();
253 
254  plc->sinVertCorrection = std::sin(plc->verticalCorrection);
255  plc->cosVertCorrection = std::cos(plc->verticalCorrection);
256 
261  }
262 
263  return true; // all ok
264  }
265  catch (const std::exception& e)
266  {
267  std::cerr << "[VelodyneCalibration::loadFromYAMLText]" << e.what()
268  << "\n";
269  return false;
270  }
271 #else
272  THROW_EXCEPTION("This method requires building MRPT with YAML-CPP.");
273 #endif
274 }
275 
277 {
278 #if MRPT_HAS_YAMLCPP
279  try
280  {
281  std::ifstream f(filename);
282  if (!f.is_open())
283  THROW_EXCEPTION_FMT("Cannot open file: '%s'", filename.c_str());
284 
285  // Load file:
286  std::string str(
287  (std::istreambuf_iterator<char>(f)),
288  std::istreambuf_iterator<char>());
289 
290  return loadFromYAMLText(str);
291  }
292  catch (const std::exception& e)
293  {
294  std::cerr << "[VelodyneCalibration::loadFromYAMLFile]" << e.what()
295  << "\n";
296  return false;
297  }
298 #else
299  THROW_EXCEPTION("This method requires building MRPT with YAML-CPP.");
300 #endif
301 }
302 
303 bool VelodyneCalibration::empty() const { return laser_corrections.empty(); }
305 static std::map<std::string, VelodyneCalibration> cache_default_calibs;
306 
307 // It always return a calibration structure, but it may be empty if the model
308 // name is unknown.
310  const std::string& lidar_model)
311 {
312  // Cached calib data?
313  auto it = cache_default_calibs.find(lidar_model);
314  if (it != cache_default_calibs.end()) return it->second;
315 
316  VelodyneCalibration result; // Leave empty to indicate unknown model
317  std::string xml_contents, yaml_contents;
318 
319  if (lidar_model == "VLP16")
320  xml_contents = velodyne_default_calib_VLP16;
321  else if (lidar_model == "HDL32")
322  xml_contents = velodyne_default_calib_HDL32;
323  else if (lidar_model == "HDL64")
324  yaml_contents = velodyne_default_calib_HDL64E_S3;
325 
326  if (!xml_contents.empty())
327  {
328  if (!result.loadFromXMLText(xml_contents))
329  std::cerr << "[VelodyneCalibration::LoadDefaultCalibration] Error "
330  "parsing default XML calibration file for model '"
331  << lidar_model << "'\n";
332  }
333  else if (!yaml_contents.empty())
334  {
335  if (!result.loadFromYAMLText(yaml_contents))
336  std::cerr << "[VelodyneCalibration::LoadDefaultCalibration] Error "
337  "parsing default YAML calibration file for model '"
338  << lidar_model << "'\n";
339  }
340 
341  cache_default_calibs[lidar_model] = result;
342  return cache_default_calibs[lidar_model];
343 }
Velodyne calibration data, for usage in mrpt::obs::CObservationVelodyneScan.
const char * velodyne_default_calib_HDL32
bool loadFromXMLFile(const std::string &velodyne_calibration_xml_filename)
Loads calibration from file, in the format supplied by the manufacturer.
bool loadFromXMLText(const std::string &xml_file_contents)
Loads calibration from a string containing an entire XML calibration file.
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:67
Main Class representing a XML node.
Definition: xmlParser.h:314
const std::string velodyne_default_calib_HDL64E_S3
double DEG2RAD(const double x)
Degrees to radians.
static XMLNode parseString(XMLCSTR lpXMLString, XMLCSTR tag=nullptr, XMLResults *pResults=nullptr)
Parse an XML string and return the root of a XMLNode tree representing the string.
Definition: xmlParser.cpp:2218
void clear()
Clear all previous contents.
char isEmpty() const
is this node Empty?
Definition: xmlParser.cpp:3419
STL namespace.
static XMLCSTR getError(XMLError error)
this gives you a
Definition: xmlParser.cpp:83
XMLCSTR getText(int i=0) const
return ith text field
Definition: xmlParser.cpp:3399
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:120
map< string, CVectorDouble > results
#define ASSERT_EQUAL_(__A, __B)
Assert comparing two values, reporting their actual values upon failure.
Definition: exceptions.h:137
std::vector< PerLaserCalib > laser_corrections
bool loadFromYAMLText(const std::string &yaml_file_contents)
Loads calibration from a string containing an entire YAML calibration file.
This namespace contains representation of robot actions and observations.
#define ASSERT_ABOVEEQ_(__A, __B)
Definition: exceptions.h:167
GLsizei const GLchar ** string
Definition: glext.h:4116
static std::map< std::string, VelodyneCalibration > cache_default_calibs
static XMLNode parseFile(XMLCSTR filename, XMLCSTR tag=nullptr, XMLResults *pResults=nullptr)
Parse an XML file and return the root of a XMLNode tree representing the file.
Definition: xmlParser.cpp:2285
bool empty() const
Returns true if no calibration has been loaded yet.
GLuint id
Definition: glext.h:3920
const char * velodyne_default_calib_VLP16
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Definition: exceptions.h:69
bool loadFromYAMLFile(const std::string &velodyne_calib_yaml_filename)
Loads calibration from a YAML calibration file.
static const VelodyneCalibration & LoadDefaultCalibration(const std::string &lidar_model)
Loads default calibration files for common LIDAR models.
Structure used to obtain error details if the parse fails.
Definition: xmlParser.h:275
XMLNode getChildNode(int i=0) const
return ith child node
Definition: xmlParser.cpp:3404



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 8fe78517f Sun Jul 14 19:43:28 2019 +0200 at lun oct 28 02:10:00 CET 2019