CARLA 作业综合整合与性能评价

对应课程作业五:(其他) 把前四份作业统一到一个入口,并给出可复现的量化性能评价。

1. 概述与目标

前四份作业各自是独立功能包,本模块提供两件事:

  1. 统一调度:一个入口拉起任意子作业,参数原样透传。
  2. 性能评价:真实训练并回放各模块,输出可复现的量化指标表与对比图。

代码位于 src/ground/carla_benchmark_suite/。

1.1 被整合的四个模块

target 功能包 对应任务 算法性质
control carla_keyboard_control 任务(1) 物理仿真与键盘运动控制 直接构造控制量
perception carla_perception_control 任务(2) 传感器感知与运动控制 感知 NN + 控制 NN
navigation carla_mapping_navigation 任务(3) 建图与导航(SLAM 同步仿真) 规划 NN + 占用栅格
end_to_end carla_end_to_end_nn 任务(4) 端到端模型 端到端 CNN

1.2 与已有示例的区别

对比项 已有「自动驾驶演示」(ad_demo) 本拓展模块
技术路线 roslaunch carla_ad_demo(依赖 ros-bridge 与 scenario runner) CARLA Python API 直连 + 统一调度入口
是否依赖 ros-bridge 必须编译并运行 ros-bridge 不需要,仅需 carla Python 客户端
是否依赖 scenario runner 需要,且必须设 SCENARIO_RUNNER_PATH 不需要
功能范围 单次演示(随机路线 / 场景执行) 统一调度 4 个子作业 + 量化性能评价
性能指标 无(只有运行日志) 真实测量的精度 / 时延 / 平滑度 / 覆盖率指标表
指标可复现性 — 离线可复现:--benchmark 无需 CARLA 服务端
无 CARLA / 无图形界面时 无法运行 --benchmark 与 --list 均可离线运行

1.3 与仓库中其它模块的区分

其它模块各自实现一个具体算法;本模块不实现新算法,只做两件事: 把四个功能包统一到一个入口调度,以及对它们做真实测量与横向对比。 它是唯一一个会从其它功能包导入代码并实际运行的模块。

2. 计算原理

2.1 性能评价指标定义

轨迹跟踪横向误差 RMSE(作业二):

转向平滑度 AoS(Amount of Steering):相邻转向指令的平均绝对变化量,越小越平滑:

转向饱和比例:转向被打到边界 的比例,过高说明控制裕度不足:

建图覆盖率:概率明显偏离 0.5(即已观测)的格子占比:

端到端回归指标(作业四):

推理时延:单步前向的平均耗时与 P95,反映实时性:

2.2 评价方法

评测不依赖随机数造数,而是真实执行:

--benchmark:
  perception : 合成数据集 → 训练感知NN与控制NN → 回放轨迹 → 量测横向误差
  navigation : 合成数据集 → 训练规划NN → 激光雷达合成帧建图 + NN导航 → 量测覆盖率与导航误差
  end_to_end : 合成道路图像 → 训练CNN → 量测MAE/相关/方向一致率/单帧时延
  → 汇总指标表 → 导出 report.json 与对比图

为什么不能用随机数造指标

早期版本的性能评价用 np.random.seed(0) 生成速度、转向与误差序列, 再"计算"出指标。这样的数字与算法毫无关系,无论模块是否正常都会输出 "好看"的结果,完全起不到评价作用。本模块改为真实训练与回放,指标可复现、可验证。

2.3 指标量纲差异的处理

各指标量纲差异极大(MSE 约 、准确率约 、占据格数约 ), 在同一张条形图上直接对比会导致小数值指标完全看不见。

本模块的对比图按组内最大值归一化条长,左侧用位图字体标注指标名, 在条形右侧用点阵绘制真实数值, 保证既能直观比较、又能读到准确数字。

3. 算法流程

--list       列出四个模块及就绪状态(磁盘上能否找到其 main.py)
--benchmark  逐项真实评测 → 汇总表 → 导出 JSON 与对比图
--target X   定位子包 main.py → subprocess 启动 → 参数原样透传
             ("--" 之后的参数不做解析,直接交给子进程)
ROS 节点     读取 report.json 或现场评测 → 周期性发布指标到话题

4. 源码解析

4.1 main.py — 主入口

函数 作用
MODULES 四个子模块的登记表(功能包名、任务、说明)
_module_main_path() 定位子包 main.py;未知模块名或文件缺失时返回 None
_load_sibling_module() 加载兄弟包的 main.py,并把其所在目录加入 sys.path 以支持包内导入
compute_metrics() 由原始序列计算全部指标(RMSE / AoS / 饱和率 / 时延 / 回归指标)
bench_perception() 作业二基准:训练两个 NN + 轨迹回放
bench_navigation() 作业三基准:训练规划 NN + 建图 + 导航
bench_end_to_end() 作业四基准:训练 CNN + 量测精度与时延
run_benchmark() 评测套件主流程与指标表汇总
render_metric_bars() 指标对比图(组内归一化 + 点阵数值标注)
run_module() 以子进程调度子模块
list_modules() 模块总览

4.2 benchmark_node.py — ROS 2 节点

两种工作方式:按 target 参数包含对应子功能包的 launch(调度模式), 或读取 report.json/现场评测后周期性把指标发布到 /carla/benchmark/metrics(Float32MultiArray)与 /carla/benchmark/metric_names (String,逗号分隔),便于记录到 rosbag 或由其它节点订阅。

4.3 launch/main.launch.py — ROS 2 launch

通过 OpaqueFunction 在启动时按 target 决定行为:调度模式包含子功能包自己的 launch 文件(复用其节点与参数定义,避免在本包内重复描述), 默认模式则启动指标发布节点。

5. 仿真运行步骤

5.1 支持与测试环境

组件 版本 / 说明
操作系统 Windows 10/11 原生;Ubuntu 20.04(Noetic)/ 22.04(Humble)
仿真器 CARLA 0.9.16(仅在线调度子作业时需要;--benchmark 不需要)
Python 3.10+(CARLA 0.9.16 客户端 wheel 为 cp310/cp311/cp312)
依赖 仅 numpy(各模块神经网络均为纯 numpy 实现)
ROS ROS 2 Humble(ros2 launch);Noetic 下用 main.sh 直接运行,本包不提供 catkin launch

5.2 新手路线:从已有示例到本模块

序号 做什么 出处
1 启动 CARLA 服务端 设置并连接到 Carla 模拟器 →「启动 Carla 服务器」
2 查看宿主机 IP、确认虚拟机连通 同上 →「使用 Carla 客户端启动 Ego Vehicle」
— ★ 在此切换到本模块 以下与本模块相关
3 先离线跑基准评测(无需 CARLA) 本页 5.5 节
4 再按需调度子作业 本页 5.7 节

5.3 步骤 0:环境准备

CARLA 服务端的下载安装与启动、宿主机 IP 与端口 2000 的查看等通用步骤与已有示例 完全相同,本文不重复,请参考 设置并连接到 Carla 模拟器:

需要做的事 参考位置
启动 CARLA 服务端、选择地图 设置并连接到 Carla 模拟器 →「启动 Carla 服务器」
查看宿主机 IP、填写 host 参数 同上 →「使用 Carla 客户端启动 Ego Vehicle」
连接失败、黑屏、numpy 报错排查 同上 →「常见问题」

本模块的评测环节不需要 CARLA

--list 与 --benchmark 都在本地完成,不连接 CARLA 服务端。 只有在 --target 调度需要连 CARLA 的子作业(如 navigation 的 --mode run)时才需要。

5.4 步骤 1:编译本功能包(ROS 2)

本模块的源代码位于本仓库(OpenHUTB/ros2)的 src/ground/carla_benchmark_suite/。ROS 2 要求功能包放在工作空间的 src/ 目录下, 因此先把本仓库克隆到工作空间的 src/:

mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
git clone https://github.com/OpenHUTB/ros2.git     # 换成你自己的 fork 亦可

克隆后的目录关系如下,colcon build 必须在工作空间根目录执行:

~/ros2_ws/                                   <- 工作空间根目录,colcon 在这里运行
└── src/
    └── ros2/                                <- 本仓库(git clone 得到)
        └── src/ground/
            └── carla_benchmark_suite/                       <- 本模块源代码

因此后文写的 src/ground/carla_benchmark_suite/...,实际路径是 ~/ros2_ws/src/ros2/src/ground/carla_benchmark_suite/...。编译并激活环境:

cd ~/ros2_ws
colcon build --packages-select carla_benchmark_suite --symlink-install
source install/setup.bash

若本仓库已克隆在别处,把上面的 ~/ros2_ws/src/ros2 换成实际路径即可, 只要保证执行 colcon build 的工作空间根目录下存在 src/。

若同时使用被调度/被评测的四个子功能包,一并编译:

colcon build --packages-select carla_keyboard_control carla_perception_control \
             carla_mapping_navigation carla_end_to_end_nn carla_benchmark_suite \
             --symlink-install

5.5 步骤 2:查看模块总览与运行基准评测(无需 CARLA)

python3 src/ground/carla_benchmark_suite/main.py --list
python3 src/ground/carla_benchmark_suite/main.py --benchmark \
        --save_dir ~/shots --out ~/shots/report.json

只评测其中一项(节省时间):

python3 src/ground/carla_benchmark_suite/main.py --benchmark --which end_to_end --samples 60

5.6 步骤 3:验证与 CARLA 服务端的连接(仅调度在线子作业时需要)

命令里的 192.168.8.1 是运行 CARLA 服务端的宿主机(Windows)IP: 在宿主机上执行 ipconfig,取 VMware 虚拟网卡(VMnet8)的 IPv4 地址即可 (本机该地址为 192.168.8.1,虚拟机 ens33 为 192.168.8.131,两者同网段)。 查看方式与已有示例一致,详见 设置并连接到 Carla 模拟器 →「使用 Carla 客户端启动 Ego Vehicle」。

python3 -c "import carla; c=carla.Client('192.168.8.1',2000); c.set_timeout(10); print('CONNECT OK:', c.get_world().get_map().name)"

5.7 步骤 4:调度子作业

# 作业二:离线取证(无需 CARLA)
python3 src/ground/carla_benchmark_suite/main.py --target perception -- \
        --headless --demo --save_dir ~/shots

# 作业三:在线建图 + NN 导航(--host 填宿主机 IP)
python3 src/ground/carla_benchmark_suite/main.py --target navigation -- \
        --mode run --host 192.168.8.1 --goal "20,8" --sim_time 40

# 作业四:训练端到端 CNN
python3 src/ground/carla_benchmark_suite/main.py --target end_to_end -- \
        --mode train --epochs 60

# 作业一:键盘控制(需要图形界面与 CARLA)
python3 src/ground/carla_benchmark_suite/main.py --target control -- --host 192.168.8.1

参数透传用 -- 分隔

-- 之前的参数由本模块解析,-- 之后的参数原样传给子作业。 这样即使子作业新增了自己的参数,本模块也无需改动。

5.8 步骤 5:ROS 启动

# ROS 2:发布评测指标(读取已导出的 report.json)
ros2 launch carla_benchmark_suite main.launch.py metrics_file:=$HOME/shots/report.json

# ROS 2:调度子模块(包含子包自己的 launch)
ros2 launch carla_benchmark_suite main.launch.py target:=navigation host:=192.168.8.1

# 模式 D:ROS 1 Noetic —— 用 main.sh 直接运行(不需要 ROS,也不需要 catkin 封装)
#   本包是 ament_python(format 3)包,Noetic 的 catkin 环境里没有它的 package index,
#   roslaunch 找不到该包,所以**不提供** ROS 1 launch;`--launch` 在 Noetic 下会明确报错。
#   main.sh 会自动挑 python3.10(CARLA 0.9.16 的 wheel 是 cp310+):
bash src/ground/carla_benchmark_suite/main.sh --benchmark --save_dir ~/shots
bash src/ground/carla_benchmark_suite/main.sh --target perception -- --host 192.168.8.1

一键脚本:bash main.sh --benchmark / bash main.sh --list。

5.9 运行效果

各模块指标对比图(条长按组内最大值归一化以免小数值不可见; 左侧直接标注指标名与单位,条形右侧点阵为真实数值,共 10 项):

各模块性能指标对比

动图:各模块指标逐条长出(10 帧,37 KB。条形从 0 长到实测值,最后停住并标出数值, 一眼能看出四份作业在"精度 / 误差 / 覆盖率"三个维度上的相对水平):

各模块性能指标对比动图

评测终端输出(节选,本机实测):

====================================================================
  CARLA 作业综合基准评测(真实测量,无需 CARLA 服务端)
====================================================================

---- 评测 perception:RGB+深度+激光雷达 → 感知 NN;状态 → 控制 NN;给定轨迹跟踪 ----
    steer_mean                 = 0.02592
    steer_std                  = 0.06123
    aos                        = 0.01820
    speed_mean                 = 7.03799
    lateral_rmse               = 0.21876
    lateral_max                = 1.21778
    percept_acc                = 0.97500
    percept_acc_train          = 0.98750
    control_mse                = 0.00339
    control_mse_train          = 0.00350
    holdout_n                  = 120

---- 评测 navigation:激光雷达占用栅格建图 + 神经网络规划导航 ----
    plan_mse                   = 0.00788
    reg_corr                   = 0.98865
    occupied_cells             = 1214
    known_ratio                = 0.26503
    coverage_start             = 0.02950
    coverage_final             = 0.26503
    nav_min_dist               = 1.41609
    nav_reached                = True
    latency_mean_ms            = 0.02977

---- 评测 end_to_end:相机图像 → 端到端 CNN → 转向 ----
    reg_mae                    = 0.14361
    reg_rmse                   = 0.15857
    reg_corr                   = 0.98957
    reg_sign_acc               = 0.93000
    e2e_baseline_mae           = 0.40404
    infer_ms_per_frame         = 2.23733

====================================================================
  汇总
====================================================================
  指标                                  数值
  --------------------------------------
  感知 NN 准确率(留出)                   0.9750
  控制 NN MSE(留出)                  0.00339
  横向误差 RMSE (m)                   0.2188
  规划 NN MSE                      0.00788
  建图覆盖率                           0.2650
  占据格数                              1214
  导航最近距离 (m)                      1.4161
  端到端 MAE                        0.14361
  端到端方向一致率                        0.9300
  端到端相关系数                         0.9896

指标已导出: shots/report.json
对比图已导出: shots/metric_summary.png

5.10 常见问题

Q1:--list 显示某个模块"未获取"? 说明本模块在磁盘上找不到该功能包的 main.py(路径期望为 src/ground/<功能包名>/main.py)。由于四份作业是独立功能包、独立提交的, 若某个包尚未合入当前分支就会出现这种情况。 本模块对此是优雅降级的:缺失的模块只显示"未获取",不影响其它模块的调度与评测; --benchmark 中对应评测项会记为失败但不会中断整体流程。

Q2:--benchmark 报某个评测项失败? 各评测项互相独立,某一项失败不影响其它项(结果里记为 error)。 常见原因是缺少对应功能包。可用 --which 只跑确认可用的项。

Q3:纯 numpy 评测太慢? 端到端评测的 CNN 为纯 numpy 实现(无 GPU 加速),耗时与样本数、训练轮数成正比。 可用 --samples 60 --epochs 40 缩短,或 --which 只跑需要的项。

Q4:ROS launch 调度子模块时找不到子包? 调度模式会包含子功能包自己的 main.launch.py,因此必须先编译那个子包 (见 5.4 节)。若只需发布评测指标(不调度),则不需要任何子包。

6. 性能评价

6.1 实测结果(本机实测,即 5.5 节那条 --benchmark 的默认参数)

复现命令:python3 src/ground/carla_benchmark_suite/main.py --benchmark \ --save_dir ~/shots --out ~/shots/report.json(默认 perception 150 epoch / navigation 60 epoch / end_to_end 40 epoch & 100 样本,约 2 分钟, 绝大部分花在端到端 CNN 的纯 numpy 训练上)。

四个被评测的功能包(作业一~四)都在本仓库 src/ground/ 下,干净克隆即可复现 全部 10 项指标;指标由固定随机种子决定,可逐位复现(时延类指标随机器浮动)。 感知/控制两项报的是留出集(另生成 120 个样本、不同种子、不参与训练), 训练集数值仅作对照。

模块 指标 数值
作业二 感知 感知 NN 准确率(留出集) 0.9750(训练集 0.9875)
作业二 感知 控制 NN MSE(留出集) 0.00339(训练集 0.00350)
作业二 感知 横向误差 RMSE 0.2188 m
作业二 感知 平均速度 7.0380 m/s
作业二 感知 转向 AoS(平滑度) 0.01820
作业三 建图 建图覆盖率 0.2650
作业三 建图 占据格数 1214
作业三 导航 规划 NN MSE 0.00788
作业三 导航 导航最近距离 1.4161 m(阈值 1.5 m,已到达)
作业三 导航 单步推理时延 0.0298 ms
作业四 端到端 MAE 0.14361
作业四 端到端 方向一致率 0.9300
作业四 端到端 相关系数 0.9896
作业四 端到端 零输出基线 MAE 0.40404(网络 MAE 是基线的 1/2.8)
作业四 端到端 单帧推理时延 2.8932 ms

6.2 横向对比与观察

观察 数据支撑 说明
感知/控制 NN 精度高 留出集准确率 0.9750、控制 MSE 0.00339 分层方案在合成数据上表现稳定
轨迹跟踪平滑 AoS 0.0182、饱和率 0 弯道自适应减速有效,转向无抖动
建图有效 覆盖率 0.2650、占据格 1214 6 秒左右的行驶即可覆盖约 27% 栅格
规划 NN 实时性好 单步 0.0298 ms MLP 体量小,远快于 50 ms 的仿真步长
端到端显著优于基线 MAE 0.1436 vs 基线 0.4040 网络确实学到了"图像 → 转向",而非恒输出 0
端到端推理较慢 2.89 ms/帧 纯 numpy 卷积无 GPU 加速;仍远快于 50 ms 步长

6.3 评价过程中的两个关键教训

问题 现象 处理
原版用随机数造指标 np.random.seed(0) 生成假的转向/速度/误差序列,指标与算法无关 改为真实训练 + 回放测量;指标可复现、可验证
nn_models.py 多副本漂移 作业四修了 maxpool 梯度与 tanh 两处缺陷后,评价包仍用旧副本,端到端 MAE 一度测得 36.12(正常 <0.3) 统一各包副本,并新增副本一致性回归测试,分歧即失败并列出差异文件
指标量纲差异导致图不可读 MSE 约 、占据格数约 ,同图对比时小数值完全看不见 对比图按组内最大值归一化条长,并用点阵标注真实数值
报的是训练集精度 感知/控制 NN 直接在自己的训练输入上预测,0.9875 是训练集准确率,不是泛化精度 另生成 120 个样本(不同种子、不参与训练)作留出集,汇总表只报留出集,训练集数值留作对照

6.4 结论

  • 完整性:四份作业(物理仿真与键盘控制、感知与控制 NN、建图与规划 NN、 端到端 CNN)均可由本模块统一调度,且各自满足"算法为神经网络"的硬性要求。
  • 可复现性:四个被评测功能包都在本仓库内,--benchmark 一条命令即可复现全部 10 项指标(固定随机种子),无需 CARLA 服务端,也避免了用随机数造指标的做法。
  • 可验证性:单元测试 23 项覆盖指标计算的数学正确性与副本一致性, 其中指标计算的边界情形(空输入、单元素)与副本漂移都有回归测试保护。
  • 局限:评测在合成数据上进行,用于验证算法正确性与链路可用性; 绝对数值不代表真实道路性能,实车指标需用采集的真实数据重测。