OccupancyGridMap.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2020 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/io/CFileGZInputStream.h>
11 #include <mrpt/maps/CSimplePointsMap.h>
13 #include <mrpt/poses/CPose2D.h>
14 #include <mrpt/serialization/CArchive.h>
15 #include <mrpt/system/filesystem.h>
16 #include <mvsim/World.h>
18 
19 #include <rapidxml.hpp>
20 
21 #include "xml_utils.h"
22 
23 using namespace rapidxml;
24 using namespace mvsim;
25 using namespace std;
26 
27 OccupancyGridMap::OccupancyGridMap(
28  World* parent, const rapidxml::xml_node<char>* root)
29  : WorldElementBase(parent),
30  m_gui_uptodate(false),
31  m_show_grid_collision_points(true),
32  m_restitution(0.01),
33  m_lateral_friction(0.5)
34 {
35  loadConfigFrom(root);
36 }
37 
40 {
41  m_gui_uptodate = false;
42 
43  // <file>FILENAME.{png,gridmap}</file>
44  xml_node<>* xml_file = root->first_node("file");
45  if (!xml_file || !xml_file->value())
46  throw std::runtime_error(
47  "Error: <file></file> XML entry not found inside gridmap node!");
48 
49  const string sFile = m_world->resolvePath(xml_file->value());
50  const string sFileExt =
51  mrpt::system::extractFileExtension(sFile, true /*ignore gz*/);
52 
53  // MRPT gridmaps format:
54  if (sFileExt == "gridmap")
55  {
56  mrpt::io::CFileGZInputStream fi(sFile);
57  auto f = mrpt::serialization::archiveFrom(fi);
58  f >> m_grid;
59  }
60  else
61  // Assume it's an image:
62  {
63  TParameterDefinitions other_params;
64  double xcenterpixel = -1, ycenterpixel = -1;
65  double resolution = 0.10;
66 
67  other_params["resolution"] = TParamEntry("%lf", &resolution);
68  other_params["centerpixel_x"] = TParamEntry("%lf", &xcenterpixel);
69  other_params["centerpixel_y"] = TParamEntry("%lf", &ycenterpixel);
70 
71  parse_xmlnode_children_as_param(*root, other_params);
72 
74  sFile, resolution, {xcenterpixel, ycenterpixel}))
75  throw std::runtime_error(mrpt::format(
76  "[OccupancyGridMap] ERROR: File not found '%s'",
77  sFile.c_str()));
78  }
79 
80  {
81  // Other general params:
83  ps["show_collisions"] =
85  ps["restitution"] = TParamEntry("%lf", &m_restitution);
86  ps["lateral_friction"] = TParamEntry("%lf", &m_lateral_friction);
87 
89  }
90 }
91 
93  mrpt::opengl::COpenGLScene& scene, bool childrenOnly)
94 {
95  using namespace mrpt::math;
96 
97  // 1st time call?? -> Create objects
98  if (!m_gl_grid)
99  {
100  m_gl_grid = mrpt::opengl::CSetOfObjects::Create();
101  scene.insert(m_gl_grid);
102  }
103  if (m_gl_obs_clouds.size() != m_obstacles_for_each_obj.size())
104  {
106  }
107 
108  // 1st call OR gridmap changed?
109  if (!m_gui_uptodate)
110  {
112  m_gui_uptodate = true;
113  }
114 
115  // Update obstacles:
116  {
117  std::lock_guard<std::mutex> csl(m_gl_obs_clouds_buffer_cs);
118  for (size_t i = 0; i < m_gl_obs_clouds.size(); i++)
119  {
120  mrpt::opengl::CSetOfObjects::Ptr& gl_objs = m_gl_obs_clouds[i];
121  if (!gl_objs)
122  {
123  gl_objs = mrpt::opengl::CSetOfObjects::Create();
124  MRPT_TODO("Add a name, and remove old ones in scene, etc.")
125  scene.insert(gl_objs);
126  }
127 
128  // Now that we are in a safe thread (with the OpenGL scene lock
129  // adquired from the caller)
130  // proceed to replace the old with the new point cloud:
131  gl_objs->clear();
132  if (m_gl_obs_clouds_buffer.size() > i)
133  gl_objs->insert(m_gl_obs_clouds_buffer[i]);
134  }
135 
136  m_gl_obs_clouds_buffer.clear();
137  } // end lock
138 }
139 
141 {
142  // Make a list of objects subject to collide with the occupancy grid:
143  // - Vehicles
144  // - Blocks
145  {
146  const World::VehicleList& lstVehs = this->m_world->getListOfVehicles();
147  const World::BlockList& lstBlocks = this->m_world->getListOfBlocks();
148  const size_t nObjs = lstVehs.size() + lstBlocks.size();
149 
150  m_obstacles_for_each_obj.resize(nObjs);
151  size_t obj_idx = 0;
152  for (World::VehicleList::const_iterator itVeh = lstVehs.begin();
153  itVeh != lstVehs.end(); ++itVeh, ++obj_idx)
154  {
157  itVeh->second->getMaxVehicleRadius() * 1.50f;
158  const mrpt::math::TPose3D& pose = itVeh->second->getPose();
160  pose.x, pose.y,
161  0 /* angle=0, no need to rotate everything to later rotate back again! */);
162  }
163  for (const auto& block : lstBlocks)
164  {
167  block.second->getMaxBlockRadius() * 1.50f;
168  const mrpt::math::TPose3D& pose = block.second->getPose();
169  /* angle=0, no need to rotate everything to later rotate back again!
170  */
171  ipv.pose = mrpt::poses::CPose2D(pose.x, pose.y, 0);
172 
173  obj_idx++;
174  }
175  }
176 
177  // For each object, create a ground body with fixtures at each scanned point
178  // around the vehicle, so it can collide with the environment:
179  // Upon first usage, reserve mem:
180  { // lock
181  std::lock_guard<std::mutex> csl(m_gl_obs_clouds_buffer_cs);
182  const size_t nObjs = m_obstacles_for_each_obj.size();
183  m_gl_obs_clouds_buffer.resize(nObjs);
184 
185  for (size_t obj_idx = 0; obj_idx < nObjs; obj_idx++)
186  {
187  // 1) Simulate scan to get obstacles around the vehicle:
189  mrpt::obs::CObservation2DRangeScan::Ptr& scan = ipv.scan;
190  // Upon first time, reserve mem:
191  if (!scan) scan = mrpt::obs::CObservation2DRangeScan::Create();
192 
193  const float veh_max_obstacles_ranges = ipv.max_obstacles_ranges;
194  const float occup_threshold = 0.5f;
195  const size_t nRays = 50;
196 
197  scan->aperture = 2.0 * M_PI; // 360 field of view
198  scan->maxRange = veh_max_obstacles_ranges;
199 
201  *scan, ipv.pose, occup_threshold, nRays, 0.0f /*noise*/);
202 
203  // Since we'll dilate obstacle points, let's give a bit more space
204  // as compensation:
205  const float range_enlarge = 0.25f * m_grid.getResolution();
206  for (size_t k = 0; k < scan->getScanSize(); k++)
207  {
208  scan->setScanRange(k, scan->getScanRange(k) + range_enlarge);
209  }
210  // 2) Create a Box2D "ground body" with square "fixtures" so the
211  // vehicle can collide with the occ. grid:
212 
213  // Create Box2D objects upon first usage:
214  if (!ipv.collide_body)
215  {
216  b2BodyDef bdef;
217  ipv.collide_body = m_world->getBox2DWorld()->CreateBody(&bdef);
218  ASSERT_(ipv.collide_body);
219  }
220  // Force move the body to the vehicle origins (to use obstacles in
221  // local coords):
223  b2Vec2(ipv.pose.x(), ipv.pose.y()), .0f);
224 
225  // GL:
226  // 1st usage?
227  mrpt::opengl::CPointCloud::Ptr& gl_pts =
228  m_gl_obs_clouds_buffer[obj_idx];
230  {
231  gl_pts = mrpt::opengl::CPointCloud::Create();
232  gl_pts->setPointSize(4.0f);
233  gl_pts->setColor(0, 0, 1);
234 
235  gl_pts->setVisibility(m_show_grid_collision_points);
236  gl_pts->setPose(mrpt::poses::CPose2D(ipv.pose));
237  gl_pts->clear();
238  }
239 
240  // Physical properties of each "occupied cell":
241  const float occCellSemiWidth = m_grid.getResolution() * 0.4f;
242  b2PolygonShape sqrPoly;
243  sqrPoly.SetAsBox(occCellSemiWidth, occCellSemiWidth);
244  sqrPoly.m_radius = 1e-3; // The "skin" depth of the body
245  b2FixtureDef fixtureDef;
246  fixtureDef.shape = &sqrPoly;
247  fixtureDef.restitution = m_restitution;
248  fixtureDef.density = 0; // Fixed (inf. mass)
249  fixtureDef.friction = m_lateral_friction; // 0.5f;
250 
251  // Create fixtures at their place (or disable it if no obstacle has
252  // been sensed):
254  sincos_tab = m_sincos_lut.getSinCosForScan(*scan);
255  ipv.collide_fixtures.resize(nRays);
256  for (size_t k = 0; k < nRays; k++)
257  {
258  if (!ipv.collide_fixtures[k].fixture)
259  ipv.collide_fixtures[k].fixture =
260  ipv.collide_body->CreateFixture(&fixtureDef);
261 
262  if (!scan->getScanRangeValidity(k))
263  {
264  ipv.collide_fixtures[k].fixture->SetSensor(
265  true); // Box2D's way of saying: don't collide with
266  // this!
267  ipv.collide_fixtures[k].fixture->SetUserData(
269  }
270  else
271  {
272  ipv.collide_fixtures[k].fixture->SetSensor(
273  false); // Box2D's way of saying: don't collide with
274  // this!
275  ipv.collide_fixtures[k].fixture->SetUserData(nullptr);
276 
277  b2PolygonShape* poly = dynamic_cast<b2PolygonShape*>(
278  ipv.collide_fixtures[k].fixture->GetShape());
279  ASSERT_(poly != nullptr);
280 
281  const float llx =
282  sincos_tab.ccos[k] * scan->getScanRange(k);
283  const float lly =
284  sincos_tab.csin[k] * scan->getScanRange(k);
285 
286  const float ggx = ipv.pose.x() + llx;
287  const float ggy = ipv.pose.y() + lly;
288 
289  const float gx = m_grid.idx2x(m_grid.x2idx(ggx));
290  const float gy = m_grid.idx2y(m_grid.y2idx(ggy));
291 
292  const float lx = gx - ipv.pose.x();
293  const float ly = gy - ipv.pose.y();
294 
295  poly->SetAsBox(
296  occCellSemiWidth, occCellSemiWidth, b2Vec2(lx, ly),
297  .0f /*angle*/);
298 
299  if (gl_pts && m_show_grid_collision_points)
300  {
301  gl_pts->mrpt::opengl::CPointCloud::insertPoint(
302  lx, ly, .0);
303  }
304  }
305  }
306  } // end for obj_idx
307 
308  } // end lock
309 }
const b2Shape * shape
Definition: b2Fixture.h:71
float idx2y(const size_t cy) const
This file contains rapidxml parser and DOM implementation.
const TSinCosValues & getSinCosForScan(const CObservation2DRangeScan &scan) const
b2Fixture * CreateFixture(const b2FixtureDef *def)
Definition: b2Body.cpp:166
std::vector< mrpt::opengl::CSetOfObjects::Ptr > m_gl_obs_clouds
std::map< std::string, TParamEntry > TParameterDefinitions
Ch * value() const
Definition: rapidxml.hpp:692
mrpt::opengl::CSetOfObjects::Ptr m_gl_grid
call of internalGuiUpdate()
void getAs3DObject(mrpt::opengl::CSetOfObjectsPtr &outObj) const MRPT_OVERRIDE
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="")
Definition: xml_utils.cpp:179
const VehicleList & getListOfVehicles() const
Definition: World.h:195
mrpt::obs::CObservation2DRangeScan::Ptr scan
std::multimap< std::string, VehicleBase::Ptr > VehicleList
Definition: World.h:173
#define M_PI
mrpt::obs::CSinCosLookUpTableFor2DScans m_sincos_lut
std::unique_ptr< b2World > & getBox2DWorld()
Definition: World.h:189
float32 m_radius
Definition: b2Shape.h:93
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:936
A 2D column vector.
Definition: b2Math.h:52
void insert(const CRenderizablePtr &newObject, const std::string &viewportName=std::string("main"))
void SetTransform(const b2Vec2 &position, float32 angle)
Definition: b2Body.cpp:417
std::multimap< std::string, Block::Ptr > BlockList
Definition: World.h:179
MRPT_TODO("Modify ping to run on Windows + Test this")
double m_restitution
Elastic restitution coef (default: 0.01)
std::string resolvePath(const std::string &in_path) const
Definition: World.cpp:162
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
std::string BASE_IMPEXP extractFileExtension(const std::string &filePath, bool ignore_gz=false)
#define INVISIBLE_FIXTURE_USER_DATA
Used to signal a Box2D fixture as "invisible" to sensors.
Definition: basic_types.h:22
float32 density
The density, usually in kg/m^2.
Definition: b2Fixture.h:83
void SetAsBox(float32 hx, float32 hy)
virtual void loadConfigFrom(const rapidxml::xml_node< char > *root) override
void laserScanSimulator(mrpt::obs::CObservation2DRangeScan &inout_Scan, const mrpt::poses::CPose2D &robotPose, float threshold=0.6f, size_t N=361, float noiseStd=0, unsigned int decimation=1, float angleNoiseStd=mrpt::utils::DEG2RAD(0)) const
mrpt::maps::COccupancyGridMap2D m_grid
#define ASSERT_(f)
std::vector< mrpt::opengl::CPointCloud::Ptr > m_gl_obs_clouds_buffer
float32 restitution
The restitution (elasticity) usually in the range [0,1].
Definition: b2Fixture.h:80
virtual void internalGuiUpdate(mrpt::opengl::COpenGLScene &scene, bool childrenOnly) override
double m_lateral_friction
(Default: 0.5)
bool loadFromBitmapFile(const std::string &file, float resolution, float xCentralPixel=-1, float yCentralPixel=-1)
std::vector< TInfoPerCollidableobj > m_obstacles_for_each_obj
virtual void simul_pre_timestep(const TSimulContext &context) override
std::mutex m_gl_obs_clouds_buffer_cs
float32 friction
The friction coefficient, usually in the range [0,1].
Definition: b2Fixture.h:77
float idx2x(const size_t cx) const
const BlockList & getListOfBlocks() const
Definition: World.h:197
GLdouble GLdouble GLdouble GLdouble GLdouble GLdouble f


mvsim
Author(s):
autogenerated on Fri May 7 2021 03:05:51