第二章:行人模型基础
好,咱们进入行人模型的世界。说实话,刚开始做自动驾驶仿真时,我总觉得行人就是个会动的障碍物。直到有一次,我做的行人突然在路中间来了个原地转圈——那动作,活像个提线木偶。嗯,从那以后我才明白,行人模型远比你想象的要复杂。
2.1 行人蓝图库
Carla 里有个挺有意思的设计——行人蓝图库。说白了,就是一堆预设好的行人模板。我个人习惯先跑一下这个命令看看都有什么:
# 列出所有行人蓝图
blueprint_library = world.get_blueprint_library()
pedestrian_bps = blueprint_library.filter('walker.pedestrian.*')
for bp in pedestrian_bps:
print(bp.id)
你会看到类似这样的输出:
walker.pedestrian.0012
walker.pedestrian.0014
walker.pedestrian.0016
walker.pedestrian.0020
walker.pedestrian.0021
walker.pedestrian.0022
walker.pedestrian.0024
walker.pedestrian.0025
walker.pedestrian.0027
walker.pedestrian.0030
walker.pedestrian.0031
walker.pedestrian.0032
walker.pedestrian.0033
walker.pedestrian.0034
walker.pedestrian.0035
walker.pedestrian.0036
walker.pedestrian.0037
walker.pedestrian.0038
walker.pedestrian.0039
walker.pedestrian.0040
walker.pedestrian.0041
walker.pedestrian.0042
walker.pedestrian.0043
walker.pedestrian.0044
walker.pedestrian.0045
walker.pedestrian.0046
walker.pedestrian.0047
walker.pedestrian.0048
walker.pedestrian.0049
walker.pedestrian.0050
每个编号对应一个不同的外观模型。我记得 Carla 早期版本只有十几个,现在已经有三十多个了。男女老少都有,高矮胖瘦各异。
2.2 行人外观与骨骼
每个行人模型背后都有一套骨骼系统。你想想看,要让行人走路自然,光有皮肤可不行,得有骨架支撑。
Carla 用的是 UE4 的骨骼动画系统。每个行人模型包含:
- 骨骼层级:从骨盆到脚趾,大概 60-80 根骨骼
- 蒙皮权重:每个顶点受哪些骨骼影响
- 形态目标:比如胖瘦、高矮的变形参数
我曾经踩过一个坑:想给行人换个衣服颜色,结果发现改的是骨骼位置。那画面,啧啧,行人直接变成了扭曲的怪物。
# 设置行人外观参数
bp = blueprint_library.find('walker.pedestrian.0020')
# 可以调整的参数
bp.set_attribute('gender', 'male') # 性别
bp.set_attribute('age', 'adult') # 年龄段
bp.set_attribute('speed', '1.4') # 行走速度(米/秒)
2.3 行人物理属性
行人的物理属性,说白了就是决定他「怎么动」的参数。我刚开始做碰撞测试时,发现行人被车撞了之后飞出去的距离总是不对。后来一查,原来是质量设得太轻了。
关键物理参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
| 质量 | 70 kg | 影响碰撞后的运动 |
| 摩擦系数 | 0.7 | 影响行走时的抓地力 |
| 弹性系数 | 0.3 | 碰撞后的反弹程度 |
| 阻尼系数 | 0.1 | 运动时的阻力 |
# 修改行人物理属性
pedestrian = world.spawn_actor(bp, spawn_point)
physics_control = pedestrian.get_physics_control()
# 调整质量
physics_control.mass = 80.0 # 改成80公斤
# 调整摩擦
physics_control.friction = 0.8
pedestrian.apply_physics_control(physics_control)
为什么会这样?因为 Carla 的物理引擎用的是 PhysX,它对这些参数很敏感。我建议你做碰撞测试时,先把质量调到 75kg 左右,这是成年人的平均体重。
2.4 行人碰撞体
碰撞体,就是行人身上用来检测碰撞的「隐形盒子」。你想想看,如果每个顶点都做碰撞检测,那计算量得多大?所以 Carla 用了简化模型。
行人碰撞体主要有三种:
- 胶囊体:像个竖着的胶囊,覆盖躯干和头部
- 球体:用于四肢末端
- 盒体:用于躯干精细碰撞
我记得有一次,我测试的行人明明被车撞到了,但碰撞检测就是没触发。查了半天,原来是碰撞体尺寸设得太小了,只覆盖了躯干,手臂伸出去的部分根本没算进去。
# 获取碰撞体信息
collision_bounds = pedestrian.bounding_box
print(f"碰撞体尺寸: {collision_bounds.extent}")
print(f"碰撞体位置: {collision_bounds.location}")
# 碰撞体可视化(调试用)
world.debug.draw_box(
box=collision_bounds,
rotation=pedestrian.get_transform().rotation,
thickness=0.1,
color=(255, 0, 0),
life_time=2.0
)
2.5 行人动画状态机
最后说说动画状态机。这东西,说白了就是控制行人「什么时候做什么动作」的规则引擎。
Carla 的行人动画状态机包含这些状态:
- Idle:站立不动,偶尔看看手机
- Walking:正常行走
- Running:奔跑
- Crossing:过马路(左右张望)
- Stumbling:绊倒
- Falling:摔倒
状态之间的切换是有条件的。比如从 Walking 切换到 Running,需要速度超过某个阈值。我曾经遇到过一个问题:行人明明在跑,但动画还是走的动作。后来发现是状态机的速度阈值设得太高了。
# 控制行人动画状态
from carla import WalkerControl
control = WalkerControl()
control.direction = Vector3D(1, 0, 0) # 前进方向
control.speed = 2.0 # 速度(米/秒)
control.jump = False # 是否跳跃
pedestrian.apply_control(control)
# 获取当前动画状态
current_state = pedestrian.get_animation_state()
print(f"当前动画: {current_state}")
嗯,行人模型这块就这些。说实话,刚开始接触时觉得挺简单的,不就是个人嘛。但真正做起来,每个细节都能让你踩坑。下一章咱们聊聊怎么让这些行人动起来,以及如何控制他们的行为。