AI-深度学习

嵌入式视觉模型进阶 17:目标跟随:从轨迹到云台控制接口

展开合集目录
  1. 嵌入式视觉模型进阶 01:怎样读懂一个实际模型
  2. 嵌入式视觉模型进阶 02:卷积进阶:分组、深度、逐点与空洞卷积
  3. 嵌入式视觉模型进阶 03:MobileNet:深度可分离卷积与倒残差
  4. 嵌入式视觉模型进阶 04:通道注意力与 MobileNetV3
  5. 嵌入式视觉模型进阶 05:ShuffleNet:通道拆分与重排
  6. 嵌入式视觉模型进阶 06:结构重参数化:训练分支怎样合为一个卷积
  7. 嵌入式视觉模型进阶 07:Backbone、Neck、Head 与多尺度特征
  8. 嵌入式视觉模型进阶 08:FPN 与 PAN:怎样融合不同尺度的信息
  9. 嵌入式视觉模型进阶 09:检测头:分类、位置与置信度
  10. 嵌入式视觉模型进阶 10:检测训练:标签分配与损失计算
  11. 嵌入式视觉模型进阶 11:完整 YOLOv8 推理:从图片到原图目标框
  12. 嵌入式视觉模型进阶 12:训练自己的检测器与错误分析
  13. 嵌入式视觉模型进阶 13:检测器导出对照与其他结构路线
  14. 嵌入式视觉模型进阶 14:跟踪基础:运动预测、匹配与轨迹生命周期
  15. 嵌入式视觉模型进阶 15:ByteTrack 思路:用低分框恢复已有轨迹
  16. 嵌入式视觉模型进阶 16:外观特征与 ReID:怎样比较两个目标
  17. 嵌入式视觉模型进阶 17:目标跟随:从轨迹到云台控制接口
  18. 嵌入式视觉模型进阶 18:视频系统:队列、时间戳与异步流水线
  19. 嵌入式视觉模型进阶 19:人脸处理流程:检测、关键点与对齐
  20. 嵌入式视觉模型进阶 20:特征识别:人脸向量、相似度与阈值
  21. 嵌入式视觉模型进阶 21:人体关键点与姿态估计
  22. 嵌入式视觉模型进阶 22:OCR 检测:从文字区域到矫正图片
  23. 嵌入式视觉模型进阶 23:OCR 识别:序列模型与 CTC
  24. 嵌入式视觉模型进阶 24:完整 OCR 流程与识别错误分析
  25. 嵌入式视觉模型进阶 25:轻量语义分割与实例分割
  26. 嵌入式视觉模型进阶 26:工业异常检测:缺陷样本少时怎么办
  27. 嵌入式视觉模型进阶 27:深度估计与图像恢复:两个专题入口
  28. 嵌入式视觉模型进阶 28:面向 NPU 的计算图与算子兼容
  29. 嵌入式视觉模型进阶 29:量化、蒸馏与剪枝的实际取舍
  30. 嵌入式视觉模型进阶 30:综合项目:检测、跟踪与云台跟随验收
嵌入式视觉模型进阶 17:目标跟随:从轨迹到云台控制接口的封面

第 17 / 30 课。 前置:上一课。本篇的运行范围以实验说明和验证记录为准,构造样例不代表真实任务精度或板端性能。

先定义控制的物理意义

图像中心偏差是像素量,不是电机步数。本课把横向偏差归一化到约 [-1,1],输出归一化角速度意图。真实系统还需标定视场角、方向、减速比、步进细分和机械限位,再由驱动层转换。不能把本课数值直接写进电机寄存器。

最小控制使用比例项 u=Kp×e。误差在死区内时目标速度为零,外部再做速度和加速度限幅。先把 P 控制与延迟关系看明白,再考虑积分或微分;积分饱和与导数噪声不能靠堆参数解决。

目标选择不能每帧重来

本实现首次选择靠近画面中心的可见轨迹,然后锁定 ID。目标丢失时停止,不立即切换到其他人;重新选择需要显式 release。这样能区分“保持当前目标”与“自动挑选新目标”两种产品行为。

未匹配的预测框不产生控制命令。实际可允许短暂预测跟随,但必须明确最长时间和停止规则。本课采用更容易验证的观测缺失即停止策略。

时间戳与停止优先级

控制要看结果对应的采集时间。处理结束得很快但输入已排队一秒,仍然是过期结果。超过 timeout 时立即输出零速度,停止路径优先于普通加速度限幅;驱动如何实现机械安全减速应由实际控制层约定。

练习与硬件衔接

改变 Kp、死区和时间步,检查速度和相邻命令变化。模拟输入停顿,确认不会持续使用最后一条非零命令。进入海思云台系列时,先在电机禁能状态核对方向,再执行低速、小角度验证。

交付目标切换规则、单位说明、超时停止日志及机械边界。框跟得很稳不表示控制稳定,视频延迟与云台运动会构成反馈回路。

配套实验与运行记录

实验:目标跟随:从轨迹到云台控制接口

查看完整代码:main.py
"""实现目标锁定、死区、限速和失效停止,分离视觉输出与电机驱动。"""

from controller import Controller


def row(x, ident=1, matched=True):
    return {"id": ident, "box": [x, 0, x + 20, 20], "matched": matched}


def main():
    controller = Controller()
    commands = []
    for x in [70, 65, 60, 45]:
        out = controller.step([row(x)], 100, 0.05, 0.02)
        commands.append(out["speed"])
        print(out)
    assert all(abs(v) <= 0.6 for v in commands)
    assert all(abs(a - b) <= 0.100001 for a, b in zip([0] + commands, commands))
    stopped = controller.step([row(70)], 100, 0.05, 0.3)
    assert stopped["speed"] == 0
    lost = controller.step([row(70, 2)], 100, 0.05, 0.02)
    assert lost["speed"] == 0 and lost["target_id"] == 1
    controller.release()
    assert controller.step([row(70, 2)], 100, 0.05, 0.02)["target_id"] == 2
    print("stale stop, identity lock and explicit reacquisition passed")


if __name__ == "__main__":
    main()
查看完整代码:controller.py
"""输出归一化角速度意图,不直接驱动电机。"""

import math


class Controller:
    def __init__(
        self, kp=1.2, deadzone=0.05, max_speed=0.6, max_accel=2.0, timeout=0.2
    ):
        self.kp = kp
        self.deadzone = deadzone
        self.max_speed = max_speed
        self.max_accel = max_accel
        self.timeout = timeout
        self.previous = 0.0
        self.target = None

    def step(self, rows, width, dt, age):
        if (
            width <= 0
            or dt <= 0
            or not all(math.isfinite(v) for v in [width, dt, age])
            or age < 0
        ):
            raise ValueError("invalid timing or dimensions")
        visible = [r for r in rows if r["matched"]]
        chosen = next((r for r in visible if r["id"] == self.target), None)
        if chosen is None and self.target is None and visible:
            chosen = min(
                visible, key=lambda r: abs((r["box"][0] + r["box"][2]) / 2 - width / 2)
            )
            self.target = chosen["id"]
        if age > self.timeout or chosen is None:
            self.previous = 0.0
            return {"target_id": self.target, "speed": 0.0, "reason": "stale_or_lost"}
        center = (chosen["box"][0] + chosen["box"][2]) / 2
        error = (center - width / 2) / (width / 2)
        desired = (
            0.0
            if abs(error) <= self.deadzone
            else max(-self.max_speed, min(self.max_speed, self.kp * error))
        )
        delta = self.max_accel * dt
        speed = max(self.previous - delta, min(self.previous + delta, desired))
        self.previous = speed
        return {"target_id": self.target, "speed": speed, "reason": "tracking"}

    def release(self):
        self.target = None
        self.previous = 0.0
下载代码

在项目根目录执行;下载包解压后,在解压目录执行 python3 main.py。

cd 'content/posts/AI-深度学习/嵌入式视觉模型进阶/17-目标跟随/code' && python3 main.py

在本篇代码目录执行 python3 main.py。依赖安装、可选入口见包内 README.md;实际运行结果见 verification.md。下载包包含本课使用的辅助模块与样例。

参考与进一步阅读

原始论文或官方文档用于核对结构、接口和适用范围。本篇代码是围绕教学目标编写的最小实验;除明确注明的完整入口外,不视为对应论文模型的完整复现。


完整进阶目录 · 入门系列 · 上一篇 · 下一篇