LaserScanner.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2024 Jose Luis Blanco Claraco |
5  | Copyright (C) 2017 Borys Tymchenko (Odessa Polytechnic University) |
6  | Distributed under 3-clause BSD License |
7  | See COPYING |
8  +-------------------------------------------------------------------------+ */
9 
10 #include <mrpt/core/lock_helper.h>
11 #include <mrpt/opengl/COpenGLScene.h>
12 #include <mrpt/opengl/stock_objects.h>
13 #include <mrpt/random.h>
14 #include <mrpt/version.h>
16 #include <mvsim/VehicleBase.h>
17 #include <mvsim/World.h>
19 
20 #include "xml_utils.h"
21 
22 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
23 #include <mvsim/mvsim-msgs/ObservationLidar2D.pb.h>
24 #endif
25 
26 using namespace mvsim;
27 using namespace rapidxml;
28 
29 int z_order_cnt = 0;
30 
32  : SensorBase(parent), z_order_(++z_order_cnt)
33 {
35 }
36 
38 
40 {
41  gui_uptodate_ = false;
42 
45 
46  // Other scalar params:
47  int nRays = 181;
48  double fov_deg = 180;
49  scan_model_.sensorPose.z() = 0.05;
50 
51  TParameterDefinitions params;
52  params["fov_degrees"] = TParamEntry("%lf", &fov_deg);
53  params["nrays"] = TParamEntry("%i", &nRays);
54  params["pose"] = TParamEntry("%pose2d_ptr3d", &scan_model_.sensorPose);
55  params["pose_3d"] = TParamEntry("%pose3d", &scan_model_.sensorPose);
56  params["height"] = TParamEntry("%lf", &scan_model_.sensorPose.z());
57  params["range_std_noise"] = TParamEntry("%lf", &rangeStdNoise_);
58  params["max_range"] = TParamEntry("%f", &scan_model_.maxRange);
59  params["angle_std_noise_deg"] = TParamEntry("%lf_deg", &angleStdNoise_);
60  params["sensor_period"] = TParamEntry("%lf", &sensor_period_);
61  params["bodies_visible"] = TParamEntry("%bool", &see_fixtures_);
62 
63  params["viz_pointSize"] = TParamEntry("%f", &viz_pointSize_);
64  params["viz_visiblePlane"] = TParamEntry("%bool", &viz_visiblePlane_);
65  params["viz_visibleLines"] = TParamEntry("%bool", &viz_visibleLines_);
66  params["viz_visiblePoints"] = TParamEntry("%bool", &viz_visiblePoints_);
67 
68  params["viz_pointsColor"] = TParamEntry("%color", &viz_pointsColor_);
69  params["viz_planeColor"] = TParamEntry("%color", &viz_planeColor_);
70 
71  params["raytrace_3d"] = TParamEntry("%bool", &raytrace_3d_);
72  params["ignore_parent_body"] = TParamEntry("%bool", &ignore_parent_body_);
73 
74  // Parse XML params:
76 
77  // Pass params to the scan2D obj:
78  scan_model_.aperture = mrpt::DEG2RAD(fov_deg);
79  scan_model_.resizeScan(nRays);
80  scan_model_.stdError = rangeStdNoise_;
81 
82  scan_model_.sensorLabel = name_;
83 }
84 
86  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& viz,
87  [[maybe_unused]] const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& physical,
88  [[maybe_unused]] bool childrenOnly)
89 {
90  using namespace std::string_literals;
91 
92  mrpt::opengl::CSetOfObjects::Ptr glVizSensors;
93  if (viz)
94  {
95  glVizSensors = std::dynamic_pointer_cast<mrpt::opengl::CSetOfObjects>(
96  viz->get().getByName("group_sensors_viz"));
97  if (!glVizSensors) return; // may happen during shutdown
98  }
99 
100  // 1st time?
101  if (!gl_scan_ && glVizSensors)
102  {
103  gl_scan_ = mrpt::opengl::CPlanarLaserScan::Create();
104 
105  gl_scan_->enablePoints(viz_visiblePoints_);
106  gl_scan_->setPointSize(viz_pointSize_);
107  const mrpt::img::TColorf ptsCol(viz_pointsColor_);
108  gl_scan_->setPointsColor(ptsCol.R, ptsCol.G, ptsCol.B, ptsCol.A);
109 
110  gl_scan_->enableSurface(viz_visiblePlane_);
111  const mrpt::img::TColorf planeCol(viz_planeColor_);
112  gl_scan_->setSurfaceColor(planeCol.R, planeCol.G, planeCol.B, planeCol.A);
113 
114  gl_scan_->enableLine(viz_visibleLines_);
115 
116  gl_scan_->setLocalRepresentativePoint({0, 0, 0.10f});
117  gl_scan_->setName("glScan veh:"s + vehicle_.getName() + " sensor:"s + this->name_);
118 
119  glVizSensors->insert(gl_scan_);
120  }
121  if (!gl_sensor_origin_ && viz)
122  {
123  gl_sensor_origin_ = mrpt::opengl::CSetOfObjects::Create();
124 #if MRPT_VERSION >= 0x270
125  gl_sensor_origin_->castShadows(false);
126 #endif
127  gl_sensor_origin_corner_ = mrpt::opengl::stock_objects::CornerXYZSimple(0.15f);
128 
130 
131  gl_sensor_origin_->setVisibility(false);
132  viz->get().insert(gl_sensor_origin_);
134  }
135  if (!gl_sensor_fov_ && viz)
136  {
137  gl_sensor_fov_ = mrpt::opengl::CSetOfObjects::Create();
138 #if MRPT_VERSION >= 0x270
139  gl_sensor_fov_->castShadows(false);
140 #endif
141 
142  auto fovScan = mrpt::opengl::CPlanarLaserScan::Create();
143  fovScan->enablePoints(false);
144  fovScan->enableSurface(true);
145 
146  mrpt::obs::CObservation2DRangeScan s = scan_model_;
147  const float f = 0.30f;
148  for (size_t i = 0; i < s.getScanSize(); i++)
149  {
150  s.setScanRange(i, f);
151  s.setScanRangeValidity(i, true);
152  }
153  fovScan->setScan(s);
154 
155  gl_sensor_fov_->insert(fovScan);
156 
157  gl_sensor_fov_->setVisibility(false);
158  viz->get().insert(gl_sensor_fov_);
160  }
161 
162  if (!gui_uptodate_ && glVizSensors->isVisible())
163  {
164  {
165  std::lock_guard<std::mutex> csl(last_scan_cs_);
166  if (last_scan2gui_)
167  {
168  gl_scan_->setScan(*last_scan2gui_);
169  gl_sensor_origin_corner_->setPose(last_scan2gui_->sensorPose);
170 
171  last_scan2gui_.reset();
172  }
173  }
174  gui_uptodate_ = true;
175  }
176 
177  const mrpt::poses::CPose3D p = vehicle_.getCPose3D();
178  const auto pp = parent()->applyWorldRenderOffset(p);
179 
180  const double z_incrs = 1e-3; // for z_order_
181  const double z_offset = 1e-3;
182 
183  if (gl_scan_)
184  {
185  auto p2 = pp;
186  p2.z_incr(z_offset + z_incrs * z_order_);
187  gl_scan_->setPose(p2);
188  }
189 
190  if (gl_sensor_fov_) gl_sensor_fov_->setPose(pp);
191  if (gl_sensor_origin_) gl_sensor_origin_->setPose(pp);
192  if (glCustomVisual_) glCustomVisual_->setPose(pp + scan_model_.sensorPose);
193 }
194 
195 void LaserScanner::simul_pre_timestep([[maybe_unused]] const TSimulContext& context) {}
196 
197 // Simulate sensor AFTER timestep, with the updated vehicle dynamical state:
199 {
201 
203  {
204  if (raytrace_3d_)
205  {
206  auto lckHasTo = mrpt::lockHelper(has_to_render_mtx_);
207 
208  // Will run upon next async call of simulateOn3DScene()
209  if (has_to_render_.has_value())
210  {
211  world_->logFmt(
212  mrpt::system::LVL_WARN,
213  "Time for a new sample came without still simulating the "
214  "last one (!) for simul_time=%.03f s.",
215  has_to_render_->simul_time);
216  }
217 
218  has_to_render_ = context;
220  }
221  else
222  {
223  // 2D mode:
225  }
226  }
227 
228  // Keep sensor global pose up-to-date:
229  const auto& p = vehicle_.getPose();
230  const auto globalSensorPose = p + scan_model_.sensorPose.asTPose();
231  Simulable::setPose(globalSensorPose, false /*do not notify*/);
232 }
233 
234 void LaserScanner::notifySimulableSetPose(const mrpt::math::TPose3D& newPose)
235 {
236  // The editor has moved the sensor in global coordinates.
237  // Convert back to local:
238  const auto& p = vehicle_.getPose();
239  scan_model_.sensorPose = mrpt::poses::CPose3D(newPose - p);
240 }
241 
243 {
244  using mrpt::maps::COccupancyGridMap2D;
245  using mrpt::obs::CObservation2DRangeScan;
246 
247  auto tle = mrpt::system::CTimeLoggerEntry(world_->getTimeLogger(), "LaserScanner");
248 
249  // Create an array of scans, each reflecting ranges to one kind of world
250  // objects.
251  // Finally, we'll take the shortest range in each direction:
252  std::list<CObservation2DRangeScan> lstScans;
253 
254  const size_t nRays = scan_model_.getScanSize();
255  const double maxRange = scan_model_.maxRange;
256 
257  // Get pose of the robot:
258  const mrpt::poses::CPose2D vehPose = vehicle_.getCPose2D();
259 
260  // grid maps:
261  // -------------
262  world_->getTimeLogger().enter("LaserScanner.scan.1.gridmap");
263 
265 
266  for (const auto& element : elements)
267  {
268  // If not a grid map, ignore:
269  const OccupancyGridMap* grid = dynamic_cast<const OccupancyGridMap*>(element.get());
270  if (!grid) continue;
271  const COccupancyGridMap2D& occGrid = grid->getOccGrid();
272 
273  // Create new scan:
274  lstScans.emplace_back(scan_model_);
275  CObservation2DRangeScan& scan = lstScans.back();
276 
277  // Ray tracing over the gridmap:
278  occGrid.laserScanSimulator(
279  scan, vehPose, 0.5f, scan_model_.getScanSize(), rangeStdNoise_, 1, angleStdNoise_);
280  }
281  world_->getTimeLogger().leave("LaserScanner.scan.1.gridmap");
282 
283  // ray trace on Box2D polygons:
284  // ------------------------------
285  world_->getTimeLogger().enter("LaserScanner.scan.2.polygons");
286  {
287  // Create new scan:
288  lstScans.push_back(CObservation2DRangeScan(scan_model_));
289  CObservation2DRangeScan& scan = lstScans.back();
290 
291  // Avoid the lidar seeing the vehicle owns shape:
292  std::map<b2Fixture*, uintptr_t> orgUserData;
293 
294  auto makeFixtureInvisible = [&](b2Fixture* f)
295  {
296  if (!f) return;
297  orgUserData[f] = f->GetUserData().pointer;
298  f->GetUserData().pointer = INVISIBLE_FIXTURE_USER_DATA;
299  };
300  auto undoInvisibleFixtures = [&]()
301  {
302  for (auto& kv : orgUserData) kv.first->GetUserData().pointer = kv.second;
303  };
304 
305  if (auto v = dynamic_cast<VehicleBase*>(&vehicle_); v)
306  {
307  makeFixtureInvisible(v->get_fixture_chassis());
308  for (auto& f : v->get_fixture_wheels()) makeFixtureInvisible(f);
309  }
310 
311  // Do Box2D raycasting stuff:
312  // ------------------------------
313  // This callback finds the closest hit. Polygon 0 is filtered.
315  {
316  public:
317  RayCastClosestCallback() = default;
318 
319  float ReportFixture(
320  b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal,
321  float fraction) override
322  {
324  {
325  // By returning -1, we instruct the calling code to ignore
326  // this fixture and
327  // continue the ray-cast to the next fixture.
328  return -1.0f;
329  }
330 
331  hit_ = true;
332  point_ = point;
333  normal_ = normal;
334  // By returning the current fraction, we instruct the calling
335  // code to clip the ray and
336  // continue the ray-cast to the next fixture. WARNING: do not
337  // assume that fixtures
338  // are reported in order. However, by clipping, we can always
339  // get the closest fixture.
340  return fraction;
341  }
342 
343  bool see_fixtures_ = true;
344  bool hit_ = false;
345  b2Vec2 point_{0, 0};
346  b2Vec2 normal_{0, 0};
347  };
348 
349  const mrpt::poses::CPose2D sensorPose = vehPose + mrpt::poses::CPose2D(scan.sensorPose);
350  const b2Vec2 sensorPt = b2Vec2(sensorPose.x(), sensorPose.y());
351 
352  RayCastClosestCallback callback;
353  callback.see_fixtures_ = see_fixtures_;
354 
355  // Scan size:
356  ASSERT_(nRays >= 2);
357  scan.resizeScanAndAssign(nRays, maxRange, false);
358  double A = sensorPose.phi() + (scan.rightToLeft ? -0.5 : +0.5) * scan.aperture;
359  const double AA = (scan.rightToLeft ? 1.0 : -1.0) * (scan.aperture / (nRays - 1));
360 
361  // Each thread must create its own rng:
362  thread_local mrpt::random::CRandomGenerator rnd;
363 
364  for (size_t i = 0; i < nRays; i++, A += AA)
365  {
366  const b2Vec2 endPt =
367  b2Vec2(sensorPt.x + cos(A) * maxRange, sensorPt.y + sin(A) * maxRange);
368 
369  callback.hit_ = false;
370  world_->getBox2DWorld()->RayCast(&callback, sensorPt, endPt);
371  scan.setScanRangeValidity(i, callback.hit_);
372 
373  float range = 0;
374  if (callback.hit_)
375  {
376  // Hit:
377  range = std::sqrt(
378  mrpt::square(callback.point_.x - sensorPt.x) +
379  mrpt::square(callback.point_.y - sensorPt.y));
380  range += rnd.drawGaussian1D_normalized() * rangeStdNoise_;
381  }
382  else
383  {
384  // Miss:
385  range = maxRange;
386  }
387  scan.setScanRange(i, range);
388  } // end for (raycast scan)
389 
390  undoInvisibleFixtures();
391  }
392  world_->getTimeLogger().leave("LaserScanner.scan.2.polygons");
393 
394  // Summarize all scans in one single scan:
395  // ----------------------------------------
396  world_->getTimeLogger().enter("LaserScanner.scan.3.merge");
397 
398  auto lastScan = CObservation2DRangeScan::Create(scan_model_);
399 
400  lastScan->timestamp = world_->get_simul_timestamp();
401  lastScan->sensorLabel = name_;
402 
403  lastScan->resizeScanAndAssign(nRays, maxRange, false);
404 
405  for (const auto& scan : lstScans)
406  {
407  for (size_t i = 0; i < nRays; i++)
408  {
409  if (scan.getScanRangeValidity(i))
410  {
411  lastScan->setScanRange(
412  i, std::min(lastScan->getScanRange(i), scan.getScanRange(i)));
413  lastScan->setScanRangeValidity(i, true);
414  }
415  }
416  }
417  world_->getTimeLogger().leave("LaserScanner.scan.3.merge");
418 
419  {
420  std::lock_guard<std::mutex> csl(last_scan_cs_);
421  last_scan_ = std::move(lastScan);
423  }
424 
425  // publish as generic Protobuf (mrpt serialized) object:
427 
428  // Publish custom 2d-lidar observation type too:
430 
431  gui_uptodate_ = false;
432 }
433 
435 {
436  // Free fbo:
437  fbo_renderer_depth_.reset();
438 }
439 
440 void LaserScanner::simulateOn3DScene(mrpt::opengl::COpenGLScene& world3DScene)
441 {
442  using namespace mrpt; // _deg
443 
444  {
445  auto lckHasTo = mrpt::lockHelper(has_to_render_mtx_);
446  if (!has_to_render_.has_value()) return;
447  }
448 
449  auto tleWhole = mrpt::system::CTimeLoggerEntry(world_->getTimeLogger(), "sensor.2Dlidar");
450 
451  auto tle1 = mrpt::system::CTimeLoggerEntry(world_->getTimeLogger(), "sensor.2Dlidar.acqGuiMtx");
452 
453  tle1.stop();
454 
455  if (glCustomVisual_) glCustomVisual_->setVisibility(false);
456 
457  // Start making a copy of the pattern observation:
458  auto curObs = mrpt::obs::CObservation2DRangeScan::Create(scan_model_);
459 
460  const size_t nRays = scan_model_.getScanSize();
461  const double maxRange = scan_model_.maxRange;
462 
463  curObs->timestamp = world_->get_simul_timestamp();
464  curObs->sensorLabel = name_;
465 
466  curObs->resizeScanAndAssign(nRays, maxRange, false);
467 
468  // Create FBO on first use, now that we are here at the GUI / OpenGL thread.
469  constexpr int FBO_NROWS = 1;
470  constexpr int FBO_NCOLS = 500;
471  constexpr double camModel_FOV = 150.0_deg;
472  mrpt::img::TCamera camModel;
473  camModel.ncols = FBO_NCOLS;
474  camModel.nrows = FBO_NROWS;
475  camModel.cx(camModel.ncols / 2.0);
476  camModel.cy(camModel.nrows / 2.0);
477  camModel.fx(camModel.cx() / tan(camModel_FOV * 0.5)); // tan(FOV/2)=cx/fx
478  camModel.fy(camModel.fx());
479 
480  if (!fbo_renderer_depth_)
481  {
482  mrpt::opengl::CFBORender::Parameters p;
483  p.width = FBO_NCOLS;
484  p.height = FBO_NROWS;
485  p.create_EGL_context = world()->sensor_has_to_create_egl_context();
486 
487  fbo_renderer_depth_ = std::make_shared<mrpt::opengl::CFBORender>(p);
488  }
489 
490  auto viewport = world3DScene.getViewport();
491 
492  auto& cam = fbo_renderer_depth_->getCamera(world3DScene);
493 
494  const auto fixedAxisConventionRot =
495  mrpt::poses::CPose3D(0, 0, 0, -90.0_deg, 0.0_deg, -90.0_deg);
496 
497  const auto vehiclePose = mrpt::poses::CPose3D(vehicle_.getPose());
498 
499  // ----------------------------------------------------------
500  // Decompose the 2D lidar FOV into "n" depth camera images,
501  // of camModel_FOV each.
502  // ----------------------------------------------------------
503  const auto firstAngle = curObs->getScanAngle(0); // wrt sensorPose
504  const auto lastAngle = curObs->getScanAngle(curObs->getScanSize() - 1);
505  const bool scanIsCW = (lastAngle > firstAngle);
506  ASSERT_NEAR_(std::abs(lastAngle - firstAngle), curObs->aperture, 1e-3);
507 
508  const unsigned int numRenders = std::ceil((curObs->aperture / camModel_FOV) - 1e-3);
509  const auto numRaysPerRender =
510  mrpt::round(nRays * std::min<double>(1.0, (camModel_FOV / curObs->aperture)));
511 
512  ASSERT_(numRaysPerRender > 0);
513 
514  // Precomputed LUT of bearings to pixel coordinates:
515  // cx - u
516  // tan(bearing) = --------------
517  // fx
518  //
519  if (angleIdx2pixelIdx_.empty())
520  {
521  angleIdx2pixelIdx_.resize(numRaysPerRender);
522  angleIdx2secant_.resize(numRaysPerRender);
523 
524  for (int i = 0; i < numRaysPerRender; i++)
525  {
526  const auto ang = (scanIsCW ? -1 : 1) *
527  (camModel_FOV * 0.5 - i * camModel_FOV / (numRaysPerRender - 1));
528 
529  const auto pixelIdx = mrpt::saturate_val<int>(
530  mrpt::round(camModel.cx() - camModel.fx() * std::tan(ang)), 0, camModel.ncols - 1);
531 
532  angleIdx2pixelIdx_.at(i) = pixelIdx;
533  angleIdx2secant_.at(i) = 1.0f / std::cos(ang);
534  }
535  }
536  else
537  {
538  // sanity check:
539  ASSERT_EQUAL_(angleIdx2pixelIdx_.size(), numRaysPerRender);
540  ASSERT_EQUAL_(angleIdx2secant_.size(), numRaysPerRender);
541  }
542 
543  // ----------------------------------------------------------
544  // "DEPTH camera" to generate lidar readings:
545  // ----------------------------------------------------------
546  cam.set6DOFMode(true);
547  cam.setProjectiveFromPinhole(camModel);
548 
549  // Disable rendering of shadows for this sensor:
550 #if MRPT_VERSION >= 0x270
551  const bool wasShadowEnabled = viewport->isShadowCastingEnabled();
552  viewport->enableShadowCasting(false);
553 #endif
554 
555  viewport->setViewportClipDistances(0.01, curObs->maxRange);
556  mrpt::math::CMatrixFloat depthImage;
557 
558  // make owner's own body invisible?
559  auto visVeh = dynamic_cast<VisualObject*>(&vehicle_);
560  auto veh = dynamic_cast<VehicleBase*>(&vehicle_);
561  bool formerVisVehState = true;
563  {
564  if (visVeh)
565  {
566  formerVisVehState = visVeh->customVisualVisible();
567  visVeh->customVisualVisible(false);
568  }
569  if (veh) veh->chassisAndWheelsVisible(false);
570  }
571 
572  for (size_t renderIdx = 0; renderIdx < numRenders; renderIdx++)
573  {
574  const double thisRenderMidAngle =
575  firstAngle + (camModel_FOV / 2.0 + camModel_FOV * renderIdx) * (scanIsCW ? 1 : -1);
576 
577  const auto depthSensorPose =
578  vehiclePose + curObs->sensorPose +
579  mrpt::poses::CPose3D::FromYawPitchRoll(thisRenderMidAngle, 0.0, 0.0) +
580  fixedAxisConventionRot;
581 
582  // Camera pose: vehicle + relativePoseOnVehicle:
583  // Note: relativePoseOnVehicle should be (y,p,r)=(90deg,0,90deg) to make
584  // the camera to look forward:
585  cam.setPose(world()->applyWorldRenderOffset(depthSensorPose));
586 
587  auto tleRender =
588  mrpt::system::CTimeLoggerEntry(world_->getTimeLogger(), "sensor.2Dlidar.renderSubScan");
589 
590  fbo_renderer_depth_->render_depth(world3DScene, depthImage);
591 
592  tleRender.stop();
593 
594  // Add random noise:
595  if (rangeStdNoise_ > 0)
596  {
597  auto tleStore =
598  mrpt::system::CTimeLoggerEntry(world_->getTimeLogger(), "sensor.2Dlidar.noise");
599 
600  // Each thread must create its own rng:
601  thread_local mrpt::random::CRandomGenerator rng;
602 
603  float* d = depthImage.data();
604  const size_t N = depthImage.size();
605  for (size_t i = 0; i < N; i++)
606  {
607  if (d[i] == 0) continue; // it was an invalid ray return.
608 
609  const float dNoisy = d[i] + rng.drawGaussian1D(0, rangeStdNoise_);
610 
611  if (dNoisy < 0 || dNoisy > curObs->maxRange) continue;
612 
613  d[i] = dNoisy;
614  }
615  }
616 
617  auto tleStore =
618  mrpt::system::CTimeLoggerEntry(world_->getTimeLogger(), "sensor.2Dlidar.storeObs");
619 
620  // Convert depth into range and store into scan observation:
621  for (int i = 0; i < numRaysPerRender; i++)
622  {
623  const auto scanRayIdx = numRaysPerRender * renderIdx + i;
624  // done with full scan range?
625  if (scanRayIdx >= curObs->getScanSize()) break;
626 
627  const auto u = angleIdx2pixelIdx_.at(i);
628 
629  const float d = depthImage(0, u);
630  const float range = d * angleIdx2secant_.at(i);
631 
632  if (range <= 0 || range >= curObs->maxRange) continue; // invalid
633 
634  curObs->setScanRange(scanRayIdx, range);
635  curObs->setScanRangeValidity(scanRayIdx, true);
636  }
637  tleStore.stop();
638  }
639 
641  {
642  if (visVeh) visVeh->customVisualVisible(formerVisVehState);
643  if (veh) veh->chassisAndWheelsVisible(formerVisVehState);
644  }
645 
646 #if MRPT_VERSION >= 0x270
647  viewport->enableShadowCasting(wasShadowEnabled);
648 #endif
649 
650  // Store generated obs:
651  {
652  auto tle3 =
653  mrpt::system::CTimeLoggerEntry(world_->getTimeLogger(), "sensor.2Dlidar.acqObsMtx");
654 
655  std::lock_guard<std::mutex> csl(last_scan_cs_);
656  last_scan_ = std::move(curObs);
658  }
659 
660  {
661  auto lckHasTo = mrpt::lockHelper(has_to_render_mtx_);
662 
663  auto tlePub =
664  mrpt::system::CTimeLoggerEntry(world_->getTimeLogger(), "sensor.2Dlidar.report");
665 
666  // publish as generic Protobuf (mrpt serialized) object:
668 
669  // Publish custom 2d-lidar observation type too:
671 
672  tlePub.stop();
673 
674  if (glCustomVisual_) glCustomVisual_->setVisibility(true);
675 
676  gui_uptodate_ = false;
677 
678  has_to_render_.reset();
679  }
680 }
681 
683 {
684  using namespace std::string_literals;
685 
687 
688 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
689  // Topic:
690  if (!publishTopic_.empty())
691  c.advertiseTopic<mvsim_msgs::ObservationLidar2D>(publishTopic_ + "_scan"s);
692 #endif
693 }
mvsim::LaserScanner::raytrace_3d_
bool raytrace_3d_
Definition: LaserScanner.h:78
mvsim::VisualObject::parent
World * parent()
Definition: VisualObject.h:51
mvsim::LaserScanner::internalGuiUpdate
virtual void internalGuiUpdate(const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &viz, const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &physical, bool childrenOnly) override
Definition: LaserScanner.cpp:85
mvsim
Definition: Client.h:21
mvsim::SensorBase::reportNewObservation_lidar_2d
void reportNewObservation_lidar_2d(const std::shared_ptr< mrpt::obs::CObservation2DRangeScan > &obs, const TSimulContext &context)
Definition: SensorBase.cpp:185
mvsim::Simulable::getName
const std::string & getName() const
Definition: Simulable.h:107
b2Vec2::y
float y
Definition: b2_math.h:128
mvsim::VisualObject::world_
World * world_
Definition: VisualObject.h:73
mvsim::LaserScanner::rangeStdNoise_
double rangeStdNoise_
Definition: LaserScanner.h:70
mvsim::SensorBase::make_sure_we_have_a_name
void make_sure_we_have_a_name(const std::string &prefix)
Assign a sensible default name/sensor label if none is provided:
Definition: SensorBase.cpp:252
mvsim::LaserScanner::viz_visibleLines_
bool viz_visibleLines_
Definition: LaserScanner.h:83
mvsim::SensorBase::varValues_
std::map< std::string, std::string > varValues_
Filled in by SensorBase::loadConfigFrom()
Definition: SensorBase.h:97
mvsim::SensorBase::reportNewObservation
void reportNewObservation(const std::shared_ptr< mrpt::obs::CObservation > &obs, const TSimulContext &context)
Definition: SensorBase.cpp:159
mvsim::World::WorldElementList
std::list< WorldElementBase::Ptr > WorldElementList
Definition: World.h:294
b2RayCastCallback
Definition: b2_world_callbacks.h:140
mvsim::TParamEntry
Definition: TParameterDefinitions.h:38
s
XmlRpcServer s
mvsim::parse_xmlnode_children_as_param
void parse_xmlnode_children_as_param(const rapidxml::xml_node< char > &xml_node, const TParameterDefinitions &params, const std::map< std::string, std::string > &variableNamesValues={}, const char *functionNameContext="", mrpt::system::COutputLogger *logger=nullptr)
Definition: xml_utils.cpp:215
mvsim::LaserScanner::~LaserScanner
virtual ~LaserScanner()
Definition: LaserScanner.cpp:37
mvsim::LaserScanner::see_fixtures_
bool see_fixtures_
Definition: LaserScanner.h:74
mvsim::LaserScanner::internal_simulate_lidar_2d_mode
void internal_simulate_lidar_2d_mode(const TSimulContext &context)
Definition: LaserScanner.cpp:242
mvsim::LaserScanner::angleIdx2pixelIdx_
std::vector< size_t > angleIdx2pixelIdx_
Definition: LaserScanner.h:111
mvsim::World::applyWorldRenderOffset
mrpt::math::TPose3D applyWorldRenderOffset(mrpt::math::TPose3D p) const
Definition: World.h:631
World.h
mvsim::Simulable::getCPose3D
mrpt::poses::CPose3D getCPose3D() const
Alternative to getPose()
Definition: Simulable.cpp:157
mvsim::Client
Definition: Client.h:48
mvsim::SensorBase::vehicle_
Simulable & vehicle_
The vehicle this sensor is attached to.
Definition: SensorBase.h:82
mvsim::SensorBase
Virtual base class for all sensors.
Definition: SensorBase.h:34
mvsim::OccupancyGridMap::getOccGrid
const mrpt::maps::COccupancyGridMap2D & getOccGrid() const
Definition: OccupancyGridMap.h:44
mvsim::LaserScanner::angleStdNoise_
double angleStdNoise_
Definition: LaserScanner.h:71
mvsim::LaserScanner::gl_scan_
mrpt::opengl::CPlanarLaserScan::Ptr gl_scan_
Definition: LaserScanner.h:102
mvsim::SensorBase::registerOnServer
void registerOnServer(mvsim::Client &c) override
Definition: SensorBase.cpp:220
mrpt
Definition: basic_types.h:36
mvsim::OccupancyGridMap
Definition: OccupancyGridMap.h:28
mvsim::World::sensor_has_to_create_egl_context
bool sensor_has_to_create_egl_context()
Definition: World.cpp:191
b2Vec2
A 2D column vector.
Definition: b2_math.h:41
b2FixtureUserData::pointer
uintptr_t pointer
For legacy compatibility.
Definition: b2_settings.h:78
xml_utils.h
f
f
mvsim::SensorBase::should_simulate_sensor
bool should_simulate_sensor(const TSimulContext &context)
Definition: SensorBase.cpp:262
mvsim::LaserScanner::last_scan_cs_
std::mutex last_scan_cs_
Definition: LaserScanner.h:93
mvsim::LaserScanner::last_scan2gui_
mrpt::obs::CObservation2DRangeScan::Ptr last_scan2gui_
Definition: LaserScanner.h:96
mvsim::LaserScanner::simul_pre_timestep
virtual void simul_pre_timestep(const TSimulContext &context) override
Definition: LaserScanner.cpp:195
mvsim::LaserScanner::viz_pointsColor_
mrpt::img::TColor viz_pointsColor_
Definition: LaserScanner.h:86
VehicleBase.h
mvsim::World::getListOfWorldElements
const WorldElementList & getListOfWorldElements() const
Definition: World.h:314
A
mvsim::LaserScanner::ignore_parent_body_
bool ignore_parent_body_
Definition: LaserScanner.h:80
mvsim::LaserScanner::viz_planeColor_
mrpt::img::TColor viz_planeColor_
Definition: LaserScanner.h:87
mvsim::LaserScanner::gl_sensor_origin_
mrpt::opengl::CSetOfObjects::Ptr gl_sensor_origin_
Definition: LaserScanner.h:103
mvsim::SensorBase::world
World * world()
Definition: SensorBase.h:84
mvsim::LaserScanner::freeOpenGLResources
void freeOpenGLResources() override
Definition: LaserScanner.cpp:434
RayCastClosestCallback
Definition: ray_cast.cpp:37
rapidxml
Definition: rapidxml.hpp:57
mvsim::TSimulContext
Definition: basic_types.h:58
mvsim::World::get_simul_timestamp
mrpt::Clock::time_point get_simul_timestamp() const
Definition: World.h:137
mvsim::LaserScanner::scan_model_
mrpt::obs::CObservation2DRangeScan scan_model_
Definition: LaserScanner.h:91
mvsim::LaserScanner::last_scan_
mrpt::obs::CObservation2DRangeScan::Ptr last_scan_
Definition: LaserScanner.h:95
mvsim::TParameterDefinitions
std::map< std::string, TParamEntry > TParameterDefinitions
Definition: TParameterDefinitions.h:64
b2Fixture
Definition: b2_fixture.h:116
mvsim::LaserScanner::loadConfigFrom
virtual void loadConfigFrom(const rapidxml::xml_node< char > *root) override
Definition: LaserScanner.cpp:39
mvsim::LaserScanner::has_to_render_mtx_
std::mutex has_to_render_mtx_
Definition: LaserScanner.h:107
mvsim::LaserScanner::z_order_
int z_order_
to help rendering multiple scans
Definition: LaserScanner.h:68
b2Fixture::GetUserData
b2FixtureUserData & GetUserData()
Definition: b2_fixture.h:278
d
d
mvsim::Simulable::simul_post_timestep
virtual void simul_post_timestep(const TSimulContext &context)
Definition: Simulable.cpp:64
mvsim::World::getBox2DWorld
std::unique_ptr< b2World > & getBox2DWorld()
Definition: World.h:307
mvsim::World::mark_as_pending_running_sensors_on_3D_scene
void mark_as_pending_running_sensors_on_3D_scene()
Definition: World.h:223
mvsim::LaserScanner::registerOnServer
void registerOnServer(mvsim::Client &c) override
Definition: LaserScanner.cpp:682
mvsim::Simulable::name_
std::string name_
Definition: Simulable.h:145
mvsim::SensorBase::sensor_period_
double sensor_period_
Definition: SensorBase.h:88
mvsim::LaserScanner::simul_post_timestep
virtual void simul_post_timestep(const TSimulContext &context) override
Definition: LaserScanner.cpp:198
b2Vec2::x
float x
Definition: b2_math.h:128
mvsim::LaserScanner::gl_sensor_origin_corner_
mrpt::opengl::CSetOfObjects::Ptr gl_sensor_origin_corner_
Definition: LaserScanner.h:103
mvsim::LaserScanner::gl_sensor_fov_
mrpt::opengl::CSetOfObjects::Ptr gl_sensor_fov_
Definition: LaserScanner.h:104
mvsim::LaserScanner::viz_visiblePlane_
bool viz_visiblePlane_
Definition: LaserScanner.h:82
mvsim::SensorBase::publishTopic_
std::string publishTopic_
Definition: SensorBase.h:94
mvsim::VisualObject::customVisualVisible
void customVisualVisible(const bool visible)
Definition: VisualObject.cpp:250
mvsim::Simulable::setPose
void setPose(const mrpt::math::TPose3D &p, bool notifyChange=true) const
Definition: Simulable.cpp:474
mvsim::INVISIBLE_FIXTURE_USER_DATA
constexpr uintptr_t INVISIBLE_FIXTURE_USER_DATA
Used to signal a Box2D fixture as "invisible" to sensors.
Definition: basic_types.h:67
mvsim::VehicleBase
Definition: VehicleBase.h:44
rapidxml::xml_node< char >
mvsim::LaserScanner::gui_uptodate_
bool gui_uptodate_
Definition: LaserScanner.h:100
mvsim::LaserScanner::fbo_renderer_depth_
std::shared_ptr< mrpt::opengl::CFBORender > fbo_renderer_depth_
Definition: LaserScanner.h:109
mvsim::LaserScanner::has_to_render_
std::optional< TSimulContext > has_to_render_
Definition: LaserScanner.h:106
mvsim::Simulable
Definition: Simulable.h:39
OccupancyGridMap.h
mvsim::Client::advertiseTopic
void advertiseTopic(const std::string &topicName)
Definition: Client.h:177
mvsim::LaserScanner::viz_visiblePoints_
bool viz_visiblePoints_
Definition: LaserScanner.h:84
mvsim::SensorBase::loadConfigFrom
virtual void loadConfigFrom(const rapidxml::xml_node< char > *root)
Definition: SensorBase.cpp:231
mvsim::Simulable::getPose
mrpt::math::TPose3D getPose() const
Definition: Simulable.cpp:490
mvsim::World::getTimeLogger
mrpt::system::CTimeLogger & getTimeLogger()
Definition: World.h:321
root
root
mvsim::Simulable::getCPose2D
mrpt::poses::CPose2D getCPose2D() const
Alternative to getPose()
Definition: Simulable.cpp:150
mvsim::VisualObject::glCustomVisual_
std::shared_ptr< mrpt::opengl::CSetOfObjects > glCustomVisual_
Definition: VisualObject.h:77
LaserScanner.h
mvsim::LaserScanner::viz_pointSize_
float viz_pointSize_
Definition: LaserScanner.h:85
mvsim::LaserScanner::simulateOn3DScene
void simulateOn3DScene(mrpt::opengl::COpenGLScene &gl_scene) override
Definition: LaserScanner.cpp:440
mvsim::LaserScanner::notifySimulableSetPose
void notifySimulableSetPose(const mrpt::math::TPose3D &newPose) override
Definition: LaserScanner.cpp:234
mvsim::LaserScanner::LaserScanner
LaserScanner(Simulable &parent, const rapidxml::xml_node< char > *root)
Definition: LaserScanner.cpp:31
mvsim::LaserScanner::angleIdx2secant_
std::vector< float > angleIdx2secant_
Definition: LaserScanner.h:112
z_order_cnt
int z_order_cnt
Definition: LaserScanner.cpp:29
mvsim::VisualObject
Definition: VisualObject.h:35
mvsim::SensorBase::RegisterSensorFOVViz
static void RegisterSensorFOVViz(const std::shared_ptr< mrpt::opengl::CSetOfObjects > &o)
Definition: SensorBase.cpp:73
mvsim::SensorBase::RegisterSensorOriginViz
static void RegisterSensorOriginViz(const std::shared_ptr< mrpt::opengl::CSetOfObjects > &o)
Definition: SensorBase.cpp:78


mvsim
Author(s):
autogenerated on Wed May 28 2025 02:13:08