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 // 避免 M_PI 未定义错误(Visual Studio 2015 和 2017 中的错误)
8
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 // 这些设置与 RecastBuilder 中的设置相同,因此如果您更改代理的高度,则应该在 RecastBuilder 中执行相同的操作
32 static const int MAX_POLYS = 256; // 定义最大多边形数量为256
33 static const int MAX_AGENTS = 500; // 定义最大代理(Agent)数量为500
34 static const int MAX_QUERY_SEARCH_NODES = 2048; // 定义最大查询搜索节点数量为2048
35 static const float AGENT_HEIGHT = 1.8f; // 定义代理的高度为1.8米
36 static const float AGENT_RADIUS = 0.3f; // 定义代理的半径为0.3米
37
38 static const float AGENT_UNBLOCK_DISTANCE = 0.5f; // 定义代理解堵距离为0.5米,即代理在被阻挡后需要保持的距离
39 static const float AGENT_UNBLOCK_DISTANCE_SQUARED = AGENT_UNBLOCK_DISTANCE * AGENT_UNBLOCK_DISTANCE; // 定义代理解堵距离的平方,用于计算距离时避免开方操作,提高效率
40 static const float AGENT_UNBLOCK_TIME = 4.0f; // 定义代理解堵时间为4秒,即代理在被阻挡后等待的时间
41
42 static const float AREA_GRASS_COST = 1.0f; // 定义草地区域的成本为1.0,用于路径规划时的权重计算
43 static const float AREA_ROAD_COST = 10.0f; // 定义道路区域的成本为10.0,用于路径规划时的权重计算,通常道路的成本高于草地
44
45 // 返回一个随机的浮点数 float
46 static float frand() {
47 return static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
48 }
49
51 // 指定行人管理器
53 }
54
56 _ready = false; // 将_ready标志设置为false,表示导航系统不再就绪
57 _time_to_unblock = 0.0f; // 将_time_to_unblock重置为0.0f,表示没有等待解堵的时间
58 _mapped_walkers_id.clear(); // 清空_mapped_walkers_id列表,该列表存储了映射的步行者ID
59 _mapped_vehicles_id.clear(); // 清空_mapped_vehicles_id列表,该列表存储了映射的车辆ID
60 _mapped_by_index.clear(); // 清空_mapped_by_index列表,该列表可能存储了按索引映射的对象
61 _walkers_blocked_position.clear(); // 清空_walkers_blocked_position列表,该列表存储了被阻塞步行者的位置
62 _yaw_walkers.clear(); // 清空_yaw_walkers列表,该列表可能存储了步行者的朝向信息
63 _binary_mesh.clear(); // 清空_binary_mesh,该变量可能存储了二进制网格数据
64 dtFreeCrowd(_crowd); // 释放_crowd资源,_crowd是用于人群模拟的动态组件
65 dtFreeNavMeshQuery(_nav_query); // 释放_nav_query资源,_nav_query是用于路径查询的组件
66 dtFreeNavMesh(_nav_mesh); // 释放_nav_mesh资源,_nav_mesh是用于路径规划的导航网格
67 }
68
69 // 参考模拟器访问API函数
70 void Navigation::SetSimulator(std::weak_ptr<carla::client::detail::Simulator> simulator)
71 {
72 // 将传入的模拟器对象的弱引用赋值给成员变量_simulator
73 // 使用弱引用可以避免循环引用问题,从而防止内存泄漏
74 _simulator = simulator;
75 // 将模拟器的弱引用传递给步行者管理器,以便步行者管理器可以与模拟器进行交互
77 }
78
79 // 设置要使用的随机数种子
80 void Navigation::SetSeed(unsigned int seed) {
81 // 使用传入的种子值初始化随机数生成器
82 srand(seed);
83 }
84
85 // 加载导航数据
86 bool Navigation::Load(const std::string &filename) {
87 std::ifstream f; // 创建一个输入文件流对象
88 std::istream_iterator<uint8_t> start(f), end; // 创建两个迭代器,用于读取文件内容
89
90 // 读取整个文件
91 // 以二进制模式打开文件
92 f.open(filename, std::ios::binary);
93 // 如果文件打开失败,则返回false
94 if (!f.is_open()) {
95 return false;
96 }
97 std::vector<uint8_t> content(start, end);
98 f.close();
99
100 // 解析内容
101 return Load(std::move(content));
102 }
103
104 // 从内存中加载导航数据
105 bool Navigation::Load(std::vector<uint8_t> content) {
106 // 定义导航网格集合的魔术数和版本号
107 const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; // 'MSET';
108 const int NAVMESHSET_VERSION = 1;
109 // 使用#pragma pack(push, 1)来取消结构体成员的对齐,确保结构体大小与二进制数据匹配
110#pragma pack(push, 1)
111
112 // 导航网格集合头的结构体
113 struct NavMeshSetHeader {
114 int magic; // 魔术
115 int version; // 版本
116 int num_tiles; // 瓦片数
117 dtNavMeshParams params; // 导航网格参数,定义了导航网格的一些属性
118 } header;
119 // 导航网格瓦片头的结构体
120 struct NavMeshTileHeader {
121 dtTileRef tile_ref; // 瓦片引用,用于在导航网格中唯一标识一个瓦片
122 int data_size; // 数据大小
123 };
124 // 恢复默认的结构体对齐方式
125#pragma pack(pop)
126
127 // 检查 导航网格集合头的结构体大小
128 // 如果内存中导航数据 都小于 头的大小,则报错
129 if (content.size() < sizeof(header)) {
130 logging::log("Nav: failed loading binary");
131 return false;
132 }
133
134 // 读取文件的头
135 unsigned long pos = 0;// 定义当前读取位置
136 memcpy(&header, &content[pos], sizeof(header)); // 使用memcpy复制头数据到结构体
137 pos += sizeof(header);// 更新读取位置
138
139 // 检查文件的魔术和版本
140 if (header.magic != NAVMESHSET_MAGIC || header.version != NAVMESHSET_VERSION) {
141 // 如果文件的魔术数字或版本不匹配,则函数返回false
142 return false;
143 }
144
145 // 分配导航网格对象的内存
146 dtNavMesh *mesh = dtAllocNavMesh();
147 if (!mesh) {
148 // 如果内存分配失败,则函数返回false
149 return false;
150 }
151
152 // 使用文件的头信息中的参数初始化导航网格
153 // 设置瓦片的数目和原点
154 dtStatus status = mesh->init(&header.params);
155 if (dtStatusFailed(status)) {
156 return false;
157 }
158
159 // 读取瓦片数据
160 for (int i = 0; i < header.num_tiles; ++i) {
161 NavMeshTileHeader tile_header;
162
163 // 读取瓦片头
164 memcpy(&tile_header, &content[pos], sizeof(tile_header));
165 pos += sizeof(tile_header);
166 if (pos >= content.size()) {
167 // 如果读取瓦片头后位置超出内容大小,释放网格并返回false
168 dtFreeNavMesh(mesh);
169 return false;
170 }
171
172 // 检查瓦片的有效性
173 if (!tile_header.tile_ref || !tile_header.data_size) {
174 // 如果瓦片无效,跳出循环
175 break;
176 }
177
178 // 分配缓冲区内存
179 char *data = static_cast<char *>(dtAlloc(static_cast<size_t>(tile_header.data_size), DT_ALLOC_PERM));
180 if (!data) {
181 // 如果内存分配失败,跳出循环
182 break;
183 }
184
185 // 读取瓦片
186 memcpy(data, &content[pos], static_cast<size_t>(tile_header.data_size));
187 pos += static_cast<unsigned long>(tile_header.data_size);
188 if (pos > content.size()) {
189 // 如果读取瓦片数据后位置超出内容大小,释放数据和网格并返回false
190 dtFree(data);
191 dtFreeNavMesh(mesh);
192 return false;
193 }
194
195 // 添加瓦片数据
196 mesh->addTile(reinterpret_cast<unsigned char *>(data), tile_header.data_size, DT_TILE_FREE_DATA,
197 tile_header.tile_ref, 0);
198 }
199
200 // 交换
201 dtFreeNavMesh(_nav_mesh);
202 _nav_mesh = mesh;
203
204 // 准备查询对象
205 dtFreeNavMeshQuery(_nav_query);
206 _nav_query = dtAllocNavMeshQuery();
208
209 // 拷贝
210 _binary_mesh = std::move(content);
211 _ready = true; // 标记为准备就绪
212
213 // 创建并初始化人群管理器
214 CreateCrowd();
215
216 return true;// 表示成功加载和初始化导航网格
217 }
218
219// 创建并初始化人群管理器
221
222 // 检查是否一切就绪
223 if (!_ready) {
224 return;
225 }
226
227 DEBUG_ASSERT(_crowd == nullptr);// 断言_crowd成员变量为nullptr,确保未重复初始化
228
229 // 创建并初始化
230 _crowd = dtAllocCrowd();
231 // 这些半径应该是车辆的最大尺寸 (CarlaCola for Carla)
232 const float max_agent_radius = AGENT_RADIUS * 20;
233 if (!_crowd->init(MAX_AGENTS, max_agent_radius, _nav_mesh)) {
234 // 如果初始化失败,记录日志并返回
235 logging::log("Nav: failed to create crowd");
236 return;
237 }
238
239 // 设置不同的过滤器
240 // 过滤器 0 不能在道路上行走
241 _crowd->getEditableFilter(0)->setIncludeFlags(CARLA_TYPE_WALKABLE);
242 _crowd->getEditableFilter(0)->setExcludeFlags(CARLA_TYPE_ROAD);
243 _crowd->getEditableFilter(0)->setAreaCost(CARLA_AREA_ROAD, AREA_ROAD_COST);
244 _crowd->getEditableFilter(0)->setAreaCost(CARLA_AREA_GRASS, AREA_GRASS_COST);
245 // 过滤器 1 可以在道路上行走
246 _crowd->getEditableFilter(1)->setIncludeFlags(CARLA_TYPE_WALKABLE);
247 _crowd->getEditableFilter(1)->setExcludeFlags(CARLA_TYPE_NONE);
248 _crowd->getEditableFilter(1)->setAreaCost(CARLA_AREA_ROAD, AREA_ROAD_COST);
249 _crowd->getEditableFilter(1)->setAreaCost(CARLA_AREA_GRASS, AREA_GRASS_COST);
250
251 // 设置不同品质的局部避让参数。
252 dtObstacleAvoidanceParams params;
253 // 主要使用默认设置,从 dtCrowd 复制。
254 memcpy(&params, _crowd->getObstacleAvoidanceParams(0), sizeof(dtObstacleAvoidanceParams));
255
256 // Low (11)
257 params.velBias = 0.5f;
258 params.adaptiveDivs = 5;
259 params.adaptiveRings = 2;
260 params.adaptiveDepth = 1;
261 _crowd->setObstacleAvoidanceParams(0, &params);
262
263 // Medium (22)
264 params.velBias = 0.5f;
265 params.adaptiveDivs = 5;
266 params.adaptiveRings = 2;
267 params.adaptiveDepth = 2;
268 _crowd->setObstacleAvoidanceParams(1, &params);
269
270 // Good (45)
271 params.velBias = 0.5f;
272 params.adaptiveDivs = 7;
273 params.adaptiveRings = 2;
274 params.adaptiveDepth = 3;
275 _crowd->setObstacleAvoidanceParams(2, &params);
276
277 // High (66)
278 params.velBias = 0.5f;
279 params.adaptiveDivs = 7;
280 params.adaptiveRings = 3;
281 params.adaptiveDepth = 3;
282
283 _crowd->setObstacleAvoidanceParams(3, &params);
284 }
285
286 // 返回从一个位置到另一个位置的路径点
288 carla::geom::Location to, // 目标位置
289 dtQueryFilter * filter, // 用于路径查询的过滤器,可以筛选路径通过的区域类型
290 std::vector<carla::geom::Location> &path, // 用于存储计算出的路径点的向量
291 std::vector<unsigned char> &area) { // 用于存储路径点所属区域类型的向量
292 // 找到路径
293 float straight_path[MAX_POLYS * 3];
294 unsigned char straight_path_flags[MAX_POLYS];
295 dtPolyRef straight_path_polys[MAX_POLYS];
296 int num_straight_path; // 直线路径中的点数量
297 int straight_path_options = DT_STRAIGHTPATH_AREA_CROSSINGS; // 直线路径查询的选项
298
299 // 路径中的多边形
300 dtPolyRef polys[MAX_POLYS];
301 int num_polys; // 路径中的多边形数量
302
303 // 检查是否一切就绪
304 if (!_ready) {
305 return false;
306 }
307
308 // 确保导航查询对象不为空
309 DEBUG_ASSERT(_nav_query != nullptr);
310
311 // 点的延伸
312 float poly_pick_ext[3];
313 poly_pick_ext[0] = 2;
314 poly_pick_ext[1] = 4;
315 poly_pick_ext[2] = 2;
316
317 // 筛选
318 dtQueryFilter filter2;
319 if (filter == nullptr) {
320 filter2.setAreaCost(CARLA_AREA_ROAD, AREA_ROAD_COST); // 设置道路区域的成本
321 filter2.setAreaCost(CARLA_AREA_GRASS, AREA_GRASS_COST); // 设置草地区域的成本
322 filter2.setIncludeFlags(CARLA_TYPE_WALKABLE); // 设置包含的标志(可通行区域)
323 filter2.setExcludeFlags(CARLA_TYPE_NONE); // 设置排除的标志(无不可通行区域)
324 filter = &filter2; // 使用默认过滤器
325 }
326
327 // 设置点
328 dtPolyRef start_ref = 0;
329 dtPolyRef end_ref = 0;
330 float start_pos[3] = { from.x, from.z, from.y }; // 转换为Detour库的坐标顺序(x, z, y)
331 float end_pos[3] = { to.x, to.z, to.y };
332 {
333 // 关键部分,强制单线程运行这里
334 std::lock_guard<std::mutex> lock(_mutex);
335 _nav_query->findNearestPoly(start_pos, poly_pick_ext, filter, &start_ref, 0);
336 _nav_query->findNearestPoly(end_pos, poly_pick_ext, filter, &end_ref, 0);
337 }
338 // 如果未找到起始或目标多边形,则返回失败
339 if (!start_ref || !end_ref) {
340 return false;
341 }
342
343 {
344 // 关键部分,强制单线程运行这里
345 std::lock_guard<std::mutex> lock(_mutex);
346 // 获取节点的路径
347 _nav_query->findPath(start_ref, end_ref, start_pos, end_pos, filter, polys, &num_polys, MAX_POLYS);
348 }
349
350 // 获得点的路径
351 num_straight_path = 0;
352 if (num_polys == 0) {
353 return false;
354 }
355
356 // 如果是部分路径,请确保终点与最后一个多边形相接
357 float end_pos2[3];
358 dtVcopy(end_pos2, end_pos);
359 if (polys[num_polys - 1] != end_ref) {
360 // 关键部分,强制单线程运行这里
361 std::lock_guard<std::mutex> lock(_mutex);
362 _nav_query->closestPointOnPoly(polys[num_polys - 1], end_pos, end_pos2, 0);
363 }
364
365 // 获得点
366 {
367 // 关键部分,强制单线程运行这里
368 std::lock_guard<std::mutex> lock(_mutex);
369 _nav_query->findStraightPath(start_pos, end_pos2, polys, num_polys,
370 straight_path, straight_path_flags,
371 straight_path_polys, &num_straight_path, MAX_POLYS, straight_path_options);
372 }
373
374 // 将路径复制到输出缓冲区
375 path.clear();
376 path.reserve(static_cast<unsigned long>(num_straight_path));
377 unsigned char area_type;
378 for (int i = 0, j = 0; j < num_straight_path; i += 3, ++j) {
379 // 保存虚幻轴的坐标(x,z,y)
380 path.emplace_back(straight_path[i], straight_path[i + 2], straight_path[i + 1]);
381 // 保存区域类型
382 {
383 // 关键部分,强制单线程运行这里
384 std::lock_guard<std::mutex> lock(_mutex);
385 _nav_mesh->getPolyArea(straight_path_polys[j], &area_type);// 获取路径点所属的多边形的区域类型
386 }
387 area.emplace_back(area_type);
388 }
389
390 return true;// 成功找到路径
391 }
392
394 std::vector<carla::geom::Location> &path, std::vector<unsigned char> &area) {
395 // 找到路径
396 float straight_path[MAX_POLYS * 3];
397 unsigned char straight_path_flags[MAX_POLYS];
398 dtPolyRef straight_path_polys[MAX_POLYS];
399 int num_straight_path = 0;
400 int straight_path_options = DT_STRAIGHTPATH_AREA_CROSSINGS;
401
402 // 路径中的多边形
403 dtPolyRef polys[MAX_POLYS];
404 int num_polys;
405
406 // 检查是否一切就绪
407 if (!_ready) {
408 return false;
409 }
410
411 DEBUG_ASSERT(_nav_query != nullptr);
412
413 // 点的扩展
414 float poly_pick_ext[3] = {2,4,2};
415
416 // 从代理获取当前过滤器
417 auto it = _mapped_walkers_id.find(id);
418 if (it == _mapped_walkers_id.end())
419 return false;
420
421
422// 定义一个指向查询过滤器的指针,用于后续的路径查询。
423 const dtQueryFilter *filter;
424 {
425 // 关键部分,强制单线程运行这里
426 std::lock_guard<std::mutex> lock(_mutex);
427 // 根据代理的参数获取对应的过滤器。
428 filter = _crowd->getFilter(_crowd->getAgent(it->second)->params.queryFilterType);
429 }
430
431 // 设置点
432 dtPolyRef start_ref = 0;
433 dtPolyRef end_ref = 0;
434 // 定义起点和终点的位置数组,注意这里z和y的顺序被交换了,这取决于导航网格的坐标系
435 float start_pos[3] = { from.x, from.z, from.y };
436 float end_pos[3] = { to.x, to.z, to.y };
437 {
438 // 关键部分,强制单线程运行这里
439 std::lock_guard<std::mutex> lock(_mutex);
440 // 查询离起点最近的多边形。
441 _nav_query->findNearestPoly(start_pos, poly_pick_ext, filter, &start_ref, 0);
442 // 查询离终点最近的多边形。
443 _nav_query->findNearestPoly(end_pos, poly_pick_ext, filter, &end_ref, 0);
444 }
445 if (!start_ref || !end_ref) {
446 return false;
447 }
448
449 // 获取点的路径
450 {
451 // 关键部分,强制单线程运行这里
452 std::lock_guard<std::mutex> lock(_mutex);
453 // 使用导航查询对象查询路径。
454 _nav_query->findPath(start_ref, end_ref, start_pos, end_pos, filter, polys, &num_polys, MAX_POLYS);
455 }
456
457 // 获取点的路径
458 if (num_polys == 0) {
459 return false;
460 }
461
462 // 如果是部分路径,请确保终点与最后一个多边形相接
463 float end_pos2[3];
464 dtVcopy(end_pos2, end_pos); // 先复制终点位置
465 if (polys[num_polys - 1] != end_ref) {
466 // 关键部分,强制单线程运行这里
467 std::lock_guard<std::mutex> lock(_mutex);
468 // 在最后一个多边形上找到最接近终点的点
469 _nav_query->closestPointOnPoly(polys[num_polys - 1], end_pos, end_pos2, 0);
470 }
471
472 // 获取点
473 {
474 // 关键部分,强制单线程运行这里
475 // 锁定互斥锁,确保直线路径查询是单线程执行的。
476 std::lock_guard<std::mutex> lock(_mutex);
477 // 使用导航查询对象获取直线路径。
478 _nav_query->findStraightPath(start_pos, end_pos2, polys, num_polys,
479 straight_path, straight_path_flags,
480 straight_path_polys, &num_straight_path, MAX_POLYS, straight_path_options);
481 }
482
483 // 将路径复制到输出缓冲区
484 path.clear();
485 path.reserve(static_cast<unsigned long>(num_straight_path));
486 unsigned char area_type;
487 for (int i = 0, j = 0; j < num_straight_path; i += 3, ++j) {
488 // 保存虚幻轴的坐标(x,z,y)
489 path.emplace_back(straight_path[i], straight_path[i + 2], straight_path[i + 1]);
490 // 保存面积类型
491 {
492 // 关键部分,强制单线程运行这里
493 std::lock_guard<std::mutex> lock(_mutex);
494 _nav_mesh->getPolyArea(straight_path_polys[j], &area_type);
495 }
496 area.emplace_back(area_type);
497 }
498
499 return true;
500 }
501
502 // 在人群中创造新的行人
504 dtCrowdAgentParams params;
505
506 // 检查是否一切就绪
507 if (!_ready) {
508 return false;
509 }
510
511 DEBUG_ASSERT(_crowd != nullptr);
512
513 // 设置参数
514 memset(&params, 0, sizeof(params));
515 params.radius = AGENT_RADIUS;
516 params.height = AGENT_HEIGHT;
517 params.maxAcceleration = 160.0f;
518 params.maxSpeed = 1.47f;
519 params.collisionQueryRange = 10;
520 params.obstacleAvoidanceType = 3;
521 params.separationWeight = 0.5f;
522
523 // 设置代理是否可以过马路
524 if (frand() <= _probability_crossing) {
525 params.queryFilterType = 1;
526 } else {
527 params.queryFilterType = 0;
528 }
529
530 // flags
531 params.updateFlags = 0;
532 params.updateFlags |= DT_CROWD_ANTICIPATE_TURNS;
533 params.updateFlags |= DT_CROWD_OBSTACLE_AVOIDANCE;
534 params.updateFlags |= DT_CROWD_SEPARATION;
535
536 // 来自虚幻坐标(减去一半高度以将枢轴从中心(虚幻)移动到底部(recast))
537 float point_from[3] = { from.x, from.z - (AGENT_HEIGHT / 2.0f), from.y };
538 // 添加行人
539 int index;
540 {
541 // 关键部分,强制单线程运行这里
542 std::lock_guard<std::mutex> lock(_mutex);
543 index = _crowd->addAgent(point_from, &params);
544 if (index == -1) {
545 return false;
546 }
547 }
548
549 // 保存 id
550 _mapped_walkers_id[id] = index;
551 _mapped_by_index[index] = id;
552
553 // 初始化偏航角
554 _yaw_walkers[id] = 0.0f;
555
556 // 添加行人进行路线规划
558
559 return true;
560 }
561
562 // 在人群中创造一种新的车辆,以便行人避开
564 namespace cg = carla::geom;
565 dtCrowdAgentParams params;
566
567 // 检查是否一切就绪
568 if (!_ready) {
569 return false;
570 }
571
572 DEBUG_ASSERT(_crowd != nullptr);
573
574 // 获取边界框扩展以及周围的一些空间
575 float marge = 0.8f;
576 float hx = vehicle.bounding.extent.x + marge;
577 float hy = vehicle.bounding.extent.y + marge;
578 // 定义边界框的 4 个角
579 cg::Vector3D box_corner1 {-hx, -hy, 0};
580 cg::Vector3D box_corner2 { hx + 0.2f, -hy, 0};
581 cg::Vector3D box_corner3 { hx + 0.2f, hy, 0};
582 cg::Vector3D box_corner4 {-hx, hy, 0};
583 // 旋转点
584 float angle = cg::Math::ToRadians(vehicle.transform.rotation.yaw);
585 box_corner1 = cg::Math::RotatePointOnOrigin2D(box_corner1, angle);
586 box_corner2 = cg::Math::RotatePointOnOrigin2D(box_corner2, angle);
587 box_corner3 = cg::Math::RotatePointOnOrigin2D(box_corner3, angle);
588 box_corner4 = cg::Math::RotatePointOnOrigin2D(box_corner4, angle);
589 // 转换为世界位置
590 box_corner1 += vehicle.transform.location;
591 box_corner2 += vehicle.transform.location;
592 box_corner3 += vehicle.transform.location;
593 box_corner4 += vehicle.transform.location;
594
595 // 检查该参与者是否存在
596 auto it = _mapped_vehicles_id.find(vehicle.id);
597 if (it != _mapped_vehicles_id.end()) {
598 // 获得找到的索引
599 int index = it->second;
600 if (index != -1) {
601 // 获得智能体
602 dtCrowdAgent *agent;
603 {
604 // 关键部分,强制单线程运行这里
605 std::lock_guard<std::mutex> lock(_mutex);
606 agent = _crowd->getEditableAgent(index);
607 }
608 if (agent) {
609 // 更新它的位置
610 agent->npos[0] = vehicle.transform.location.x;
611 agent->npos[1] = vehicle.transform.location.z;
612 agent->npos[2] = vehicle.transform.location.y;
613 // 更新其朝向的边界框
614 agent->params.obb[0] = box_corner1.x;
615 agent->params.obb[1] = box_corner1.z;
616 agent->params.obb[2] = box_corner1.y;
617 agent->params.obb[3] = box_corner2.x;
618 agent->params.obb[4] = box_corner2.z;
619 agent->params.obb[5] = box_corner2.y;
620 agent->params.obb[6] = box_corner3.x;
621 agent->params.obb[7] = box_corner3.z;
622 agent->params.obb[8] = box_corner3.y;
623 agent->params.obb[9] = box_corner4.x;
624 agent->params.obb[10] = box_corner4.z;
625 agent->params.obb[11] = box_corner4.y;
626 }
627 return true;
628 }
629 }
630
631 // 设置参数
632 memset(&params, 0, sizeof(params));
633 params.radius = 2;
634 params.height = AGENT_HEIGHT;
635 params.maxAcceleration = 0.0f;
636 params.maxSpeed = 1.47f;
637 params.collisionQueryRange = 0;
638 params.obstacleAvoidanceType = 0;
639 params.separationWeight = 100.0f;
640
641 // 标志
642 params.updateFlags = 0;
643 params.updateFlags |= DT_CROWD_SEPARATION;
644
645 // 更新其朝向的边界框
646 // 数据: [x][y][z] [x][y][z] [x][y][z] [x][y][z]
647 params.useObb = true;
648 params.obb[0] = box_corner1.x;
649 params.obb[1] = box_corner1.z;
650 params.obb[2] = box_corner1.y;
651 params.obb[3] = box_corner2.x;
652 params.obb[4] = box_corner2.z;
653 params.obb[5] = box_corner2.y;
654 params.obb[6] = box_corner3.x;
655 params.obb[7] = box_corner3.z;
656 params.obb[8] = box_corner3.y;
657 params.obb[9] = box_corner4.x;
658 params.obb[10] = box_corner4.z;
659 params.obb[11] = box_corner4.y;
660
661 // 从虚幻坐标(垂直为 Z)到 Recast 坐标(垂直为 Y,右手坐标系)
662 float point_from[3] = { vehicle.transform.location.x,
663 vehicle.transform.location.z,
664 vehicle.transform.location.y };
665
666 // 添加行人
667 int index;
668 {
669 // 关键部分,强制单线程运行这里
670 std::lock_guard<std::mutex> lock(_mutex); // 锁定互斥量,确保代码块在多线程环境下是安全的
671 index = _crowd->addAgent(point_from, &params); // 向人群添加代理,并返回代理的索引
672 if (index == -1) {
673 logging::log("Vehicle agent not added to the crowd by some problem!");
674 return false;
675 }
676
677 // 标记为有效
678 dtCrowdAgent *agent = _crowd->getEditableAgent(index); // 获取代理对象
679 if (agent) {
680 agent->state = DT_CROWDAGENT_STATE_WALKING; // 将代理的状态设为“行走”
681 }
682 }
683
684 // 保存 id
685 _mapped_vehicles_id[vehicle.id] = index; // 将车辆 ID 映射到代理的索引
686 _mapped_by_index[index] = vehicle.id; // 将代理索引映射到车辆 ID
687
688 return true;
689 }
690
691 // 移除代理
693
694 // 检查是否一切就绪
695 if (!_ready) {
696 return false;
697 }
698
699 DEBUG_ASSERT(_crowd != nullptr); // 确保 _crowd 非空
700
701 // 获取内部行人索引
702 auto it = _mapped_walkers_id.find(id); // 在映射表中查找行人 ID
703 if (it != _mapped_walkers_id.end()) {
704 // 从人群中移除
705 {
706 // 关键部分,强制单线程运行这里
707 std::lock_guard<std::mutex> lock(_mutex);
708 _crowd->removeAgent(it->second); // 从人群中移除对应的代理
709 }
710 _walker_manager.RemoveWalker(id); // 从其他管理系统中移除行人
711 // remove from mapping
712 _mapped_walkers_id.erase(it);
713 _mapped_by_index.erase(it->second);
714
715 return true;
716 }
717
718 // get the internal vehicle index
719 it = _mapped_vehicles_id.find(id); // 查找车辆 ID
720 if (it != _mapped_vehicles_id.end()) {
721 // 从人群中移除
722 {
723 // 关键部分,强制单线程运行这里
724 std::lock_guard<std::mutex> lock(_mutex); // 锁定互斥量
725 _crowd->removeAgent(it->second); // 从人群中移除对应的代理
726 }
727 // 从映射中移除
728 _mapped_vehicles_id.erase(it);
729 _mapped_by_index.erase(it->second);
730
731 return true;
732 }
733
734 return false;
735 }
736
737 // 在人群中添加/更新/删除车辆
738 bool Navigation::UpdateVehicles(std::vector<VehicleCollisionInfo> vehicles) {
739 std::unordered_set<carla::rpc::ActorId> updated;
740
741 // 添加所有当前已映射的车辆
742 for (auto &&entry : _mapped_vehicles_id) {
743 updated.insert(entry.first); // 将已映射的车辆 ID 插入 updated 集合
744 }
745
746 // 添加所有车辆(如果已经存在,则仅更新)
747 for (auto &&entry : vehicles) {
748 // 尝试添加或更新车辆
749 AddOrUpdateVehicle(entry);
750 // 标记为已更新(以避免在此帧中删除它)
751 updated.erase(entry.id);
752 }
753
754 // 删除所有未更新的车辆(它们不存在于此帧中)
755 for (auto &&entry : updated) {
756 // 删除未更新的代理
757 RemoveAgent(entry);
758 }
759
760 return true;
761 }
762
763 // 设置新的最大速度
764 bool Navigation::SetWalkerMaxSpeed(ActorId id, float max_speed) {
765
766 // 检查是否一切就绪
767 if (!_ready) {
768 return false;
769 }
770
771 DEBUG_ASSERT(_crowd != nullptr);
772
773 // 获取内部索引
774 auto it = _mapped_walkers_id.find(id);
775 if (it == _mapped_walkers_id.end()) {
776 return false;
777 }
778
779 // 获得智能体
780 {
781 // 关键部分,强制单线程运行这里
782 std::lock_guard<std::mutex> lock(_mutex); // 锁定互斥量,确保单线程安全
783 dtCrowdAgent *agent = _crowd->getEditableAgent(it->second); // 获取代理
784 if (agent) {
785 agent->params.maxSpeed = max_speed; // 设置最大速度
786 return true;
787 }
788 }
789
790 return false;
791 }
792
793 // 设定新的目标点
795
796 // 检查是否一切就绪
797 if (!_ready) {
798 return false;
799 }
800
801 // 获取内部索引
802 auto it = _mapped_walkers_id.find(id);
803 if (it == _mapped_walkers_id.end()) {
804 return false;
805 }
806
807 return _walker_manager.SetWalkerRoute(id, to);
808 }
809
810 // 设置新的目标点,直接前往没有事件发生的地方
812
813 // 检查是否一切就绪
814 if (!_ready) {
815 return false;
816 }
817
818 // 获取内部索引
819 auto it = _mapped_walkers_id.find(id);
820 if (it == _mapped_walkers_id.end()) {
821 return false;
822 }
823
824 return SetWalkerDirectTargetIndex(it->second, to);
825 }
826
827 // 设置新的目标点,直接前往没有事件发生的地方
829
830 // 检查是否一切就绪
831 if (!_ready) {
832 return false;
833 }
834
835 DEBUG_ASSERT(_crowd != nullptr);
836 DEBUG_ASSERT(_nav_query != nullptr);
837
838 if (index == -1) {
839 return false;
840 }
841
842 // 设定目标位置
843 float point_to[3] = { to.x, to.z, to.y };
844 float nearest[3];
845 bool res;
846 {
847 // 关键部分,强制单线程运行这里
848 std::lock_guard<std::mutex> lock(_mutex);
849 const dtQueryFilter *filter = _crowd->getFilter(0);
850 dtPolyRef target_ref;
851 _nav_query->findNearestPoly(point_to, _crowd->getQueryHalfExtents(), filter, &target_ref, nearest);
852 if (!target_ref) {
853 return false;
854 }
855
856 res = _crowd->requestMoveTarget(index, target_ref, point_to);
857 }
858
859 return res;
860 }
861
862 // 更新人群中的所有行人
864
865 // 检查是否一切就绪
866 if (!_ready) {
867 return;
868 }
869
870 DEBUG_ASSERT(_crowd != nullptr);
871
872 // 更新人群代理
873 _delta_seconds = state.GetTimestamp().delta_seconds;
874 {
875 // 关键部分,强制单线程运行这里
876 std::lock_guard<std::mutex> lock(_mutex);
877 _crowd->update(static_cast<float>(_delta_seconds), nullptr);
878 }
879
880 // 更新行人路线
882
883 // 更新检查被堵塞代理的时间
885
886 // 查看所有活跃代理
887 int total_unblocked = 0;
888 int total_agents;
889 {
890 // 关键部分,强制单线程运行这里
891 std::lock_guard<std::mutex> lock(_mutex);
892 total_agents = _crowd->getAgentCount();
893 }
894 const dtCrowdAgent *ag;
895 for (int i = 0; i < total_agents; ++i) {
896 {
897 // 关键部分,强制单线程运行这里
898 std::lock_guard<std::mutex> lock(_mutex);
899 ag = _crowd->getAgent(i);
900 }
901
902 if (!ag->active || ag->paused || ag->dead) {
903 continue;
904 }
905
906 // 仅检查未暂停的行人,不检查车辆
907 if (!ag->params.useObb && !ag->paused) {
908 bool reset_target_pos = false;
909 bool use_same_filter = false;
910
911 // 检查参与者是否解除堵塞
913 // 获取每个参与者移动的距离
915 carla::geom::Vector3D current = carla::geom::Vector3D(ag->npos[0], ag->npos[1], ag->npos[2]);
916 carla::geom::Vector3D distance = current - previous;
917 float d = distance.SquaredLength();
919 ++total_unblocked;
920 reset_target_pos = true;
921 use_same_filter = true;
922 }
923 // 更新当前位置
924 _walkers_blocked_position[i] = current;
925
926 // check to assign a new target position
927 if (reset_target_pos) {
928 // set if the agent can cross roads or not
929 if (!use_same_filter) {
930 if (frand() <= _probability_crossing) {
931 SetAgentFilter(i, 1);
932 } else {
933 SetAgentFilter(i, 0);
934 }
935 }
936 // 设置新的随机目标
937 carla::geom::Location location;
938 GetRandomLocation(location, nullptr);
940 }
941 }
942 }
943 }
944
945 // 检查重置时间
947 _time_to_unblock = 0.0f;
948 }
949 }
950
951 // 获取行人当前变换
953
954 // 检查是否一切就绪
955 if (!_ready) {
956 return false;
957 }
958
959 DEBUG_ASSERT(_crowd != nullptr);
960
961 // 获取内部索引
962 auto it = _mapped_walkers_id.find(id);
963 if (it == _mapped_walkers_id.end()) {
964 return false;
965 }
966
967 // 找到索引
968 int index = it->second;
969 if (index == -1) {
970 return false;
971 }
972
973 // 获得行人
974 const dtCrowdAgent *agent;
975 {
976 // 关键部分,强制单线程运行这里
977 std::lock_guard<std::mutex> lock(_mutex);
978 agent = _crowd->getAgent(index);
979 }
980
981 if (!agent->active) {
982 return false;
983 }
984
985 // 在虚幻坐标中设置其位置
986 trans.location.x = agent->npos[0];
987 trans.location.y = agent->npos[2];
988 trans.location.z = agent->npos[1];
989
990 // 设置其旋转
991 float yaw;
992 float speed = 0.0f;
993 float min = 0.1f;
994 if (agent->vel[0] < -min || agent->vel[0] > min ||
995 agent->vel[2] < -min || agent->vel[2] > min) {
996 yaw = atan2f(agent->vel[2], agent->vel[0]) * (180.0f / static_cast<float>(M_PI));
997 speed = sqrtf(agent->vel[0] * agent->vel[0] + agent->vel[1] * agent->vel[1] + agent->vel[2] * agent->vel[2]);
998 } else {
999 yaw = atan2f(agent->dvel[2], agent->dvel[0]) * (180.0f / static_cast<float>(M_PI));
1000 speed = sqrtf(agent->dvel[0] * agent->dvel[0] + agent->dvel[1] * agent->dvel[1] + agent->dvel[2] * agent->dvel[2]);
1001 }
1002
1003 // 插入当前角度和目标角度
1004 float shortest_angle = fmod(yaw - _yaw_walkers[id] + 540.0f, 360.0f) - 180.0f;
1005 float per = (speed / 1.5f);
1006 if (per > 1.0f) per = 1.0f;
1007 float rotation_speed = per * 6.0f;
1008 trans.rotation.yaw = _yaw_walkers[id] +
1009 (shortest_angle * rotation_speed * static_cast<float>(_delta_seconds));
1010 _yaw_walkers[id] = trans.rotation.yaw;
1011
1012 return true;
1013 }
1014
1015 // 获取行人的当前位置
1017
1018 // 检查是否一切就绪
1019 if (!_ready) {
1020 return false;
1021 }
1022
1023 DEBUG_ASSERT(_crowd != nullptr);
1024
1025 // 获取内部索引
1026 auto it = _mapped_walkers_id.find(id);
1027 if (it == _mapped_walkers_id.end()) {
1028 return false;
1029 }
1030
1031 // 找到索引
1032 int index = it->second;
1033 if (index == -1) {
1034 return false;
1035 }
1036
1037 // 获得行人
1038 const dtCrowdAgent *agent;
1039 {
1040 // 关键部分,强制单线程运行这里
1041 std::lock_guard<std::mutex> lock(_mutex);
1042 agent = _crowd->getAgent(index);
1043 }
1044
1045 if (!agent->active) {
1046 return false;
1047 }
1048
1049 // 在虚幻坐标中设置其位置
1050 location.x = agent->npos[0];
1051 location.y = agent->npos[2];
1052 location.z = agent->npos[1];
1053
1054 return true;
1055 }
1056
1058
1059 // 检查是否一切就绪
1060 if (!_ready) {
1061 return 0.0f;
1062 }
1063
1064 DEBUG_ASSERT(_crowd != nullptr);
1065
1066 // 获取内部索引
1067 auto it = _mapped_walkers_id.find(id);
1068 if (it == _mapped_walkers_id.end()) {
1069 return 0.0f;
1070 }
1071
1072 // 找到索引
1073 int index = it->second;
1074 if (index == -1) {
1075 return 0.0f;
1076 }
1077
1078 // 获得行人
1079 const dtCrowdAgent *agent;
1080 {
1081 // 关键部分,强制单线程运行这里
1082 std::lock_guard<std::mutex> lock(_mutex);
1083 agent = _crowd->getAgent(index);
1084 }
1085
1086 return sqrt(agent->vel[0] * agent->vel[0] + agent->vel[1] * agent->vel[1] + agent->vel[2] *
1087 agent->vel[2]);
1088 }
1089
1090 // 获取随机的导航位置
1091 bool Navigation::GetRandomLocation(carla::geom::Location &location, dtQueryFilter * filter) const {
1092
1093 // 检查是否一切就绪
1094 if (!_ready) {
1095 return false;
1096 }
1097
1098 DEBUG_ASSERT(_nav_query != nullptr);
1099
1100 // 过滤器
1101 dtQueryFilter filter2;
1102 if (filter == nullptr) {
1103 filter2.setIncludeFlags(CARLA_TYPE_SIDEWALK);
1104 filter2.setExcludeFlags(CARLA_TYPE_NONE);
1105 filter = &filter2;
1106 }
1107
1108 // 我们会尝试最多 10 轮,否则我们就找不到好的位置
1109 dtPolyRef random_ref { 0 };
1110 float point[3] { 0.0f, 0.0f, 0.0f };
1111 int rounds = 10;
1112 {
1113 dtStatus status;
1114 // 关键部分,强制单线程运行这里
1115 std::lock_guard<std::mutex> lock(_mutex);
1116 do {
1117 status = _nav_query->findRandomPoint(filter, frand, &random_ref, point);
1118 // 在虚幻坐标中设置位置
1119 if (status == DT_SUCCESS) {
1120 location.x = point[0];
1121 location.y = point[2];
1122 location.z = point[1];
1123 }
1124 --rounds;
1125 } while (status != DT_SUCCESS && rounds > 0);
1126 }
1127
1128 return (rounds > 0);
1129 }
1130
1131 // 为代理分配过滤索引
1132 void Navigation::SetAgentFilter(int agent_index, int filter_index)
1133 {
1134 // 获得行人
1135 dtCrowdAgent *agent;
1136 {
1137 // 关键部分,强制单线程运行这里
1138 std::lock_guard<std::mutex> lock(_mutex);
1139 agent = _crowd->getEditableAgent(agent_index);
1140 }
1141 agent->params.queryFilterType = static_cast<unsigned char>(filter_index);
1142 }
1143
1144 // 设置代理在其路径上过马路的概率 0.0 表示没有行人可以过马路,
1145 // 0.5 表示 50% 的行人可以过马路
1146 // 1.0 表示所有行人都可以在需要时过马路
1148 {
1149 _probability_crossing = percentage;
1150 }
1151
1152 // 将人群中的代理设置为暂停
1153 void Navigation::PauseAgent(ActorId id, bool pause) {
1154 // 检查是否一切就绪
1155 if (!_ready) {
1156 return;
1157 }
1158
1159 DEBUG_ASSERT(_crowd != nullptr);
1160
1161 // 获取内部索引
1162 auto it = _mapped_walkers_id.find(id);
1163 if (it == _mapped_walkers_id.end()) {
1164 return;
1165 }
1166
1167 // 找到索引
1168 int index = it->second;
1169 if (index == -1) {
1170 return;
1171 }
1172
1173 // 获取行人
1174 dtCrowdAgent *agent;
1175 {
1176 // 关键部分,强制单线程运行这里
1177 std::lock_guard<std::mutex> lock(_mutex);
1178 agent = _crowd->getEditableAgent(index);
1179 }
1180
1181 // 标记为暂停
1182 agent->paused = pause;
1183 }
1184
1185 bool Navigation::HasVehicleNear(ActorId id, float distance, carla::geom::Location direction) {
1186 // 获取内部索引(行人或者车辆)
1187 auto it = _mapped_walkers_id.find(id);
1188 if (it == _mapped_walkers_id.end()) {
1189 it = _mapped_vehicles_id.find(id);
1190 if (it == _mapped_vehicles_id.end()) {
1191 return false;
1192 }
1193 }
1194
1195 float dir[3] = { direction.x, direction.z, direction.y };
1196 bool result;
1197 {
1198 // 关键部分,强制单线程运行这里
1199 std::lock_guard<std::mutex> lock(_mutex);
1200 result = _crowd->hasVehicleNear(it->second, distance * distance, dir, false);
1201 }
1202 return result;
1203 }
1204
1205 /// 让代理查看某个位置
1207 // 获取内部索引(行人或车辆)
1208 auto it = _mapped_walkers_id.find(id);
1209 if (it == _mapped_walkers_id.end()) {
1210 it = _mapped_vehicles_id.find(id);
1211 if (it == _mapped_vehicles_id.end()) {
1212 return false;
1213 }
1214 }
1215
1216 dtCrowdAgent *agent;
1217 {
1218 // 关键部分,强制单线程运行这里
1219 std::lock_guard<std::mutex> lock(_mutex);
1220 agent = _crowd->getEditableAgent(it->second);
1221 }
1222
1223 // 获取位置
1224 float x = (location.x - agent->npos[0]) * 0.0001f;
1225 float y = (location.y - agent->npos[2]) * 0.0001f;
1226 float z = (location.z - agent->npos[1]) * 0.0001f;
1227
1228 // 设置其速度
1229 agent->vel[0] = x;
1230 agent->vel[2] = y;
1231 agent->vel[1] = z;
1232 agent->nvel[0] = x;
1233 agent->nvel[2] = y;
1234 agent->nvel[1] = z;
1235 agent->dvel[0] = x;
1236 agent->dvel[2] = y;
1237 agent->dvel[1] = z;
1238
1239 return true;
1240 }
1241
1242 bool Navigation::IsWalkerAlive(ActorId id, bool &alive) {
1243 // 检查是否所有都就绪
1244 if (!_ready) {
1245 return false;
1246 }
1247
1248 DEBUG_ASSERT(_crowd != nullptr);
1249
1250 // 获取内部索引
1251 auto it = _mapped_walkers_id.find(id);
1252 if (it == _mapped_walkers_id.end()) {
1253 return false;
1254 }
1255
1256 // 找到索引
1257 int index = it->second;
1258 if (index == -1) {
1259 return false;
1260 }
1261
1262 // 获取行人
1263 const dtCrowdAgent *agent;
1264 {
1265 // 关键部分,强制单线程运行这里
1266 std::lock_guard<std::mutex> lock(_mutex);
1267 agent = _crowd->getAgent(index);
1268 }
1269
1270 // 标记
1271 alive = !agent->dead;
1272
1273 return true;
1274 }
1275
1276} // namespace nav
1277} // namespace carla
auto end() const noexcept
#define DEBUG_ASSERT(predicate)
Definition Debug.h:68
double min(double v1, double v2)
返回两个数中的较小值
Definition Simplify.h:591
表示某一帧的所有参与者的状态
const auto & GetTimestamp() const
Vector3D extent
边界框的半尺寸(本地坐标系下,表示在每个轴方向上的半宽、半高和半深)
float SquaredLength() const
bool SetWalkerMaxSpeed(ActorId id, float max_speed)
设置新的最大速度
void UpdateCrowd(const client::detail::EpisodeState &state)
更新人群中的所有步行者
bool GetPath(carla::geom::Location from, carla::geom::Location to, dtQueryFilter *filter, std::vector< carla::geom::Location > &path, std::vector< unsigned char > &area)
返回从一个位置到另一个位置的路径点
void SetAgentFilter(int agent_index, int filter_index)
为代理分配过滤索引
std::unordered_map< ActorId, int > _mapped_vehicles_id
Definition Navigation.h:198
std::unordered_map< ActorId, int > _mapped_walkers_id
mapping Id
Definition Navigation.h:197
bool RemoveAgent(ActorId id)
移除代理
std::weak_ptr< carla::client::detail::Simulator > _simulator
Definition Navigation.h:210
bool GetWalkerPosition(ActorId id, carla::geom::Location &location)
获取行人的当前位置
float GetWalkerSpeed(ActorId id)
获取步行人速度
bool Load(const std::string &filename)
从磁盘中加载导航数据
bool SetWalkerTarget(ActorId id, carla::geom::Location to)
设置新的目标点以通过有事件的路线
void SetSeed(unsigned int seed)
设置随机数种子
dtNavMesh * _nav_mesh
网格
Definition Navigation.h:192
bool UpdateVehicles(std::vector< VehicleCollisionInfo > vehicles)
在人群中添加/更新/删除车辆
std::unordered_map< int, ActorId > _mapped_by_index
Definition Navigation.h:200
bool SetWalkerDirectTarget(ActorId id, carla::geom::Location to)
bool SetWalkerLookAt(ActorId id, carla::geom::Location location)
让代理查看某个位置
void PauseAgent(ActorId id, bool pause)
将人群中的代理设置为暂停
bool HasVehicleNear(ActorId id, float distance, carla::geom::Location direction)
如果代理在附近有车辆(作为邻居),则返回
bool GetWalkerTransform(ActorId id, carla::geom::Transform &trans)
获取步行人当前变换
bool GetRandomLocation(carla::geom::Location &location, dtQueryFilter *filter=nullptr) const
获取导航的随机位置
bool IsWalkerAlive(ActorId id, bool &alive)
如果行人代理被车辆撞死,则返回
WalkerManager _walker_manager
行人管理器负责带事件的路线规划
Definition Navigation.h:208
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)
设置行人代理在路径跟随过程中穿过马路的概率
std::unordered_map< ActorId, float > _yaw_walkers
存储上一个节拍的行人偏航角
Definition Navigation.h:202
dtCrowd * _crowd
crowd
Definition Navigation.h:195
bool AddWalker(ActorId id, carla::geom::Location from)
创建新的行人
std::vector< uint8_t > _binary_mesh
Definition Navigation.h:189
bool SetWalkerDirectTargetIndex(int index, carla::geom::Location to)
void SetSimulator(std::weak_ptr< carla::client::detail::Simulator > simulator)
引用模拟器来访问API函数
dtNavMeshQuery * _nav_query
Definition Navigation.h:193
void CreateCrowd(void)
创建人群对象
bool AddOrUpdateVehicle(VehicleCollisionInfo &vehicle)
在人群中创造一辆新的车辆,让行人避开
std::unordered_map< int, carla::geom::Vector3D > _walkers_blocked_position
每隔一段时间保存每个参与者的位置,并检查是否有参与者被阻挡
Definition Navigation.h:204
bool RemoveWalker(ActorId id)
void SetSimulator(std::weak_ptr< carla::client::detail::Simulator > simulator)
bool Update(double delta)
void SetNav(Navigation *nav)
bool SetWalkerRoute(ActorId id)
static void log(Args &&... args)
Definition Logging.h:61
@ 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:51
@ CARLA_AREA_ROAD
Definition Navigation.h:50
static const float AREA_ROAD_COST
static float frand()
@ CARLA_TYPE_WALKABLE
Definition Navigation.h:71
@ CARLA_TYPE_SIDEWALK
Definition Navigation.h:59
@ CARLA_TYPE_NONE
Definition Navigation.h:57
@ CARLA_TYPE_ROAD
Definition Navigation.h:63
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
CARLA模拟器的主命名空间。
Definition Carla.cpp:139
rpc::ActorId ActorId
Definition ActorId.h:26
向人群发送有关车辆的信息的结构体
Definition Navigation.h:77
carla::geom::BoundingBox bounding
Definition Navigation.h:80
carla::geom::Transform transform
Definition Navigation.h:79