mrpt_localization.cpp
Go to the documentation of this file.
1 /***********************************************************************************
2  * Revised BSD License *
3  * Copyright (c) 2014, Markus Bader <markus.bader@tuwien.ac.at> *
4  * All rights reserved. *
5  * *
6  * Redistribution and use in source and binary forms, with or without *
7  * modification, are permitted provided that the following conditions are met: *
8  * * Redistributions of source code must retain the above copyright *
9  * notice, this list of conditions and the following disclaimer. *
10  * * Redistributions in binary form must reproduce the above copyright *
11  * notice, this list of conditions and the following disclaimer in the *
12  * documentation and/or other materials provided with the distribution. *
13  * * Neither the name of the Vienna University of Technology nor the *
14  * names of its contributors may be used to endorse or promote products *
15  * derived from this software without specific prior written permission. *
16  * *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  *AND *
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  **
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
22  * DISCLAIMED. IN NO EVENT SHALL Markus Bader BE LIABLE FOR ANY *
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  **
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
27  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  **
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  ** *
32  ***********************************************************************************/
33 
34 #include <mrpt/maps/COccupancyGridMap2D.h>
35 #include <mrpt/maps/CSimplePointsMap.h>
36 #include <mrpt/opengl/CEllipsoid2D.h>
37 #include <mrpt/opengl/COpenGLScene.h>
38 #include <mrpt/opengl/CPointCloud.h>
39 #include <mrpt/ros1bridge/map.h>
40 #include <mrpt/system/filesystem.h>
43 #include <ros/console.h>
44 
45 #include <chrono>
46 #include <thread>
47 
48 using namespace mrpt;
49 using namespace mrpt::slam;
50 using namespace mrpt::opengl;
51 using namespace mrpt::gui;
52 using namespace mrpt::math;
53 using namespace mrpt::system;
54 using namespace mrpt::bayes;
55 using namespace mrpt::poses;
56 using namespace std;
57 using namespace mrpt::maps;
58 using namespace mrpt::obs;
59 using namespace mrpt::img;
60 using namespace mrpt::config;
61 
62 using mrpt::maps::COccupancyGridMap2D;
63 using mrpt::maps::CSimplePointsMap;
64 
67  : PFLocalizationCore(), param_(param)
68 {
69 }
70 
72 {
73  ROS_INFO_STREAM("ini_file ready " << param_->ini_file);
74  ASSERT_FILE_EXISTS_(param_->ini_file);
75  ROS_INFO_STREAM("ASSERT_FILE_EXISTS_ " << param_->ini_file);
76  CConfigFile ini_file;
77  ini_file.setFileName(param_->ini_file);
78  ROS_INFO_STREAM("CConfigFile: " << param_->ini_file);
79 
80  std::vector<int>
81  particles_count; // Number of initial particles (if size>1, run
82  // the experiments N times)
83 
84  // Load configuration:
85  // -----------------------------------------
86  string iniSectionName("LocalizationExperiment");
87  update_counter_ = 0;
88 
89  // Mandatory entries:
90  ini_file.read_vector(
91  iniSectionName, "particles_count", std::vector<int>(1, 0),
92  particles_count,
93  /*Fail if not found*/ true);
94 
95  if (param_->map_file.empty())
96  {
97  param_->map_file = ini_file.read_string(iniSectionName, "map_file", "");
98  }
99 
100  // Non-mandatory entries:
101  SCENE3D_FREQ_ = ini_file.read_int(iniSectionName, "3DSceneFrequency", 10);
103  ini_file.read_bool(iniSectionName, "3DSceneFollowRobot", true);
104 
106  ini_file.read_bool(iniSectionName, "SHOW_PROGRESS_3D_REAL_TIME", false);
107  SHOW_PROGRESS_3D_REAL_TIME_DELAY_MS_ = ini_file.read_int(
108  iniSectionName, "SHOW_PROGRESS_3D_REAL_TIME_DELAY_MS", 1);
109 
110 #if !MRPT_HAS_WXWIDGETS
112 #endif
113 
114  // Default odometry uncertainty parameters in "odom_params_default_"
115  // depending on how fast the robot moves, etc...
116  // Only used for observations-only rawlogs:
117  motion_model_default_options_.modelSelection =
118  CActionRobotMovement2D::mmGaussian;
119 
120  motion_model_default_options_.gaussianModel.minStdXY =
121  ini_file.read_double("DummyOdometryParams", "minStdXY", 0.04);
122  motion_model_default_options_.gaussianModel.minStdPHI = DEG2RAD(
123  ini_file.read_double("DefaultOdometryParams", "minStdPHI", 2.0));
124 
125  // Read initial particles distribution; fail if any parameter is not found
126  init_PDF_mode =
127  ini_file.read_bool(iniSectionName, "init_PDF_mode", false, true);
129  ini_file.read_float(iniSectionName, "init_PDF_min_x", 0, true);
131  ini_file.read_float(iniSectionName, "init_PDF_max_x", 0, true);
133  ini_file.read_float(iniSectionName, "init_PDF_min_y", 0, true);
135  ini_file.read_float(iniSectionName, "init_PDF_max_y", 0, true);
136  float min_phi = DEG2RAD(
137  ini_file.read_float(iniSectionName, "init_PDF_min_phi_deg", -180));
138  float max_phi = DEG2RAD(
139  ini_file.read_float(iniSectionName, "init_PDF_max_phi_deg", 180));
140  mrpt::poses::CPose2D p;
141  mrpt::math::CMatrixDouble33 cov;
142  cov(0, 0) = fabs(init_PDF_max_x - init_PDF_min_x);
143  cov(1, 1) = fabs(init_PDF_max_y - init_PDF_min_y);
144  cov(2, 2) =
145  min_phi < max_phi ? max_phi - min_phi : (max_phi + 2 * M_PI) - min_phi;
146  p.x() = init_PDF_min_x + cov(0, 0) / 2.0;
147  p.y() = init_PDF_min_y + cov(1, 1) / 2.0;
148  p.phi() = min_phi + cov(2, 2) / 2.0;
149  ROS_DEBUG(
150  "----------- phi: %4.3f: %4.3f <-> %4.3f, %4.3f\n", p.phi(), min_phi,
151  max_phi, cov(2, 2));
152  initial_pose_ = mrpt::poses::CPosePDFGaussian(p, cov);
153  state_ = INIT;
154 
155  configureFilter(ini_file);
156  // Metric map options:
157 
158  ASSERT_(metric_map_);
159 
160  if (!mrpt::ros1bridge::MapHdl::loadMap(
161  *metric_map_, ini_file, param_->map_file, "metricMap",
162  param_->debug))
163  {
164  waitForMap();
165  }
166 
167  initial_particle_count_ = *particles_count.begin();
168 
169  if (param_->gui_mrpt) init3DDebug();
170 }
171 
172 void PFLocalization::configureFilter(const CConfigFile& _configFile)
173 {
174  // PF-algorithm Options:
175  // ---------------------------
176  CParticleFilter::TParticleFilterOptions pfOptions;
177  pfOptions.loadFromConfigFile(_configFile, "PF_options");
178  pfOptions.dumpToConsole();
179 
180  // PDF Options:
181  // ------------------
182  TMonteCarloLocalizationParams pdfPredictionOptions;
183  pdfPredictionOptions.KLD_params.loadFromConfigFile(
184  _configFile, "KLD_options");
185 
186  pdf_.clear();
187 
188  // PDF Options:
189  pdf_.options = pdfPredictionOptions;
190 
191  pdf_.options.metricMap = metric_map_;
192 
193  // Create the PF object:
194  pf_.m_options = pfOptions;
195 }
196 
198 {
199  ROS_INFO("init3DDebug");
200  if (!SHOW_PROGRESS_3D_REAL_TIME_) return;
201  if (!win3D_)
202  {
203  win3D_ = CDisplayWindow3D::Create(
204  "pf-localization - The MRPT project", 1000, 600);
205  win3D_->setCameraZoom(20);
206  win3D_->setCameraAzimuthDeg(-45);
207  // win3D_->waitForKey();
208 
209  // Create the 3D scene and get the map only once, later we'll modify
210  // only the particles, etc..
211  COccupancyGridMap2D::TEntropyInfo grid_info;
212  // The gridmap:
213  if (metric_map_->countMapsByClass<COccupancyGridMap2D>())
214  {
215  metric_map_->mapByClass<COccupancyGridMap2D>()->computeEntropy(
216  grid_info);
217  }
218  else
219  {
220  grid_info.effectiveMappedArea = (init_PDF_max_x - init_PDF_min_x) *
222  }
223  ROS_INFO(
224  "The gridmap has %.04fm2 observed area, %u observed cells\n",
225  grid_info.effectiveMappedArea,
226  (unsigned)grid_info.effectiveMappedCells);
227  ROS_INFO(
228  "Initial PDF: %f particles/m2\n",
229  initial_particle_count_ / grid_info.effectiveMappedArea);
230 
231  auto plane = metric_map_->getVisualization();
232  scene_.insert(plane);
233 
235  {
236  COpenGLScene::Ptr ptr_scene = win3D_->get3DSceneAndLock();
237 
238  ptr_scene->insert(plane);
239 
240  ptr_scene->enableFollowCamera(true);
241 
242  win3D_->unlockAccess3DScene();
243  }
244  } // Show 3D?
245  if (param_->debug)
246  ROS_INFO(" --------------------------- init3DDebug done \n");
247  if (param_->debug) fflush(stdout);
248 }
249 
250 void PFLocalization::show3DDebug(CSensoryFrame::Ptr _observations)
251 {
252  // Create 3D window if requested:
254  {
255  TTimeStamp cur_obs_timestamp = INVALID_TIMESTAMP;
256  if (_observations->size() > 0)
257  cur_obs_timestamp =
258  _observations->getObservationByIndex(0)->timestamp;
259 
260  const auto [cov, meanPose] = pdf_.getCovarianceAndMean();
261 
262  COpenGLScene::Ptr ptr_scene = win3D_->get3DSceneAndLock();
263 
264  win3D_->setCameraPointingToPoint(meanPose.x(), meanPose.y(), 0);
265 
266  mrpt::opengl::TFontParams fp;
267  fp.color = TColorf(.8f, .8f, .8f);
268  fp.vfont_name = "mono";
269  fp.vfont_scale = 15;
270 
271  win3D_->addTextMessage(
272  10, 10,
273  mrpt::format(
274  "timestamp: %s",
275  cur_obs_timestamp != INVALID_TIMESTAMP
276  ? mrpt::system::dateTimeLocalToString(cur_obs_timestamp)
277  .c_str()
278  : "(none)"),
279  6001, fp);
280 
281  win3D_->addTextMessage(
282  10, 33,
283  mrpt::format(
284  "#particles= %7u", static_cast<unsigned int>(pdf_.size())),
285  6002, fp);
286 
287  win3D_->addTextMessage(
288  10, 55,
289  mrpt::format(
290  "mean pose (x y phi_deg)= %s", meanPose.asString().c_str()),
291  6003, fp);
292 
293  // The particles:
294  {
295  CRenderizable::Ptr parts = ptr_scene->getByName("particles");
296  if (parts) ptr_scene->removeObject(parts);
297 
298  CSetOfObjects::Ptr p = pdf_.getAs3DObject<CSetOfObjects::Ptr>();
299  p->setName("particles");
300  ptr_scene->insert(p);
301  }
302 
303  // The particles' cov:
304  {
305  CRenderizable::Ptr ellip = ptr_scene->getByName("parts_cov");
306  if (!ellip)
307  {
308  auto o = CEllipsoid2D::Create();
309  ellip = o;
310  ellip->setName("parts_cov");
311  ellip->setColor(1, 0, 0, 0.6);
312 
313  o->setLineWidth(2);
314  o->setQuantiles(3);
315  o->set2DsegmentsCount(60);
316  ptr_scene->insert(ellip);
317  }
318  ellip->setLocation(meanPose.x(), meanPose.y(), 0.05);
319  dynamic_cast<CEllipsoid2D*>(ellip.get())
320  ->setCovMatrix(cov.blockCopy<2, 2>());
321  }
322 
323  // The laser scan:
324  {
325  CRenderizable::Ptr scan_pts = ptr_scene->getByName("scan");
326  if (!scan_pts)
327  {
328  auto o = CPointCloud::Create();
329  scan_pts = o;
330  scan_pts->setName("scan");
331  scan_pts->setColor(1, 0, 0, 0.9);
332  o->enableColorFromZ(false);
333  o->setPointSize(4);
334  ptr_scene->insert(scan_pts);
335  }
336 
337  CSimplePointsMap map;
338  static CSimplePointsMap last_map;
339 
340  CPose3D robot_pose_3D(meanPose);
341 
342  map.clear();
343  _observations->insertObservationsInto(map);
344 
345  dynamic_cast<CPointCloud*>(scan_pts.get())
346  ->loadFromPointsMap(&last_map);
347  dynamic_cast<CPointCloud*>(scan_pts.get())->setPose(robot_pose_3D);
348  last_map = map;
349  }
350 
351  // The camera:
352  ptr_scene->enableFollowCamera(true);
353 
354  // Views:
355  COpenGLViewport::Ptr view1 = ptr_scene->getViewport("main");
356  {
357  CCamera& cam = view1->getCamera();
358  cam.setAzimuthDegrees(-90);
359  cam.setElevationDegrees(90);
360  cam.setPointingAt(meanPose);
361  cam.setZoomDistance(5);
362  cam.setOrthogonal();
363  }
364 
365  win3D_->unlockAccess3DScene();
366 
367  // Move camera:
368  // win3D_->setCameraPointingToPoint( curRobotPose.x, curRobotPose.y,
369  // curRobotPose.z );
370 
371  // Update:
372  win3D_->forceRepaint();
373 
374  std::this_thread::sleep_for(
375  std::chrono::milliseconds(SHOW_PROGRESS_3D_REAL_TIME_DELAY_MS_));
376  }
377 }
bool SHOW_PROGRESS_3D_REAL_TIME_
virtual ~PFLocalization()
mrpt::gui::CDisplayWindow3D::Ptr win3D_
mrpt::opengl::COpenGLScene scene_
f
int SHOW_PROGRESS_3D_REAL_TIME_DELAY_MS_
int initial_particle_count_
number of particles for initialization
#define M_PI
#define ROS_INFO(...)
mrpt::slam::CMonteCarloLocalization2D pdf_
the filter
mrpt::poses::CPosePDFGaussian initial_pose_
initial posed used in initializeFilter()
virtual bool waitForMap()
#define ROS_INFO_STREAM(args)
void show3DDebug(CSensoryFrame::Ptr _observations)
PFLocalization(Parameters *parm)
#define DEG2RAD(x)
mrpt::bayes::CParticleFilter pf_
common interface for particle filters
CActionRobotMovement2D::TMotionModelOptions motion_model_default_options_
used if there are is not odom
void configureFilter(const mrpt::config::CConfigFile &_configFile)
Parameters * param_
CMultiMetricMap::Ptr metric_map_
map
#define ROS_DEBUG(...)


mrpt_localization
Author(s): Markus Bader, Raphael Zack
autogenerated on Thu Jun 1 2023 03:07:06