【导航基础 1-5】第 3/25 课

🤖 第03课:动态避障

📌 动态避障概述

服务机器人运行在动态环境中——行人走动、推车移动、门开合——静态路径规划不够。动态避障需要感知-预测-规避完整能力链。

🔄 动态避障能力链

感知 → 追踪 → 预测 → 规划 → 执行 → 反馈
 │      │      │      │      │      │
激光雷达 数据关联 轨迹预测 速度选择 运动控制 安全监测
摄像头  卡尔曼滤波 线性/社交 VO/DWA 底层驱动 紧急停止

📌 动态障碍物追踪与预测

import math, random

class DynamicObstacle:
    def __init__(self, oid, x, y, vx, vy, radius=0.3):
        self.id = oid; self.x = x; self.y = y
        self.vx = vx; self.vy = vy; self.radius = radius
        self.history = [(x, y)]

    def update(self, dt=0.1):
        self.x += self.vx*dt; self.y += self.vy*dt
        self.history.append((self.x, self.y))
        if len(self.history) > 50: self.history.pop(0)

    def predict(self, steps=10, dt=0.1):
        px, py = self.x, self.y
        return [(px + self.vx*dt*i, py + self.vy*dt*i) for i in range(1, steps+1)]

class ObstacleTracker:
    def __init__(self):
        self.obstacles = {}
        self.next_id = 0

    def update(self, detections):
        for det_x, det_y, det_vx, det_vy, det_r in detections:
            best_id, best_dist = None, 1.0
            for oid, obs in self.obstacles.items():
                d = math.sqrt((obs.x-det_x)**2 + (obs.y-det_y)**2)
                if d < best_dist: best_dist = d; best_id = oid
            if best_id is not None:
                o = self.obstacles[best_id]
                o.x, o.y, o.vx, o.vy = det_x, det_y, det_vx, det_vy
            else:
                oid = self.next_id; self.next_id += 1
                self.obstacles[oid] = DynamicObstacle(oid, det_x, det_y, det_vx, det_vy, det_r)

tracker = ObstacleTracker()
obstacles = [[3.0,2.0,0.5,0.3,0.3],[7.0,4.0,-0.3,0.4,0.3],[5.0,1.0,0.0,0.6,0.4]]

print("动态障碍物追踪与预测")
print("=" * 50)
for step in range(20):
    for obs in obstacles:
        obs[0] += obs[2]*0.1; obs[1] += obs[3]*0.1
    tracker.update([tuple(d) for d in obstacles])
    if step % 5 == 0:
        print(f"\n步骤{step}:")
        for oid, obs in tracker.obstacles.items():
            pred = obs.predict(5)
            ps = ", ".join(f"({p[0]:.1f},{p[1]:.1f})" for p in pred[:3])
            print(f"  障碍物{oid}: ({obs.x:.2f},{obs.y:.2f}) 速度({obs.vx:.2f},{obs.vy:.2f}) 预测:{ps}")

print(f"\n✅ 追踪{len(tracker.obstacles)}个动态障碍物")
✅ 验证通过 动态障碍物追踪与预测 ================================================== 步骤0: 障碍物0: (3.05,2.03) 速度(0.50,0.30) 预测:(3.1,2.1), (3.1,2.1), (3.2,2.1) 障碍物1: (6.97,4.04) 速度(-0.30,0.40) 预测:(6.9,4.1), (6.9,4.1), (6.9,4.2) 障碍物2: (5.00,1.06) 速度(0.00,0.60) 预测:(5.0,1.1), (5.0,1.2), (5.0,1.2) 步骤5: 障碍物0: (3.30,2.18) 速度(0.50,0.30) 预测:(3.3,2.2), (3.4,2.2), (3.4,2.3) 障碍物1: (6.82,4.24) 速度(-0.30,0.40) 预测:(6.8,4.3), (6.8,4.3), (6.7,4.4) 障碍物2: (5.00,1.36) 速度(0.00,0.60) 预测:(5.0,1.4), (5.0,1.5), (5.0,1.5) 步骤10: 障碍物0: (3.55,2.33) 速度(0.50,0.30) 预测:(3.6,2.4), (3.6,2.4), (3.7,2.4) 障碍物1: (6.67,4.44) 速度(-0.30,0.40) 预测:(6.6,4.5), (6.6,4.5), (6.6,4.6) 障碍物2: (5.00,1.66) 速度(0.00,0.60) 预测:(5.0,1.7), (5.0,1.8), (5.0,1.8) 步骤15: 障碍物0: (3.80,2.48) 速度(0.50,0.30) 预测:(3.8,2.5), (3.9,2.5), (3.9,2.6) 障碍物1: (6.52,4.64) 速度(-0.30,0.40) 预测:(6.5,4.7), (6.5,4.7), (6.4,4.8) 障碍物2: (5.00,1.96) 速度(0.00,0.60) 预测:(5.0,2.0), (5.0,2.1), (5.0,2.1) ✅ 追踪3个动态障碍物

📌 速度障碍物法(VO)

速度障碍物法将动态障碍物映射为速度空间中的禁止锥体:

import math

class VOAvoidance:
    def __init__(self, robot_r=0.3, max_speed=1.0):
        self.robot_r = robot_r
        self.max_speed = max_speed

    def compute_safe_vel(self, rpos, rvel, goal, obstacles):
        best_vel = (0, 0); best_score = -1e9
        for vx in [i*0.1-1.0 for i in range(21)]:
            for vy in [i*0.1-1.0 for i in range(21)]:
                speed = math.sqrt(vx*vx+vy*vy)
                if speed > self.max_speed: continue
                safe = True
                for obs in obstacles:
                    dx = obs["pos"][0]-rpos[0]; dy = obs["pos"][1]-rpos[1]
                    dist = math.sqrt(dx*dx+dy*dy)
                    if dist < 0.01: continue
                    combined_r = self.robot_r + obs["radius"]
                    angle = math.atan2(dy, dx)
                    half = math.asin(min(combined_r/dist, 1.0))
                    rel_vx = obs["vel"][0]-vx; rel_vy = obs["vel"][1]-vy
                    rel_angle = math.atan2(rel_vy, rel_vx)
                    diff = abs(rel_angle - angle)
                    if diff > math.pi: diff = 2*math.pi - diff
                    if diff < half: safe = False; break
                if safe:
                    ga = math.atan2(goal[1]-rpos[1], goal[0]-rpos[0])
                    va = math.atan2(vy, vx)
                    ad = abs(ga-va)
                    if ad > math.pi: ad = 2*math.pi - ad
                    score = speed - ad*2
                    if score > best_score: best_score = score; best_vel = (vx, vy)
        return best_vel

vo = VOAvoidance()
rpos = (0.0, 0.0); goal = (10.0, 8.0)
obstacles = [
    {"pos":(3.0,2.5),"vel":(0.3,0.2),"radius":0.4},
    {"pos":(6.0,5.0),"vel":(-0.2,0.3),"radius":0.3},
    {"pos":(8.0,3.0),"vel":(0.1,-0.1),"radius":0.35},
]

print("速度障碍物法(VO)避障导航")
for step in range(80):
    for obs in obstacles:
        obs["pos"] = (obs["pos"][0]+obs["vel"][0]*0.1, obs["pos"][1]+obs["vel"][1]*0.1)
    vx, vy = vo.compute_safe_vel(rpos, (0,0), goal, obstacles)
    rpos = (rpos[0]+vx*0.1, rpos[1]+vy*0.1)
    d = math.sqrt((rpos[0]-goal[0])**2+(rpos[1]-goal[1])**2)
    if d < 0.5:
        print(f"✅ 第{step+1}步到达! ({rpos[0]:.2f},{rpos[1]:.2f})")
        break
else:
    print(f"⚠️ 80步未到达 ({rpos[0]:.2f},{rpos[1]:.2f})")
✅ 验证通过 速度障碍物法(VO)避障导航 ⚠️ 80步未到达 (5.44,4.16)

📌 社交力模型

社交力模型模拟行人运动行为,驱动力朝目标、排斥力远离障碍:

import math

class SocialForce:
    def __init__(self):
        self.A = 2.0; self.B = 0.3; self.desired_speed = 0.8; self.relax = 0.5

    def desired_force(self, pos, vel, goal):
        dx, dy = goal[0]-pos[0], goal[1]-pos[1]
        d = math.sqrt(dx*dx+dy*dy)
        if d < 0.01: return (0, 0)
        ex, ey = dx/d, dy/d
        return ((self.desired_speed*ex-vel[0])/self.relax, (self.desired_speed*ey-vel[1])/self.relax)

    def social_force(self, pi, pj, vj, ri=0.3, rj=0.3):
        dx, dy = pi[0]-pj[0], pi[1]-pj[1]
        d = math.sqrt(dx*dx+dy*dy)
        if d < 0.01: return (0, 0)
        rij = ri + rj
        nx, ny = dx/d, dy/d
        f = self.A * math.exp((rij-d)/self.B)
        if d < rij: f += 1.2*(rij-d)
        return (f*nx, f*ny)

sf = SocialForce()
robot = {"pos":[0.0,5.0], "vel":[0.0,0.0], "r":0.3}
goal = (10.0, 5.0)
peds = [{"pos":[4.0,4.5],"vel":[-0.3,0.1],"r":0.25},
        {"pos":[6.0,5.5],"vel":[0.2,-0.1],"r":0.25},
        {"pos":[8.0,4.0],"vel":[-0.1,0.3],"r":0.25}]

print("社交力模型避障")
for step in range(200):
    fd = sf.desired_force(tuple(robot["pos"]), tuple(robot["vel"]), goal)
    fsx, fsy = 0, 0
    for p in peds:
        fx, fy = sf.social_force(tuple(robot["pos"]), tuple(p["pos"]), tuple(p["vel"]), robot["r"], p["r"])
        fsx += fx; fsy += fy
    robot["vel"][0] += (fd[0]+fsx)*0.05
    robot["vel"][1] += (fd[1]+fsy)*0.05
    sp = math.sqrt(robot["vel"][0]**2+robot["vel"][1]**2)
    if sp > 1.2:
        robot["vel"][0] *= 1.2/sp; robot["vel"][1] *= 1.2/sp
    robot["pos"][0] += robot["vel"][0]*0.05
    robot["pos"][1] += robot["vel"][1]*0.05
    for p in peds:
        p["pos"][0] += p["vel"][0]*0.05; p["pos"][1] += p["vel"][1]*0.05
    if math.sqrt((robot["pos"][0]-goal[0])**2+(robot["pos"][1]-goal[1])**2) < 0.5:
        print(f"✅ 第{step+1}步到达! ({robot['pos'][0]:.2f},{robot['pos'][1]:.2f})")
        break
else:
    print(f"⚠️ 200步未到达 ({robot['pos'][0]:.2f},{robot['pos'][1]:.2f})")
✅ 验证通过 社交力模型避障 ⚠️ 200步未到达 (6.18,5.69)

📌 避障策略对比

📊 算法对比

算法类型优点缺点场景
DWA速度空间动力学约束局部最优结构化
VO/RVO速度障碍动态障碍计算量大密集人群
社交力力场行为自然参数敏感人机共存
TEB轨迹优化时间最优计算高精确导航
DRL端到端泛化强不可解释复杂场景

📌 实时避障系统设计

完整的实时避障系统需要多传感器融合分层决策

🏗️ 三层避障架构

┌────────────────────────────────────────┐
│  全局规划层 (1Hz)                       │
│  A*/NavFn → 全局最优路径               │
├────────────────────────────────────────┤
│  局部规划层 (10Hz)                      │
│  DWA/TEB → 局部轨迹优化+动态避障       │
├────────────────────────────────────────┤
│  安全防护层 (50Hz)                      │
│  碰撞检测 → 紧急制动                   │
└────────────────────────────────────────┘
💡 层级越高频率越低但视野越大,层级越低频率越高但只关注近距离安全。三层协作确保全局最优和实时安全。

📌 行人预测与意图识别

在人群密集场景中,仅靠当前状态不够,需要预测行人未来运动

📊 行人预测方法对比

方法预测时长精度计算量
恒速模型(CVM)1-2秒极小
社交力模型2-5秒
LSTM/GRU3-8秒
Transformer(Trajectron++)5-12秒极高

实际系统中通常采用CVM+社交力的轻量方案,在Jetson等边缘设备上实时运行:

⚠️ 行人预测的不确定性随时间急剧增加,超过3秒的预测仅供粗略参考,必须配合高频局部规划使用。

📌 练习

📝 练习 1

实现ORCA互惠避障算法,考虑对方也会避让。

📝 练习 2

社交力+DWA结合,用社交力修正DWA评分函数。

📝 练习 3

实现紧急停止机制:0.5秒内将碰撞时急停,设计恢复状态机。

📌 成就

🏆 本课成就

📌 实时避障系统设计

完整的实时避障系统需要多传感器融合分层决策

🏗️ 三层避障架构

┌────────────────────────────────────────┐
│  全局规划层 (1Hz)                       │
│  A*/NavFn → 全局最优路径               │
├────────────────────────────────────────┤
│  局部规划层 (10Hz)                      │
│  DWA/TEB → 局部轨迹优化+动态避障       │
├────────────────────────────────────────┤
│  安全防护层 (50Hz)                      │
│  碰撞检测 → 紧急制动                   │
└────────────────────────────────────────┘
💡 层级越高频率越低但视野越大,层级越低频率越高但只关注近距离安全。三层协作确保全局最优和实时安全。

📌 行人预测与意图识别

在人群密集场景中,仅靠当前状态不够,需要预测行人未来运动

📊 行人预测方法对比

方法预测时长精度计算量
恒速模型(CVM)1-2秒极小
社交力模型2-5秒
LSTM/GRU3-8秒
Transformer5-12秒极高
⚠️ 行人预测的不确定性随时间急剧增加,超过3秒的预测仅供粗略参考,必须配合高频局部规划使用。
◀ 上一课 📚 目录 下一课 ▶