CARLA
 
载入中...
搜索中...
未找到
Navigation.cpp
浏览该文件的文档.
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"
14#include "carla/geom/Math.h"
15
16#include <iterator>
17#include <fstream>
18#include <mutex>
19
20namespace carla {
21namespace nav {
22
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;
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
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;
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();
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
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();
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
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
#define DEBUG_ASSERT(predicate)
Definition Debug.h:66
double min(double v1, double v2)
Definition Simplify.h:294
Represents the state of all the actors of an episode at a given frame.
const auto & GetTimestamp() const
Vector3D extent
Half the size of the BoundingBox in local space
float SquaredLength() const
bool SetWalkerMaxSpeed(ActorId id, float max_speed)
set new max speed
void UpdateCrowd(const client::detail::EpisodeState &state)
update all walkers in crowd
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
void SetAgentFilter(int agent_index, int filter_index)
assign a filter index to an agent
std::unordered_map< ActorId, int > _mapped_vehicles_id
Definition Navigation.h:133
std::unordered_map< ActorId, int > _mapped_walkers_id
mapping Id
Definition Navigation.h:132
bool RemoveAgent(ActorId id)
remove an agent
std::weak_ptr< carla::client::detail::Simulator > _simulator
Definition Navigation.h:145
bool GetWalkerPosition(ActorId id, carla::geom::Location &location)
get the walker current location
float GetWalkerSpeed(ActorId id)
get the walker current transform
bool Load(const std::string &filename)
load navigation data
bool SetWalkerTarget(ActorId id, carla::geom::Location to)
set a new target point to go through a route with events
void SetSeed(unsigned int seed)
set the seed to use with random numbers
dtNavMesh * _nav_mesh
meshes
Definition Navigation.h:127
bool UpdateVehicles(std::vector< VehicleCollisionInfo > vehicles)
add/update/delete vehicles in crowd
std::unordered_map< int, ActorId > _mapped_by_index
Definition Navigation.h:135
bool SetWalkerDirectTarget(ActorId id, carla::geom::Location to)
bool SetWalkerLookAt(ActorId id, carla::geom::Location location)
make agent look at some location
void PauseAgent(ActorId id, bool pause)
set an agent as paused for the crowd
bool HasVehicleNear(ActorId id, float distance, carla::geom::Location direction)
return if the agent has a vehicle near (as neighbour)
bool GetWalkerTransform(ActorId id, carla::geom::Transform &trans)
get the walker current transform
bool GetRandomLocation(carla::geom::Location &location, dtQueryFilter *filter=nullptr) const
get a random location for navigation
bool IsWalkerAlive(ActorId id, bool &alive)
return if the agent has been killed by a vehicle
WalkerManager _walker_manager
walker manager for the route planning with events
Definition Navigation.h:143
bool GetAgentRoute(ActorId id, carla::geom::Location from, carla::geom::Location to, std::vector< carla::geom::Location > &path, std::vector< unsigned char > &area)
void SetPedestriansCrossFactor(float percentage)
set the probability that an agent could cross the roads in its path following
std::unordered_map< ActorId, float > _yaw_walkers
store walkers yaw angle from previous tick
Definition Navigation.h:137
dtCrowd * _crowd
crowd
Definition Navigation.h:130
bool AddWalker(ActorId id, carla::geom::Location from)
create a new walker
std::vector< uint8_t > _binary_mesh
Definition Navigation.h:124
bool SetWalkerDirectTargetIndex(int index, carla::geom::Location to)
void SetSimulator(std::weak_ptr< carla::client::detail::Simulator > simulator)
reference to the simulator to access API functions
dtNavMeshQuery * _nav_query
Definition Navigation.h:128
void CreateCrowd(void)
create the crowd object
bool AddOrUpdateVehicle(VehicleCollisionInfo &vehicle)
create a new vehicle in crowd to be avoided by walkers
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
bool RemoveWalker(ActorId id)
remove a walker route
bool AddWalker(ActorId id)
create a new walker route
void SetSimulator(std::weak_ptr< carla::client::detail::Simulator > simulator)
reference to the simulator to access API functions
bool Update(double delta)
update all routes
void SetNav(Navigation *nav)
assign the navigation module
bool SetWalkerRoute(ActorId id)
set a new route from its current position
static void log(Args &&... args)
Definition Logging.h:59
@ DT_CROWD_OPTIMIZE_TOPO
@ DT_CROWD_OBSTACLE_AVOIDANCE
@ DT_CROWD_SEPARATION
@ DT_CROWD_OPTIMIZE_VIS
@ DT_CROWD_ANTICIPATE_TURNS
@ CARLA_AREA_GRASS
Definition Navigation.h:31
@ CARLA_AREA_ROAD
Definition Navigation.h:30
static const float AREA_ROAD_COST
static float frand()
@ CARLA_TYPE_WALKABLE
Definition Navigation.h:43
@ CARLA_TYPE_SIDEWALK
Definition Navigation.h:37
@ CARLA_TYPE_NONE
Definition Navigation.h:36
@ CARLA_TYPE_ROAD
Definition Navigation.h:39
static const float AGENT_UNBLOCK_TIME
static const float AGENT_RADIUS
static const float AGENT_HEIGHT
static const float AGENT_UNBLOCK_DISTANCE_SQUARED
static const int MAX_AGENTS
static const int MAX_POLYS
static const int MAX_QUERY_SEARCH_NODES
static const float AGENT_UNBLOCK_DISTANCE
static const float AREA_GRASS_COST
This file contains definitions of common data structures used in traffic manager.
Definition Carla.cpp:133
rpc::ActorId ActorId
Definition ActorId.h:18
struct to send info about vehicles to the crowd
Definition Navigation.h:47
carla::geom::BoundingBox bounding
Definition Navigation.h:50
carla::geom::Transform transform
Definition Navigation.h:49