CARLA 执行
把生成的路网与场景真正跑进 CARLA:加载 .xodr 建成可驾驶世界、
播放 .xosc 驱动车辆、并截图。
1. 工具参数
1.1 run_road_in_carla
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
layout |
string | straight |
路网布局 |
params_json |
string | {} |
覆盖默认参数 |
vehicle_count |
int | 5 | 布景车辆数 |
capture |
bool | True | 是否截图 |
out_dir |
string | llm/output/carla/shots/<layout> |
截图目录 |
host |
string | 127.0.0.1 |
CARLA 地址 |
port |
int | 2000 | CARLA 端口 |
1.2 run_scenario_in_carla
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
template |
string | lead_brake |
场景模板(与 xosc_path 二选一) |
xosc_path |
string | 空 | 直接指定 .xosc 文件 |
xodr_layout |
string | straight |
承载场景的路网 |
duration |
float | 0 | 播放时长;0 表示用场景自身 StopTrigger |
capture_times |
string | 2,5 |
截图时刻,逗号分隔 |
out_dir |
string | llm/output/xosc_run/shots/<template> |
截图目录 |
map_name |
string | 空 | 用内置地图承载(如 Town03),填了就忽略 xodr_layout;红绿灯场景必须用内置地图 |
1.3 list_carla_maps
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
host / port |
string / int | 127.0.0.1 / 2000 |
CARLA 地址 |
返回服务端版本、当前地图、可用地图列表。
1.4 run_traffic_light_demo
在含红绿灯的内置地图上演示信号灯条件与信号灯动作:挑一盏灯,沿来车方向后退
约 35m 布设自车,先冻结为红灯,到 red_hold 后切绿,自车按
TrafficSignalCondition(green) 起步。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
map_name |
string | Town03 |
内置地图(需含红绿灯) |
red_hold |
float | 4.0 | 红灯保持时长(秒) |
duration |
float | 16.0 | 总时长 |
capture_times |
string | 1,3,6,10 |
截图时刻 |
out_dir |
string | llm/output/xosc_run/shots/traffic_light |
截图目录 |
2. 对话示例
CARLA 连上了吗
把十字路口路网加载进 CARLA 并截图
在 CARLA 里播放 cut_in 场景,第 2 秒和第 5 秒各截一张图
把 wrong_way 场景跑 6 秒看看效果
3. 代码示例
import carla_runner as CR
from scenario_templates import build
from osc_builder import write_scenario
from xosc_player import parse_xosc, play
# 1. 连接并加载路网
client = CR.connect()
world = CR.load_xodr_world(client, "output/straight.xodr")
CR.clear_actors(world)
# 2. 准备场景
spec = build("cut_in", seed=1)
write_scenario(spec, "output/cut_in.xosc")
sc = parse_xosc("output/cut_in.xosc")
# 3. 播放并截图
res = play(world, sc, duration=8.0, capture_at=[2.0, 5.0],
out_dir="output/shots")
print(res["events_fired"], "/", res["events_total"])
4. 路网加载流程
load_xodr_world() 会先把文件内容读出来,检查 <planView/> 是否有几何,
再交给 Client.generate_opendrive_world()。加载耗时约 2 秒。
5. 播放器支持范围
5.1 支持
| 类型 | 条件/动作 | 说明 |
|---|---|---|
| 实体 | Vehicle / Pedestrian |
|
| 初始化 | TeleportAction |
LanePosition / WorldPosition |
| 速度动作 | SpeedAction |
step 与 linear 动力学 |
| 跟驰 | LongitudinalDistanceAction |
IDM 跟驰,按净距与相对速度求加速度 |
| 变道 | LaneChangeAction |
纯追踪转向 + 横向加速度 3 m/s² 限幅 |
| 横向偏移 | LaneOffsetAction |
|
| 横向间距 | LateralDistanceAction |
保持与参照实体的横向间距 |
| 相对速度 | RelativeSpeedAction |
delta(参照速度 + 值)或 factor(参照速度 × 值) |
| 轨迹跟随 | FollowTrajectoryAction |
折线轨迹 + 时间戳,纯追踪 + 前瞻 |
| 时间触发 | SimulationTimeCondition |
|
| 时距触发 | TimeHeadwayCondition |
间距 / 自身车速 |
| 距离触发 | DistanceCondition |
到指定位置 |
| 速度触发 | SpeedCondition |
|
| 静止触发 | StandStillCondition |
|
| 到达触发 | ReachPositionCondition |
按 tolerance |
| 相对速度触发 | RelativeSpeedCondition |
自身速度 − 参照实体速度 |
| TTC 触发 | TimeToCollisionCondition |
间距 / 接近速度 |
| 碰撞触发 | CollisionCondition |
包围球近似,中心距 ≤ 2.6 m |
| 加速度触发 | AccelerationCondition |
自身加速度模长 |
| 驶出路网触发 | OffroadCondition |
连续驶出 duration 秒 |
| 路段末端触发 | EndOfRoadCondition |
沿车道向前探测剩余距离 |
| 累计里程触发 | TraveledDistanceCondition |
按帧累计行驶里程 |
| 相对距离触发 | RelativeDistanceCondition |
与参照实体的直线距离 |
| 相对角度触发 | RelativeAngleCondition |
航向夹角(需 OSC 1.3) |
| 信号灯触发 | TrafficSignalCondition |
前方最近红绿灯的实际相位 |
| 信号灯动作 | TrafficSignalControllerAction |
冻结并切换相位 |
边沿检测支持 rising / falling / risingOrFalling / none 四种 ConditionEdge。
触发结构按 esmini 语义求值:
- 多个
ConditionGroup之间 OR,组内多个Condition之间 AND - 每个
Condition可带delay,需连续成立 N 秒才触发 TriggeringEntities决定条件求值主体(未声明时回落到ManeuverGroup的 Actor)Story / Act / Sequence全层级遍历;一个ManeuverGroup的多个Actor各展开一份事件<ParameterDeclarations>的$name/${name}在解析前静态替换StopTrigger与StartTrigger同一套语义,满足即提前结束SpeedActionDynamics支持step/linear/cubic/sinusoidal,dynamicsDimension支持time与rateLongitudinalDistanceAction的maxAcceleration/maxDeceleration作为 IDM 的 / ,输出加速度再按上限夹一次
5.2 不支持
以下会记入 unsupported 并明确返回,不会静默跳过:
| 类别 | 项目 |
|---|---|
| 条件 | ParameterCondition、TimeOfDayCondition、UserDefinedValueCondition |
| 结构 | Story 分支、Catalog、EntitySelection、运行期 ParameterAssignment |
6. 返回结果
run_scenario_in_carla 返回执行统计:
✅ OpenSCENARIO 场景已在 CARLA 中播放
场景:lead_brake.xosc
实体 3 个,成功布景 3 个
时长 6.00s(120 帧)
事件 4 个,已触发 3 个
已触发的动作:
t=0.00s ego ego_longitudinal_distance_ev follow=15.00
t=0.05s lead lead_speed_ev speed=13.00
t=2.05s lead lead_speed_ev speed=0.00
未执行(超出播放器范围):
- 事件 ego_standstill_ev 的条件 StandStillCondition 未满足
截图:
- output/shots/t02.00.png
- output/shots/t04.00.png
若场景配置了 StopTrigger,摘要末尾会多一行实际运行时长与结束原因,
结果 JSON 对应 ended_at 与 stop_reason(duration / stop_trigger)两个字段。
7. 12 个模板的实测结果
以下是 python llm/tools/run_regression.py --carla --duration 5 的实测输出
(自建 straight 路网,每个模板跑 5 秒):
| 模板 | 实体 | 触发事件 | 未支持项 |
|---|---|---|---|
lead_stationary |
2 | 1/1 | 0 |
close_follow |
2 | 1/1 | 0 |
wrong_way |
2 | 2/2 | 0 |
crossing_hazard |
2 | 2/2 | 0 |
junction_light |
3 | 3/3 | 0 |
lead_brake |
3 | 3/4 | 0 |
low_overlap |
3 | 4/4 | 0 |
unprotected_turn |
3 | 3/4 | 0 |
evasive_swerve |
3 | 2/2 | 0 |
overtake |
3 | 2/3 | 0 |
cut_in |
4 | 4/5 | 0 |
signal_phase |
2 | 2/4 | 0(需内置地图) |
lead_brake / cut_in / unprotected_turn / overtake 各有一个事件未触发,
是条件本身未满足(前车没在时限内完全静止 / 时距没降到阈值 / 5 秒内没走完
变道),不是播放器缺陷;--duration 拉长即可触发。
signal_phase 依赖地图自带的红绿灯,自建路网里没有,离线编译正常、实跑请用
run_traffic_light_demo(内置地图):
2026-11 红绿灯相位演示:Town03,红灯 4 秒后切绿,自车起步
效果见效果展示。
8. 注意事项
| 现象 | 原因 | 处理 |
|---|---|---|
| 加载一直超时 | .xodr 没有几何 |
检查 inspect_road() 的 valid |
_episode != nullptr 断言 |
一个进程内连续切世界 | 每种布局跑独立进程 |
| 截图是空路 | 相机复用了旧帧 | 每次截图重新创建相机 |