CARLA
Navigation.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019 Computer Vision Center (CVC) at the Universitat Autonoma
2 // de Barcelona (UAB).
3 //
4 // This work is licensed under the terms of the MIT license.
5 // For a copy, see <https://opensource.org/licenses/MIT>.
6 
7 #define _USE_MATH_DEFINES // to avoid undefined error of M_PI (bug in Visual
8  // Studio 2015 and 2017)
9 #include <cmath>
10 
11 #include "carla/Logging.h"
12 #include "carla/nav/Navigation.h"
14 #include "carla/geom/Math.h"
15 
16 #include <iterator>
17 #include <fstream>
18 #include <mutex>
19 
20 namespace carla {
21 namespace nav {
22 
23  enum UpdateFlags {
29  };
30 
31  // these settings are the same than in RecastBuilder, so if you change the height of the agent,
32  // you should do the same in RecastBuilder
33  static const int MAX_POLYS = 256;
34  static const int MAX_AGENTS = 500;
35  static const int MAX_QUERY_SEARCH_NODES = 2048;
36  static const float AGENT_HEIGHT = 1.8f;
37  static const float AGENT_RADIUS = 0.3f;
38 
39  static const float AGENT_UNBLOCK_DISTANCE = 0.5f;
40  static const float AGENT_UNBLOCK_DISTANCE_SQUARED = AGENT_UNBLOCK_DISTANCE * AGENT_UNBLOCK_DISTANCE;
41  static const float AGENT_UNBLOCK_TIME = 4.0f;
42 
43  static const float AREA_GRASS_COST = 1.0f;
44  static const float AREA_ROAD_COST = 10.0f;
45 
46  // return a random float
47  static float frand() {
48  return static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
49  }
50 
52  // assign walker manager
53  _walker_manager.SetNav(this);
54  }
55 
57  _ready = false;
58  _time_to_unblock = 0.0f;
59  _mapped_walkers_id.clear();
60  _mapped_vehicles_id.clear();
61  _mapped_by_index.clear();
63  _yaw_walkers.clear();
64  _binary_mesh.clear();
65  dtFreeCrowd(_crowd);
66  dtFreeNavMeshQuery(_nav_query);
67  dtFreeNavMesh(_nav_mesh);
68  }
69 
70  // reference to the simulator to access API functions
71  void Navigation::SetSimulator(std::weak_ptr<carla::client::detail::Simulator> simulator)
72  {
73  _simulator = simulator;
74  _walker_manager.SetSimulator(simulator);
75  }
76 
77  // set the seed to use with random numbers
78  void Navigation::SetSeed(unsigned int seed) {
79  srand(seed);
80  }
81 
82  // load navigation data
83  bool Navigation::Load(const std::string &filename) {
84  std::ifstream f;
85  std::istream_iterator<uint8_t> start(f), end;
86 
87  // read the whole file
88  f.open(filename, std::ios::binary);
89  if (!f.is_open()) {
90  return false;
91  }
92  std::vector<uint8_t> content(start, end);
93  f.close();
94 
95  // parse the content
96  return Load(std::move(content));
97  }
98 
99  // load navigation data from memory
100  bool Navigation::Load(std::vector<uint8_t> content) {
101  const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; // 'MSET';
102  const int NAVMESHSET_VERSION = 1;
103 #pragma pack(push, 1)
104 
105  struct NavMeshSetHeader {
106  int magic;
107  int version;
108  int num_tiles;
109  dtNavMeshParams params;
110  } header;
111  struct NavMeshTileHeader {
112  dtTileRef tile_ref;
113  int data_size;
114  };
115 #pragma pack(pop)
116 
117  // check size for header
118  if (content.size() < sizeof(header)) {
119  logging::log("Nav: failed loading binary");
120  return false;
121  }
122 
123  // read the file header
124  unsigned long pos = 0;
125  memcpy(&header, &content[pos], sizeof(header));
126  pos += sizeof(header);
127 
128  // check file magic and version
129  if (header.magic != NAVMESHSET_MAGIC || header.version != NAVMESHSET_VERSION) {
130  return false;
131  }
132 
133  // allocate object
134  dtNavMesh *mesh = dtAllocNavMesh();
135  if (!mesh) {
136  return false;
137  }
138 
139  // set number of tiles and origin
140  dtStatus status = mesh->init(&header.params);
141  if (dtStatusFailed(status)) {
142  return false;
143  }
144 
145  // read the tiles data
146  for (int i = 0; i < header.num_tiles; ++i) {
147  NavMeshTileHeader tile_header;
148 
149  // read the tile header
150  memcpy(&tile_header, &content[pos], sizeof(tile_header));
151  pos += sizeof(tile_header);
152  if (pos >= content.size()) {
153  dtFreeNavMesh(mesh);
154  return false;
155  }
156 
157  // check for valid tile
158  if (!tile_header.tile_ref || !tile_header.data_size) {
159  break;
160  }
161 
162  // allocate the buffer
163  char *data = static_cast<char *>(dtAlloc(static_cast<size_t>(tile_header.data_size), DT_ALLOC_PERM));
164  if (!data) {
165  break;
166  }
167 
168  // read the tile
169  memcpy(data, &content[pos], static_cast<size_t>(tile_header.data_size));
170  pos += static_cast<unsigned long>(tile_header.data_size);
171  if (pos > content.size()) {
172  dtFree(data);
173  dtFreeNavMesh(mesh);
174  return false;
175  }
176 
177  // add the tile data
178  mesh->addTile(reinterpret_cast<unsigned char *>(data), tile_header.data_size, DT_TILE_FREE_DATA,
179  tile_header.tile_ref, 0);
180  }
181 
182  // exchange
183  dtFreeNavMesh(_nav_mesh);
184  _nav_mesh = mesh;
185 
186  // prepare the query object
187  dtFreeNavMeshQuery(_nav_query);
188  _nav_query = dtAllocNavMeshQuery();
189  _nav_query->init(_nav_mesh, MAX_QUERY_SEARCH_NODES);
190 
191  // copy
192  _binary_mesh = std::move(content);
193  _ready = true;
194 
195  // create and init the crowd manager
196  CreateCrowd();
197 
198  return true;
199  }
200 
202 
203  // check if all is ready
204  if (!_ready) {
205  return;
206  }
207 
208  DEBUG_ASSERT(_crowd == nullptr);
209 
210  // create and init
211  _crowd = dtAllocCrowd();
212  // these radius should be the maximum size of the vehicles (CarlaCola for Carla)
213  const float max_agent_radius = AGENT_RADIUS * 20;
214  if (!_crowd->init(MAX_AGENTS, max_agent_radius, _nav_mesh)) {
215  logging::log("Nav: failed to create crowd");
216  return;
217  }
218 
219  // set different filters
220  // filter 0 can not walk on roads
221  _crowd->getEditableFilter(0)->setIncludeFlags(CARLA_TYPE_WALKABLE);
222  _crowd->getEditableFilter(0)->setExcludeFlags(CARLA_TYPE_ROAD);
223  _crowd->getEditableFilter(0)->setAreaCost(CARLA_AREA_ROAD, AREA_ROAD_COST);
224  _crowd->getEditableFilter(0)->setAreaCost(CARLA_AREA_GRASS, AREA_GRASS_COST);
225  // filter 1 can walk on roads
226  _crowd->getEditableFilter(1)->setIncludeFlags(CARLA_TYPE_WALKABLE);
227  _crowd->getEditableFilter(1)->setExcludeFlags(CARLA_TYPE_NONE);
228  _crowd->getEditableFilter(1)->setAreaCost(CARLA_AREA_ROAD, AREA_ROAD_COST);
229  _crowd->getEditableFilter(1)->setAreaCost(CARLA_AREA_GRASS, AREA_GRASS_COST);
230 
231  // Setup local avoidance params to different qualities.
232  dtObstacleAvoidanceParams params;
233  // Use mostly default settings, copy from dtCrowd.
234  memcpy(&params, _crowd->getObstacleAvoidanceParams(0), sizeof(dtObstacleAvoidanceParams));
235 
236  // Low (11)
237  params.velBias = 0.5f;
238  params.adaptiveDivs = 5;
239  params.adaptiveRings = 2;
240  params.adaptiveDepth = 1;
241  _crowd->setObstacleAvoidanceParams(0, &params);
242 
243  // Medium (22)
244  params.velBias = 0.5f;
245  params.adaptiveDivs = 5;
246  params.adaptiveRings = 2;
247  params.adaptiveDepth = 2;
248  _crowd->setObstacleAvoidanceParams(1, &params);
249 
250  // Good (45)
251  params.velBias = 0.5f;
252  params.adaptiveDivs = 7;
253  params.adaptiveRings = 2;
254  params.adaptiveDepth = 3;
255  _crowd->setObstacleAvoidanceParams(2, &params);
256 
257  // High (66)
258  params.velBias = 0.5f;
259  params.adaptiveDivs = 7;
260  params.adaptiveRings = 3;
261  params.adaptiveDepth = 3;
262 
263  _crowd->setObstacleAvoidanceParams(3, &params);
264  }
265 
266  // return the path points to go from one position to another
269  dtQueryFilter * filter,
270  std::vector<carla::geom::Location> &path,
271  std::vector<unsigned char> &area) {
272  // path found
273  float straight_path[MAX_POLYS * 3];
274  unsigned char straight_path_flags[MAX_POLYS];
275  dtPolyRef straight_path_polys[MAX_POLYS];
276  int num_straight_path;
277  int straight_path_options = DT_STRAIGHTPATH_AREA_CROSSINGS;
278 
279  // polys in path
280  dtPolyRef polys[MAX_POLYS];
281  int num_polys;
282 
283  // check if all is ready
284  if (!_ready) {
285  return false;
286  }
287 
288  DEBUG_ASSERT(_nav_query != nullptr);
289 
290  // point extension
291  float poly_pick_ext[3];
292  poly_pick_ext[0] = 2;
293  poly_pick_ext[1] = 4;
294  poly_pick_ext[2] = 2;
295 
296  // filter
297  dtQueryFilter filter2;
298  if (filter == nullptr) {
299  filter2.setAreaCost(CARLA_AREA_ROAD, AREA_ROAD_COST);
300  filter2.setAreaCost(CARLA_AREA_GRASS, AREA_GRASS_COST);
301  filter2.setIncludeFlags(CARLA_TYPE_WALKABLE);
302  filter2.setExcludeFlags(CARLA_TYPE_NONE);
303  filter = &filter2;
304  }
305 
306  // set the points
307  dtPolyRef start_ref = 0;
308  dtPolyRef end_ref = 0;
309  float start_pos[3] = { from.x, from.z, from.y };
310  float end_pos[3] = { to.x, to.z, to.y };
311  {
312  // critical section, force single thread running this
313  std::lock_guard<std::mutex> lock(_mutex);
314  _nav_query->findNearestPoly(start_pos, poly_pick_ext, filter, &start_ref, 0);
315  _nav_query->findNearestPoly(end_pos, poly_pick_ext, filter, &end_ref, 0);
316  }
317  if (!start_ref || !end_ref) {
318  return false;
319  }
320 
321  {
322  // critical section, force single thread running this
323  std::lock_guard<std::mutex> lock(_mutex);
324  // get the path of nodes
325  _nav_query->findPath(start_ref, end_ref, start_pos, end_pos, filter, polys, &num_polys, MAX_POLYS);
326  }
327 
328  // get the path of points
329  num_straight_path = 0;
330  if (num_polys == 0) {
331  return false;
332  }
333 
334  // in case of partial path, make sure the end point is clamped to the last
335  // polygon
336  float end_pos2[3];
337  dtVcopy(end_pos2, end_pos);
338  if (polys[num_polys - 1] != end_ref) {
339  // critical section, force single thread running this
340  std::lock_guard<std::mutex> lock(_mutex);
341  _nav_query->closestPointOnPoly(polys[num_polys - 1], end_pos, end_pos2, 0);
342  }
343 
344  // get the points
345  {
346  // critical section, force single thread running this
347  std::lock_guard<std::mutex> lock(_mutex);
348  _nav_query->findStraightPath(start_pos, end_pos2, polys, num_polys,
349  straight_path, straight_path_flags,
350  straight_path_polys, &num_straight_path, MAX_POLYS, straight_path_options);
351  }
352 
353  // copy the path to the output buffer
354  path.clear();
355  path.reserve(static_cast<unsigned long>(num_straight_path));
356  unsigned char area_type;
357  for (int i = 0, j = 0; j < num_straight_path; i += 3, ++j) {
358  // save coordinate for Unreal axis (x, z, y)
359  path.emplace_back(straight_path[i], straight_path[i + 2], straight_path[i + 1]);
360  // save area type
361  {
362  // critical section, force single thread running this
363  std::lock_guard<std::mutex> lock(_mutex);
364  _nav_mesh->getPolyArea(straight_path_polys[j], &area_type);
365  }
366  area.emplace_back(area_type);
367  }
368 
369  return true;
370  }
371 
373  std::vector<carla::geom::Location> &path, std::vector<unsigned char> &area) {
374  // path found
375  float straight_path[MAX_POLYS * 3];
376  unsigned char straight_path_flags[MAX_POLYS];
377  dtPolyRef straight_path_polys[MAX_POLYS];
378  int num_straight_path = 0;
379  int straight_path_options = DT_STRAIGHTPATH_AREA_CROSSINGS;
380 
381  // polys in path
382  dtPolyRef polys[MAX_POLYS];
383  int num_polys;
384 
385  // check if all is ready
386  if (!_ready) {
387  return false;
388  }
389 
390  DEBUG_ASSERT(_nav_query != nullptr);
391 
392  // point extension
393  float poly_pick_ext[3] = {2,4,2};
394 
395  // get current filter from agent
396  auto it = _mapped_walkers_id.find(id);
397  if (it == _mapped_walkers_id.end())
398  return false;
399 
400  const dtQueryFilter *filter;
401  {
402  // critical section, force single thread running this
403  std::lock_guard<std::mutex> lock(_mutex);
404  filter = _crowd->getFilter(_crowd->getAgent(it->second)->params.queryFilterType);
405  }
406 
407  // set the points
408  dtPolyRef start_ref = 0;
409  dtPolyRef end_ref = 0;
410  float start_pos[3] = { from.x, from.z, from.y };
411  float end_pos[3] = { to.x, to.z, to.y };
412  {
413  // critical section, force single thread running this
414  std::lock_guard<std::mutex> lock(_mutex);
415  _nav_query->findNearestPoly(start_pos, poly_pick_ext, filter, &start_ref, 0);
416  _nav_query->findNearestPoly(end_pos, poly_pick_ext, filter, &end_ref, 0);
417  }
418  if (!start_ref || !end_ref) {
419  return false;
420  }
421 
422  // get the path of nodes
423  {
424  // critical section, force single thread running this
425  std::lock_guard<std::mutex> lock(_mutex);
426  _nav_query->findPath(start_ref, end_ref, start_pos, end_pos, filter, polys, &num_polys, MAX_POLYS);
427  }
428 
429  // get the path of points
430  if (num_polys == 0) {
431  return false;
432  }
433 
434  // in case of partial path, make sure the end point is clamped to the last
435  // polygon
436  float end_pos2[3];
437  dtVcopy(end_pos2, end_pos);
438  if (polys[num_polys - 1] != end_ref) {
439  // critical section, force single thread running this
440  std::lock_guard<std::mutex> lock(_mutex);
441  _nav_query->closestPointOnPoly(polys[num_polys - 1], end_pos, end_pos2, 0);
442  }
443 
444  // get the points
445  {
446  // critical section, force single thread running this
447  std::lock_guard<std::mutex> lock(_mutex);
448  _nav_query->findStraightPath(start_pos, end_pos2, polys, num_polys,
449  straight_path, straight_path_flags,
450  straight_path_polys, &num_straight_path, MAX_POLYS, straight_path_options);
451  }
452 
453  // copy the path to the output buffer
454  path.clear();
455  path.reserve(static_cast<unsigned long>(num_straight_path));
456  unsigned char area_type;
457  for (int i = 0, j = 0; j < num_straight_path; i += 3, ++j) {
458  // save coordinate for Unreal axis (x, z, y)
459  path.emplace_back(straight_path[i], straight_path[i + 2], straight_path[i + 1]);
460  // save area type
461  {
462  // critical section, force single thread running this
463  std::lock_guard<std::mutex> lock(_mutex);
464  _nav_mesh->getPolyArea(straight_path_polys[j], &area_type);
465  }
466  area.emplace_back(area_type);
467  }
468 
469  return true;
470  }
471 
472  // create a new walker in crowd
474  dtCrowdAgentParams params;
475 
476  // check if all is ready
477  if (!_ready) {
478  return false;
479  }
480 
481  DEBUG_ASSERT(_crowd != nullptr);
482 
483  // set parameters
484  memset(&params, 0, sizeof(params));
485  params.radius = AGENT_RADIUS;
486  params.height = AGENT_HEIGHT;
487  params.maxAcceleration = 160.0f;
488  params.maxSpeed = 1.47f;
489  params.collisionQueryRange = 10;
490  params.obstacleAvoidanceType = 3;
491  params.separationWeight = 0.5f;
492 
493  // set if the agent can cross roads or not
494  if (frand() <= _probability_crossing) {
495  params.queryFilterType = 1;
496  } else {
497  params.queryFilterType = 0;
498  }
499 
500  // flags
501  params.updateFlags = 0;
502  params.updateFlags |= DT_CROWD_ANTICIPATE_TURNS;
503  params.updateFlags |= DT_CROWD_OBSTACLE_AVOIDANCE;
504  params.updateFlags |= DT_CROWD_SEPARATION;
505 
506  // from Unreal coordinates (subtract half height to move pivot from center
507  // (unreal) to bottom (recast))
508  float point_from[3] = { from.x, from.z - (AGENT_HEIGHT / 2.0f), from.y };
509  // add walker
510  int index;
511  {
512  // critical section, force single thread running this
513  std::lock_guard<std::mutex> lock(_mutex);
514  index = _crowd->addAgent(point_from, &params);
515  if (index == -1) {
516  return false;
517  }
518  }
519 
520  // save the id
521  _mapped_walkers_id[id] = index;
522  _mapped_by_index[index] = id;
523 
524  // init yaw
525  _yaw_walkers[id] = 0.0f;
526 
527  // add walker for the route planning
529 
530  return true;
531  }
532 
533  // create a new vehicle in crowd to be avoided by walkers
535  namespace cg = carla::geom;
536  dtCrowdAgentParams params;
537 
538  // check if all is ready
539  if (!_ready) {
540  return false;
541  }
542 
543  DEBUG_ASSERT(_crowd != nullptr);
544 
545  // get the bounding box extension plus some space around
546  float marge = 0.8f;
547  float hx = vehicle.bounding.extent.x + marge;
548  float hy = vehicle.bounding.extent.y + marge;
549  // define the 4 corners of the bounding box
550  cg::Vector3D box_corner1 {-hx, -hy, 0};
551  cg::Vector3D box_corner2 { hx + 0.2f, -hy, 0};
552  cg::Vector3D box_corner3 { hx + 0.2f, hy, 0};
553  cg::Vector3D box_corner4 {-hx, hy, 0};
554  // rotate the points
555  float angle = cg::Math::ToRadians(vehicle.transform.rotation.yaw);
556  box_corner1 = cg::Math::RotatePointOnOrigin2D(box_corner1, angle);
557  box_corner2 = cg::Math::RotatePointOnOrigin2D(box_corner2, angle);
558  box_corner3 = cg::Math::RotatePointOnOrigin2D(box_corner3, angle);
559  box_corner4 = cg::Math::RotatePointOnOrigin2D(box_corner4, angle);
560  // translate to world position
561  box_corner1 += vehicle.transform.location;
562  box_corner2 += vehicle.transform.location;
563  box_corner3 += vehicle.transform.location;
564  box_corner4 += vehicle.transform.location;
565 
566  // check if this actor exists
567  auto it = _mapped_vehicles_id.find(vehicle.id);
568  if (it != _mapped_vehicles_id.end()) {
569  // get the index found
570  int index = it->second;
571  if (index != -1) {
572  // get the agent
573  dtCrowdAgent *agent;
574  {
575  // critical section, force single thread running this
576  std::lock_guard<std::mutex> lock(_mutex);
577  agent = _crowd->getEditableAgent(index);
578  }
579  if (agent) {
580  // update its position
581  agent->npos[0] = vehicle.transform.location.x;
582  agent->npos[1] = vehicle.transform.location.z;
583  agent->npos[2] = vehicle.transform.location.y;
584  // update its oriented bounding box
585  agent->params.obb[0] = box_corner1.x;
586  agent->params.obb[1] = box_corner1.z;
587  agent->params.obb[2] = box_corner1.y;
588  agent->params.obb[3] = box_corner2.x;
589  agent->params.obb[4] = box_corner2.z;
590  agent->params.obb[5] = box_corner2.y;
591  agent->params.obb[6] = box_corner3.x;
592  agent->params.obb[7] = box_corner3.z;
593  agent->params.obb[8] = box_corner3.y;
594  agent->params.obb[9] = box_corner4.x;
595  agent->params.obb[10] = box_corner4.z;
596  agent->params.obb[11] = box_corner4.y;
597  }
598  return true;
599  }
600  }
601 
602  // set parameters
603  memset(&params, 0, sizeof(params));
604  params.radius = 2;
605  params.height = AGENT_HEIGHT;
606  params.maxAcceleration = 0.0f;
607  params.maxSpeed = 1.47f;
608  params.collisionQueryRange = 0;
609  params.obstacleAvoidanceType = 0;
610  params.separationWeight = 100.0f;
611 
612  // flags
613  params.updateFlags = 0;
614  params.updateFlags |= DT_CROWD_SEPARATION;
615 
616  // update its oriented bounding box
617  // data: [x][y][z] [x][y][z] [x][y][z] [x][y][z]
618  params.useObb = true;
619  params.obb[0] = box_corner1.x;
620  params.obb[1] = box_corner1.z;
621  params.obb[2] = box_corner1.y;
622  params.obb[3] = box_corner2.x;
623  params.obb[4] = box_corner2.z;
624  params.obb[5] = box_corner2.y;
625  params.obb[6] = box_corner3.x;
626  params.obb[7] = box_corner3.z;
627  params.obb[8] = box_corner3.y;
628  params.obb[9] = box_corner4.x;
629  params.obb[10] = box_corner4.z;
630  params.obb[11] = box_corner4.y;
631 
632  // from Unreal coordinates (vertical is Z) to Recast coordinates (vertical is Y)
633  float point_from[3] = { vehicle.transform.location.x,
634  vehicle.transform.location.z,
635  vehicle.transform.location.y };
636 
637  // add walker
638  int index;
639  {
640  // critical section, force single thread running this
641  std::lock_guard<std::mutex> lock(_mutex);
642  index = _crowd->addAgent(point_from, &params);
643  if (index == -1) {
644  logging::log("Vehicle agent not added to the crowd by some problem!");
645  return false;
646  }
647 
648  // mark as valid
649  dtCrowdAgent *agent = _crowd->getEditableAgent(index);
650  if (agent) {
651  agent->state = DT_CROWDAGENT_STATE_WALKING;
652  }
653  }
654 
655  // save the id
656  _mapped_vehicles_id[vehicle.id] = index;
657  _mapped_by_index[index] = vehicle.id;
658 
659  return true;
660  }
661 
662  // remove an agent
664 
665  // check if all is ready
666  if (!_ready) {
667  return false;
668  }
669 
670  DEBUG_ASSERT(_crowd != nullptr);
671 
672  // get the internal walker index
673  auto it = _mapped_walkers_id.find(id);
674  if (it != _mapped_walkers_id.end()) {
675  // remove from crowd
676  {
677  // critical section, force single thread running this
678  std::lock_guard<std::mutex> lock(_mutex);
679  _crowd->removeAgent(it->second);
680  }
682  // remove from mapping
683  _mapped_walkers_id.erase(it);
684  _mapped_by_index.erase(it->second);
685 
686  return true;
687  }
688 
689  // get the internal vehicle index
690  it = _mapped_vehicles_id.find(id);
691  if (it != _mapped_vehicles_id.end()) {
692  // remove from crowd
693  {
694  // critical section, force single thread running this
695  std::lock_guard<std::mutex> lock(_mutex);
696  _crowd->removeAgent(it->second);
697  }
698  // remove from mapping
699  _mapped_vehicles_id.erase(it);
700  _mapped_by_index.erase(it->second);
701 
702  return true;
703  }
704 
705  return false;
706  }
707 
708  // add/update/delete vehicles in crowd
709  bool Navigation::UpdateVehicles(std::vector<VehicleCollisionInfo> vehicles) {
710  std::unordered_set<carla::rpc::ActorId> updated;
711 
712  // add all current mapped vehicles in the set
713  for (auto &&entry : _mapped_vehicles_id) {
714  updated.insert(entry.first);
715  }
716 
717  // add all vehicles (if already exists, it gets updated only)
718  for (auto &&entry : vehicles) {
719  // try to add or update the vehicle
720  AddOrUpdateVehicle(entry);
721  // mark as updated (to avoid removing it in this frame)
722  updated.erase(entry.id);
723  }
724 
725  // remove all vehicles not updated (they don't exist in this frame)
726  for (auto &&entry : updated) {
727  // remove agent not updated
728  RemoveAgent(entry);
729  }
730 
731  return true;
732  }
733 
734  // set new max speed
735  bool Navigation::SetWalkerMaxSpeed(ActorId id, float max_speed) {
736 
737  // check if all is ready
738  if (!_ready) {
739  return false;
740  }
741 
742  DEBUG_ASSERT(_crowd != nullptr);
743 
744  // get the internal index
745  auto it = _mapped_walkers_id.find(id);
746  if (it == _mapped_walkers_id.end()) {
747  return false;
748  }
749 
750  // get the agent
751  {
752  // critical section, force single thread running this
753  std::lock_guard<std::mutex> lock(_mutex);
754  dtCrowdAgent *agent = _crowd->getEditableAgent(it->second);
755  if (agent) {
756  agent->params.maxSpeed = max_speed;
757  return true;
758  }
759  }
760 
761  return false;
762  }
763 
764  // set a new target point to go
766 
767  // check if all is ready
768  if (!_ready) {
769  return false;
770  }
771 
772  // get the internal index
773  auto it = _mapped_walkers_id.find(id);
774  if (it == _mapped_walkers_id.end()) {
775  return false;
776  }
777 
778  return _walker_manager.SetWalkerRoute(id, to);
779  }
780 
781  // set a new target point to go directly without events
783 
784  // check if all is ready
785  if (!_ready) {
786  return false;
787  }
788 
789  // get the internal index
790  auto it = _mapped_walkers_id.find(id);
791  if (it == _mapped_walkers_id.end()) {
792  return false;
793  }
794 
795  return SetWalkerDirectTargetIndex(it->second, to);
796  }
797 
798  // set a new target point to go directly without events
800 
801  // check if all is ready
802  if (!_ready) {
803  return false;
804  }
805 
806  DEBUG_ASSERT(_crowd != nullptr);
807  DEBUG_ASSERT(_nav_query != nullptr);
808 
809  if (index == -1) {
810  return false;
811  }
812 
813  // set target position
814  float point_to[3] = { to.x, to.z, to.y };
815  float nearest[3];
816  bool res;
817  {
818  // critical section, force single thread running this
819  std::lock_guard<std::mutex> lock(_mutex);
820  const dtQueryFilter *filter = _crowd->getFilter(0);
821  dtPolyRef target_ref;
822  _nav_query->findNearestPoly(point_to, _crowd->getQueryHalfExtents(), filter, &target_ref, nearest);
823  if (!target_ref) {
824  return false;
825  }
826 
827  res = _crowd->requestMoveTarget(index, target_ref, point_to);
828  }
829 
830  return res;
831  }
832 
833  // update all walkers in crowd
835 
836  // check if all is ready
837  if (!_ready) {
838  return;
839  }
840 
841  DEBUG_ASSERT(_crowd != nullptr);
842 
843  // update crowd agents
844  _delta_seconds = state.GetTimestamp().delta_seconds;
845  {
846  // critical section, force single thread running this
847  std::lock_guard<std::mutex> lock(_mutex);
848  _crowd->update(static_cast<float>(_delta_seconds), nullptr);
849  }
850 
851  // update the walkers route
853 
854  // update the time to check for blocked agents
856 
857  // check all active agents
858  int total_unblocked = 0;
859  int total_agents;
860  {
861  // critical section, force single thread running this
862  std::lock_guard<std::mutex> lock(_mutex);
863  total_agents = _crowd->getAgentCount();
864  }
865  const dtCrowdAgent *ag;
866  for (int i = 0; i < total_agents; ++i) {
867  {
868  // critical section, force single thread running this
869  std::lock_guard<std::mutex> lock(_mutex);
870  ag = _crowd->getAgent(i);
871  }
872 
873  if (!ag->active || ag->paused || ag->dead) {
874  continue;
875  }
876 
877  // check only pedestrians not paused, and no vehicles
878  if (!ag->params.useObb && !ag->paused) {
879  bool reset_target_pos = false;
880  bool use_same_filter = false;
881 
882  // check for unblocking actors
883  if (_time_to_unblock >= AGENT_UNBLOCK_TIME) {
884  // get the distance moved by each actor
886  carla::geom::Vector3D current = carla::geom::Vector3D(ag->npos[0], ag->npos[1], ag->npos[2]);
887  carla::geom::Vector3D distance = current - previous;
888  float d = distance.SquaredLength();
889  if (d < AGENT_UNBLOCK_DISTANCE_SQUARED) {
890  ++total_unblocked;
891  reset_target_pos = true;
892  use_same_filter = true;
893  }
894  // update with current position
895  _walkers_blocked_position[i] = current;
896 
897  // check to assign a new target position
898  if (reset_target_pos) {
899  // set if the agent can cross roads or not
900  if (!use_same_filter) {
901  if (frand() <= _probability_crossing) {
902  SetAgentFilter(i, 1);
903  } else {
904  SetAgentFilter(i, 0);
905  }
906  }
907  // set a new random target
908  carla::geom::Location location;
909  GetRandomLocation(location, nullptr);
911  }
912  }
913  }
914  }
915 
916  // check for resetting time
917  if (_time_to_unblock >= AGENT_UNBLOCK_TIME) {
918  _time_to_unblock = 0.0f;
919  }
920  }
921 
922  // get the walker current transform
924 
925  // check if all is ready
926  if (!_ready) {
927  return false;
928  }
929 
930  DEBUG_ASSERT(_crowd != nullptr);
931 
932  // get the internal index
933  auto it = _mapped_walkers_id.find(id);
934  if (it == _mapped_walkers_id.end()) {
935  return false;
936  }
937 
938  // get the index found
939  int index = it->second;
940  if (index == -1) {
941  return false;
942  }
943 
944  // get the walker
945  const dtCrowdAgent *agent;
946  {
947  // critical section, force single thread running this
948  std::lock_guard<std::mutex> lock(_mutex);
949  agent = _crowd->getAgent(index);
950  }
951 
952  if (!agent->active) {
953  return false;
954  }
955 
956  // set its position in Unreal coordinates
957  trans.location.x = agent->npos[0];
958  trans.location.y = agent->npos[2];
959  trans.location.z = agent->npos[1];
960 
961  // set its rotation
962  float yaw;
963  float speed = 0.0f;
964  float min = 0.1f;
965  if (agent->vel[0] < -min || agent->vel[0] > min ||
966  agent->vel[2] < -min || agent->vel[2] > min) {
967  yaw = atan2f(agent->vel[2], agent->vel[0]) * (180.0f / static_cast<float>(M_PI));
968  speed = sqrtf(agent->vel[0] * agent->vel[0] + agent->vel[1] * agent->vel[1] + agent->vel[2] * agent->vel[2]);
969  } else {
970  yaw = atan2f(agent->dvel[2], agent->dvel[0]) * (180.0f / static_cast<float>(M_PI));
971  speed = sqrtf(agent->dvel[0] * agent->dvel[0] + agent->dvel[1] * agent->dvel[1] + agent->dvel[2] * agent->dvel[2]);
972  }
973 
974  // interpolate current and target angle
975  float shortest_angle = fmod(yaw - _yaw_walkers[id] + 540.0f, 360.0f) - 180.0f;
976  float per = (speed / 1.5f);
977  if (per > 1.0f) per = 1.0f;
978  float rotation_speed = per * 6.0f;
979  trans.rotation.yaw = _yaw_walkers[id] +
980  (shortest_angle * rotation_speed * static_cast<float>(_delta_seconds));
981  _yaw_walkers[id] = trans.rotation.yaw;
982 
983  return true;
984  }
985 
986  // get the walker current location
988 
989  // check if all is ready
990  if (!_ready) {
991  return false;
992  }
993 
994  DEBUG_ASSERT(_crowd != nullptr);
995 
996  // get the internal index
997  auto it = _mapped_walkers_id.find(id);
998  if (it == _mapped_walkers_id.end()) {
999  return false;
1000  }
1001 
1002  // get the index found
1003  int index = it->second;
1004  if (index == -1) {
1005  return false;
1006  }
1007 
1008  // get the walker
1009  const dtCrowdAgent *agent;
1010  {
1011  // critical section, force single thread running this
1012  std::lock_guard<std::mutex> lock(_mutex);
1013  agent = _crowd->getAgent(index);
1014  }
1015 
1016  if (!agent->active) {
1017  return false;
1018  }
1019 
1020  // set its position in Unreal coordinates
1021  location.x = agent->npos[0];
1022  location.y = agent->npos[2];
1023  location.z = agent->npos[1];
1024 
1025  return true;
1026  }
1027 
1029 
1030  // check if all is ready
1031  if (!_ready) {
1032  return 0.0f;
1033  }
1034 
1035  DEBUG_ASSERT(_crowd != nullptr);
1036 
1037  // get the internal index
1038  auto it = _mapped_walkers_id.find(id);
1039  if (it == _mapped_walkers_id.end()) {
1040  return 0.0f;
1041  }
1042 
1043  // get the index found
1044  int index = it->second;
1045  if (index == -1) {
1046  return 0.0f;
1047  }
1048 
1049  // get the walker
1050  const dtCrowdAgent *agent;
1051  {
1052  // critical section, force single thread running this
1053  std::lock_guard<std::mutex> lock(_mutex);
1054  agent = _crowd->getAgent(index);
1055  }
1056 
1057  return sqrt(agent->vel[0] * agent->vel[0] + agent->vel[1] * agent->vel[1] + agent->vel[2] *
1058  agent->vel[2]);
1059  }
1060 
1061  // get a random location for navigation
1062  bool Navigation::GetRandomLocation(carla::geom::Location &location, dtQueryFilter * filter) const {
1063 
1064  // check if all is ready
1065  if (!_ready) {
1066  return false;
1067  }
1068 
1069  DEBUG_ASSERT(_nav_query != nullptr);
1070 
1071  // filter
1072  dtQueryFilter filter2;
1073  if (filter == nullptr) {
1074  filter2.setIncludeFlags(CARLA_TYPE_SIDEWALK);
1075  filter2.setExcludeFlags(CARLA_TYPE_NONE);
1076  filter = &filter2;
1077  }
1078 
1079  // we will try up to 10 rounds, otherwise we failed to find a good location
1080  dtPolyRef random_ref { 0 };
1081  float point[3] { 0.0f, 0.0f, 0.0f };
1082  int rounds = 10;
1083  {
1084  dtStatus status;
1085  // critical section, force single thread running this
1086  std::lock_guard<std::mutex> lock(_mutex);
1087  do {
1088  status = _nav_query->findRandomPoint(filter, frand, &random_ref, point);
1089  // set the location in Unreal coords
1090  if (status == DT_SUCCESS) {
1091  location.x = point[0];
1092  location.y = point[2];
1093  location.z = point[1];
1094  }
1095  --rounds;
1096  } while (status != DT_SUCCESS && rounds > 0);
1097  }
1098 
1099  return (rounds > 0);
1100  }
1101 
1102  // assign a filter index to an agent
1103  void Navigation::SetAgentFilter(int agent_index, int filter_index)
1104  {
1105  // get the walker
1106  dtCrowdAgent *agent;
1107  {
1108  // critical section, force single thread running this
1109  std::lock_guard<std::mutex> lock(_mutex);
1110  agent = _crowd->getEditableAgent(agent_index);
1111  }
1112  agent->params.queryFilterType = static_cast<unsigned char>(filter_index);
1113  }
1114 
1115  // set the probability that an agent could cross the roads in its path following
1116  // percentage of 0.0f means no pedestrian can cross roads
1117  // percentage of 0.5f means 50% of all pedestrians can cross roads
1118  // percentage of 1.0f means all pedestrians can cross roads if needed
1120  {
1121  _probability_crossing = percentage;
1122  }
1123 
1124  // set an agent as paused for the crowd
1125  void Navigation::PauseAgent(ActorId id, bool pause) {
1126  // check if all is ready
1127  if (!_ready) {
1128  return;
1129  }
1130 
1131  DEBUG_ASSERT(_crowd != nullptr);
1132 
1133  // get the internal index
1134  auto it = _mapped_walkers_id.find(id);
1135  if (it == _mapped_walkers_id.end()) {
1136  return;
1137  }
1138 
1139  // get the index found
1140  int index = it->second;
1141  if (index == -1) {
1142  return;
1143  }
1144 
1145  // get the walker
1146  dtCrowdAgent *agent;
1147  {
1148  // critical section, force single thread running this
1149  std::lock_guard<std::mutex> lock(_mutex);
1150  agent = _crowd->getEditableAgent(index);
1151  }
1152 
1153  // mark
1154  agent->paused = pause;
1155  }
1156 
1157  bool Navigation::HasVehicleNear(ActorId id, float distance, carla::geom::Location direction) {
1158  // get the internal index (walker or vehicle)
1159  auto it = _mapped_walkers_id.find(id);
1160  if (it == _mapped_walkers_id.end()) {
1161  it = _mapped_vehicles_id.find(id);
1162  if (it == _mapped_vehicles_id.end()) {
1163  return false;
1164  }
1165  }
1166 
1167  float dir[3] = { direction.x, direction.z, direction.y };
1168  bool result;
1169  {
1170  // critical section, force single thread running this
1171  std::lock_guard<std::mutex> lock(_mutex);
1172  result = _crowd->hasVehicleNear(it->second, distance * distance, dir, false);
1173  }
1174  return result;
1175  }
1176 
1177  /// make agent look at some location
1179  // get the internal index (walker or vehicle)
1180  auto it = _mapped_walkers_id.find(id);
1181  if (it == _mapped_walkers_id.end()) {
1182  it = _mapped_vehicles_id.find(id);
1183  if (it == _mapped_vehicles_id.end()) {
1184  return false;
1185  }
1186  }
1187 
1188  dtCrowdAgent *agent;
1189  {
1190  // critical section, force single thread running this
1191  std::lock_guard<std::mutex> lock(_mutex);
1192  agent = _crowd->getEditableAgent(it->second);
1193  }
1194 
1195  // get the position
1196  float x = (location.x - agent->npos[0]) * 0.0001f;
1197  float y = (location.y - agent->npos[2]) * 0.0001f;
1198  float z = (location.z - agent->npos[1]) * 0.0001f;
1199 
1200  // set its velocity
1201  agent->vel[0] = x;
1202  agent->vel[2] = y;
1203  agent->vel[1] = z;
1204  agent->nvel[0] = x;
1205  agent->nvel[2] = y;
1206  agent->nvel[1] = z;
1207  agent->dvel[0] = x;
1208  agent->dvel[2] = y;
1209  agent->dvel[1] = z;
1210 
1211  return true;
1212  }
1213 
1214  bool Navigation::IsWalkerAlive(ActorId id, bool &alive) {
1215  // check if all is ready
1216  if (!_ready) {
1217  return false;
1218  }
1219 
1220  DEBUG_ASSERT(_crowd != nullptr);
1221 
1222  // get the internal index
1223  auto it = _mapped_walkers_id.find(id);
1224  if (it == _mapped_walkers_id.end()) {
1225  return false;
1226  }
1227 
1228  // get the index found
1229  int index = it->second;
1230  if (index == -1) {
1231  return false;
1232  }
1233 
1234  // get the walker
1235  const dtCrowdAgent *agent;
1236  {
1237  // critical section, force single thread running this
1238  std::lock_guard<std::mutex> lock(_mutex);
1239  agent = _crowd->getAgent(index);
1240  }
1241 
1242  // mark
1243  alive = !agent->dead;
1244 
1245  return true;
1246  }
1247 
1248 } // namespace nav
1249 } // namespace carla
void SetSimulator(std::weak_ptr< carla::client::detail::Simulator > simulator)
reference to the simulator to access API functions
Definition: Navigation.cpp:71
static const float AGENT_RADIUS
Definition: Navigation.cpp:37
dtCrowd * _crowd
crowd
Definition: Navigation.h:130
void SetNav(Navigation *nav)
assign the navigation module
std::unordered_map< ActorId, int > _mapped_vehicles_id
Definition: Navigation.h:133
std::vector< uint8_t > _binary_mesh
Definition: Navigation.h:124
std::unordered_map< int, ActorId > _mapped_by_index
Definition: Navigation.h:135
static void log(Args &&... args)
Definition: Logging.h:59
static const float AGENT_UNBLOCK_DISTANCE_SQUARED
Definition: Navigation.cpp:40
static const int MAX_AGENTS
Definition: Navigation.cpp:34
bool AddWalker(ActorId id, carla::geom::Location from)
create a new walker
Definition: Navigation.cpp:473
bool RemoveAgent(ActorId id)
remove an agent
Definition: Navigation.cpp:663
Vector3D extent
Half the size of the BoundingBox in local space.
bool GetWalkerPosition(ActorId id, carla::geom::Location &location)
get the walker current location
Definition: Navigation.cpp:987
dtNavMeshQuery * _nav_query
Definition: Navigation.h:128
rpc::ActorId ActorId
Definition: ActorId.h:18
carla::rpc::ActorId id
Definition: Navigation.h:48
std::unordered_map< ActorId, int > _mapped_walkers_id
mapping Id
Definition: Navigation.h:132
float SquaredLength() const
Definition: geom/Vector3D.h:45
void PauseAgent(ActorId id, bool pause)
set an agent as paused for the crowd
static const int MAX_QUERY_SEARCH_NODES
Definition: Navigation.cpp:35
This file contains definitions of common data structures used in traffic manager. ...
Definition: Carla.cpp:133
Represents the state of all the actors of an episode at a given frame.
Definition: EpisodeState.h:27
bool HasVehicleNear(ActorId id, float distance, carla::geom::Location direction)
return if the agent has a vehicle near (as neighbour)
static float frand()
Definition: Navigation.cpp:47
bool SetWalkerTarget(ActorId id, carla::geom::Location to)
set a new target point to go through a route with events
Definition: Navigation.cpp:765
bool RemoveWalker(ActorId id)
remove a walker route
geom::Vector3D Vector3D
Definition: rpc/Vector3D.h:14
bool SetWalkerLookAt(ActorId id, carla::geom::Location location)
make agent look at some location
carla::geom::BoundingBox bounding
Definition: Navigation.h:50
WalkerManager _walker_manager
walker manager for the route planning with events
Definition: Navigation.h:143
#define DEBUG_ASSERT(predicate)
Definition: Debug.h:66
carla::geom::Transform transform
Definition: Navigation.h:49
bool AddOrUpdateVehicle(VehicleCollisionInfo &vehicle)
create a new vehicle in crowd to be avoided by walkers
Definition: Navigation.cpp:534
double min(double v1, double v2)
Definition: Simplify.h:294
bool SetWalkerDirectTarget(ActorId id, carla::geom::Location to)
Definition: Navigation.cpp:782
std::unordered_map< ActorId, float > _yaw_walkers
store walkers yaw angle from previous tick
Definition: Navigation.h:137
std::weak_ptr< carla::client::detail::Simulator > _simulator
Definition: Navigation.h:145
bool SetWalkerDirectTargetIndex(int index, carla::geom::Location to)
Definition: Navigation.cpp:799
bool GetPath(carla::geom::Location from, carla::geom::Location to, dtQueryFilter *filter, std::vector< carla::geom::Location > &path, std::vector< unsigned char > &area)
return the path points to go from one position to another
Definition: Navigation.cpp:267
std::unordered_map< int, carla::geom::Vector3D > _walkers_blocked_position
saves the position of each actor at intervals and check if any is blocked
Definition: Navigation.h:139
static const float AGENT_UNBLOCK_TIME
Definition: Navigation.cpp:41
void SetPedestriansCrossFactor(float percentage)
set the probability that an agent could cross the roads in its path following
void UpdateCrowd(const client::detail::EpisodeState &state)
update all walkers in crowd
Definition: Navigation.cpp:834
bool GetAgentRoute(ActorId id, carla::geom::Location from, carla::geom::Location to, std::vector< carla::geom::Location > &path, std::vector< unsigned char > &area)
Definition: Navigation.cpp:372
const auto & GetTimestamp() const
Definition: EpisodeState.h:47
bool GetWalkerTransform(ActorId id, carla::geom::Transform &trans)
get the walker current transform
Definition: Navigation.cpp:923
static const int MAX_POLYS
Definition: Navigation.cpp:33
static const float AGENT_UNBLOCK_DISTANCE
Definition: Navigation.cpp:39
static constexpr T ToRadians(T deg)
Definition: Math.h:43
float GetWalkerSpeed(ActorId id)
get the walker current transform
bool GetRandomLocation(carla::geom::Location &location, dtQueryFilter *filter=nullptr) const
get a random location for navigation
bool Update(double delta)
update all routes
void SetSeed(unsigned int seed)
set the seed to use with random numbers
Definition: Navigation.cpp:78
void SetAgentFilter(int agent_index, int filter_index)
assign a filter index to an agent
bool SetWalkerMaxSpeed(ActorId id, float max_speed)
set new max speed
Definition: Navigation.cpp:735
static const float AREA_GRASS_COST
Definition: Navigation.cpp:43
bool SetWalkerRoute(ActorId id)
set a new route from its current position
static const float AREA_ROAD_COST
Definition: Navigation.cpp:44
struct to send info about vehicles to the crowd
Definition: Navigation.h:47
bool IsWalkerAlive(ActorId id, bool &alive)
return if the agent has been killed by a vehicle
static const float AGENT_HEIGHT
Definition: Navigation.cpp:36
dtNavMesh * _nav_mesh
meshes
Definition: Navigation.h:127
bool AddWalker(ActorId id)
create a new walker route
bool Load(const std::string &filename)
load navigation data
Definition: Navigation.cpp:83
bool UpdateVehicles(std::vector< VehicleCollisionInfo > vehicles)
add/update/delete vehicles in crowd
Definition: Navigation.cpp:709
void CreateCrowd(void)
create the crowd object
Definition: Navigation.cpp:201
void SetSimulator(std::weak_ptr< carla::client::detail::Simulator > simulator)
reference to the simulator to access API functions
static Vector3D RotatePointOnOrigin2D(Vector3D p, float angle)
Definition: Math.cpp:111