4. 行人与交通参与者:行人蓝图与动画控制、交通管理器配置、自定义交通流生成、行人随机行走逻辑、多智能体协同仿真

好,咱们进入第四章。这一章我把它叫做「让世界活起来」。你想想看,光有车在路上跑,那叫交通仿真。有了行人、有了复杂的交通流,这才叫城市仿真。

我个人习惯,在做自动驾驶测试时,行人的行为往往比车辆更难预测。所以这一章,咱们重点啃下行人控制和交通管理器这两个硬骨头。

4.1 行人蓝图与动画控制

CARLA 里的行人,本质上是一个「会动的模型」。它由两部分组成:蓝图(Blueprint) 和 动画控制器(Animator)。

4.1.1 获取行人蓝图

行人的蓝图 ID 通常以 walker.pedestrian.* 开头。我建议你先把所有行人蓝图列出来看看:

blueprint_library = world.get_blueprint_library()
walker_bps = blueprint_library.filter('walker.pedestrian.*')

for bp in walker_bps:
    print(bp.id)

你会看到类似 walker.pedestrian.0001、walker.pedestrian.0002 这样的 ID。每个蓝图对应不同的外观——有穿西装的、有背书包的、还有牵着狗的(嗯,狗也算行人)。

我的经验: 测试时尽量选不同外观的行人。我曾经只用一个模型跑测试,结果视觉感知模块过拟合了——只认那个穿红衣服的人。换个人就检测不到,尴尬。

4.1.2 生成行人并控制动画

生成行人的代码和生成车辆类似,但有个关键区别:行人需要控制器。

# 生成行人
walker_bp = random.choice(walker_bps)
walker_transform = random.choice(spawn_points)

walker = world.spawn_actor(walker_bp, walker_transform)

# 生成控制器
walker_controller_bp = blueprint_library.find('controller.ai.walker')
walker_controller = world.spawn_actor(walker_controller_bp, carla.Transform(), attach_to=walker)

# 启动控制器
walker_controller.start()
walker_controller.go_to_location(target_location)

这里要注意:controller.ai.walker 是一个 AI 控制器,它负责让行人走路、转向、避障。没有它,行人就是个「站桩模特」。

4.1.3 动画状态控制

行人走路是有「节奏」的。你可以通过设置速度来控制动画:

# 设置行走速度(米/秒)
walker_controller.set_max_speed(1.4)  # 正常步行速度

# 设置为跑步
walker_controller.set_max_speed(3.0)  # 跑步状态

# 停止行走
walker_controller.stop()

为什么会这样?因为 CARLA 内部会根据速度自动切换动画混合树。速度 0 是站立,0.5-1.5 是走路,超过 2.5 就变成跑步了。

避坑指南: 我曾经把行人速度设到 10 m/s,结果看到行人「鬼畜」式地原地踏步——动画跟不上物理速度了。建议行人速度不要超过 5 m/s。

4.2 交通管理器(Traffic Manager)配置

交通管理器,简称 TM。它是 CARLA 里控制车辆行为的「大脑」。说白了,TM 决定了车辆怎么变道、怎么等红灯、怎么避让行人。

4.2.1 创建与配置 TM

# 创建交通管理器
tm = client.get_trafficmanager(port=8000)

# 设置全局参数
tm.set_global_distance_to_leading_vehicle(2.5)  # 跟车距离
tm.set_synchronous_mode(True)                    # 同步模式
tm.set_random_left_lanechange_probability(0.1)   # 左变道概率
tm.set_random_right_lanechange_probability(0.1)  # 右变道概率

我个人习惯,在同步模式下使用 TM。因为这样每一帧的决策都是确定的,方便复现问题。

4.2.2 为车辆绑定 TM

# 生成车辆后,绑定 TM
vehicle = world.spawn_actor(vehicle_bp, transform)
vehicle.set_autopilot(True, tm_port=8000)

# 或者更精细的控制
tm_vehicle = tm.get_vehicle_controller(vehicle)
tm_vehicle.set_ignore_lights_percentage(0.0)     # 完全遵守红绿灯
tm_vehicle.set_ignore_signs_percentage(0.0)      # 完全遵守标志
tm_vehicle.set_ignore_walkers_percentage(0.0)    # 完全避让行人
注意: 如果你把 ignore_walkers_percentage 设为 100,车辆会直接撞向行人。这在测试碰撞检测时有用,但平时别这么干。

4.3 自定义交通流生成

光靠 TM 的随机行为不够用。很多时候我们需要自定义交通流——比如让车流在某个路口密集,或者让所有车都走同一条路线。

4.3.1 基于路线的交通流

# 定义一条路线(由一系列 waypoint 组成)
route = []
start_waypoint = world.get_map().get_waypoint(start_location)
for i in range(20):
    next_waypoints = start_waypoint.next(10.0)
    if next_waypoints:
        start_waypoint = next_waypoints[0]
        route.append(start_waypoint.transform.location)

# 让车辆沿路线行驶
vehicle.set_autopilot(True)
tm_vehicle = tm.get_vehicle_controller(vehicle)
tm_vehicle.set_path(route)

我在项目中遇到过一个问题:路线太长了,车辆走到一半就卡住。后来发现是路线点之间的间隔太大,导致车辆找不到路径。建议 相邻路线点间隔不超过 5 米。

4.3.2 密度控制

想模拟高峰期?很简单,多生成几辆车就行:

def spawn_traffic_density(density):
    """density: 0.0 ~ 1.0"""
    spawn_points = world.get_map().get_spawn_points()
    num_vehicles = int(len(spawn_points) * density)
    
    for i in range(num_vehicles):
        bp = random.choice(vehicle_bps)
        transform = random.choice(spawn_points)
        vehicle = world.try_spawn_actor(bp, transform)
        if vehicle:
            vehicle.set_autopilot(True)

密度 0.3 是正常车流,0.7 以上就开始堵车了。我测试时常用 0.5 作为基准。

4.4 行人随机行走逻辑

行人的随机行走,说白了就是「走到一个随机点,再走到下一个随机点」。但这里面有讲究。

4.4.1 基本随机行走

import random
import time

def random_walk(walker_controller, walker, world):
    while True:
        # 在行人周围 20 米范围内选一个随机点
        current_loc = walker.get_location()
        target_loc = carla.Location(
            x=current_loc.x + random.uniform(-20, 20),
            y=current_loc.y + random.uniform(-20, 20),
            z=current_loc.z
        )
        
        # 让行人走过去
        walker_controller.go_to_location(target_loc)
        walker_controller.set_max_speed(random.uniform(0.5, 2.0))
        
        # 等待行人到达(或超时)
        time.sleep(random.uniform(5, 15))

嗯,这里要注意:不要选到马路中间的点。行人走到路中间被车撞,虽然真实,但测试场景就乱了。

4.4.2 改进版:基于人行道的行走

def safe_random_walk(walker_controller, walker, world):
    map = world.get_map()
    while True:
        current_loc = walker.get_location()
        # 获取最近的人行道 waypoint
        waypoint = map.get_waypoint(current_loc, project_to_road=False, lane_type=carla.LaneType.Sidewalk)
        
        if waypoint:
            # 在人行道上随机走
            for _ in range(5):
                next_wp = random.choice(waypoint.next(2.0))
                if next_wp:
                    waypoint = next_wp
            target_loc = waypoint.transform.location
        else:
            # 不在人行道上?那就原地待着
            target_loc = current_loc
        
        walker_controller.go_to_location(target_loc)
        time.sleep(random.uniform(3, 8))
我的经验: 用 project_to_road=False 可以确保 waypoint 在人行道上。这个参数我当初找了好久才找到。

4.5 多智能体协同仿真

多智能体,就是让多个行人、多辆车之间产生交互。比如:行人过马路,车辆停下来让行。

4.5.1 行人-车辆交互

def pedestrian_crossing_scenario(world, tm):
    # 生成一个行人,准备过马路
    walker = spawn_pedestrian_at_sidewalk(world)
    walker_controller = spawn_walker_controller(world, walker)
    
    # 生成一辆车,从远处驶来
    vehicle = spawn_vehicle_on_road(world)
    vehicle.set_autopilot(True)
    
    # 让行人走到马路对面
    cross_point = carla.Location(x=walker.get_location().x + 30, y=walker.get_location().y, z=0.5)
    walker_controller.go_to_location(cross_point)
    
    # TM 会自动处理车辆避让行人
    # 但我们可以手动调整参数
    tm_vehicle = tm.get_vehicle_controller(vehicle)
    tm_vehicle.set_distance_to_leading_vehicle(5.0)  # 增大跟车距离,给行人更多空间

为什么会自动避让?因为 TM 默认开启了 ignore_walkers_percentage=0,车辆会检测前方行人并减速。

4.5.2 多行人协同

有时候需要模拟一群人同时过马路:

def group_crossing(world, num_pedestrians=5):
    pedestrians = []
    controllers = []
    
    # 生成一群行人
    for i in range(num_pedestrians):
        walker, controller = spawn_pedestrian_with_controller(world)
        pedestrians.append(walker)
        controllers.append(controller)
    
    # 让他们同时走向同一个目标
    target = carla.Location(x=50, y=30, z=0.5)
    for controller in controllers:
        controller.go_to_location(target)
        controller.set_max_speed(1.2)  # 统一速度,保持队形
    
    return pedestrians, controllers
避坑指南: 我曾经让 20 个行人同时走向同一个点,结果他们挤在一起「卡住」了。原因是 CARLA 的行人避障算法在密集人群下会死锁。建议 每个行人目标点稍微偏移一点,比如加个随机偏移量。

4.6 本章知识体系

下面这张图总结了本章的核心逻辑:

第四章:行人与交通参与者 - 知识体系 交通参与者仿真 行人蓝图与动画 • 蓝图过滤:walker.pedestrian.* • AI控制器:controller.ai.walker • 速度控制:0.5~3.0 m/s • 动画状态自动切换 交通管理器(TM) • 跟车距离、变道概率 • 红绿灯/标志/行人忽略率 • 同步/异步模式 • 路线绑定:set_path() 自定义交通流 • 路线点间隔 ≤5m • 密度控制 0.3~0.7 • 高峰期模拟 • 特定路线生成 随机行走逻辑 • 随机目标点生成 • 人行道约束 • 速度随机化 • 超时机制 多智能体协同 • 行人-车辆交互 • 群体过马路 • 避障死锁避免 • 目标点偏移策略 目标:让仿真世界「活」起来

这张图把本章的五个核心模块串起来了。你从中间开始看——交通参与者仿真,然后向四周发散。每个模块都有对应的代码实现和参数调优技巧。

好了,这一章的内容就到这里。记住:行人控制的关键在控制器,交通流的关键在 TM 参数,多智能体的关键在交互逻辑。把这些吃透了,你的仿真场景就能以假乱真。

最后说一句: 我刚开始做行人仿真时,总觉得「不就是让小人走路吗」。直到有一次,行人突然横穿马路,我的自动驾驶算法直接懵了——它从来没训练过这种场景。从那以后,我每次测试都会加上至少 10 个随机行走的行人。你永远不知道真实世界会给你什么惊喜。

可可精品资料库