ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

YOLOv5与Tello TT无人机目标识别追踪测距实战资源解析

YOLOv5与Tello TT无人机目标识别追踪测距实战资源解析 简介这套基于YOLOv5与大疆教育无人机Tello TT的完整项目面向需要实战的深度学习CV学习者、毕设学生及课程设计用户解决无人机场景下的目标识别、检测、追踪与测距问题。资源包含已调优的模型权重、旗与圈识别的数据集、完整源码和操作说明文档可直接运行或二次开发。压缩包共1672个文件大小约269MB以758张jpg图像样本、694个txt标注文件、94个yaml配置及50个py源码为主另含训练日志、模型pt文件与Docker部署配置目录结构清晰便于对照学习与复现实验。已有283人浏览学习。相比零散教程这套资料提供了从数据处理、模型训练到无人机实际部署的完整链路并附带训练事件记录与可视化日志适合在毕业设计或竞赛项目中快速落地也可参考其思路拓展训练其他检测目标。1. 目标识别追踪测距整套流程yolov5 与 Tello TT 这一套能省掉最痛苦的三个月做无人机目标识别检测、追踪测距方向的毕设或课设最卡人的往往不是算法本身而是“模型训练好了却不知道怎么写飞控指令让它追着目标跑”。这套基于 yolov5 与大疆教育无人机 Tello TT 的完整资源恰好把这一整条链路补齐了包含旗、圈两类目标的数据集、训练好的权重、完整源码和操作说明文档。适合正在做毕设、需要项目实战的深度学习CV方向学习者也适合直接拿来当课程设计或期末大作业。拿到手就能复现从训练到真机飞行的全过程不用自己从零凑代码。2. 源码包的骨架目录结构、权重文件、训练日志与两类控制通道2.1 先看懂包长什么样源码、重量级文件和训练日志分别负责什么拿到压缩包先别急着跑训练第一步是把目录结构摸清楚。这套资源里真正的核心是三块源码、训练好的模型权重、以及多个 events.out.tfevents 开头的 TensorBoard 训练日志文件。很多人看到 tfevents 文件不知道是什么其实那是训练过程中自动生成的可视化日志里面记录了每轮 loss、mAP、PR 曲线等信息。包里出现一串不同时间戳的 tfevents说明作者当时分多次跑过训练而不是只交了一个空壳。目录大致是这样project/ ├── yolov5/ # 基于yolov5的完整训练与推理目录 │ ├── train.py # 训练入口 │ ├── detect.py # 推理入口 │ ├── data/ # 数据配置文件 │ ├── models/ # 网络结构定义 │ ├── runs/ │ │ ├── train/ # 训练输出 │ │ │ └── exp*/ # 每次训练的结果best.pt 在里面 │ │ └── detect/ # 推理输出 │ └── weights/ # 训练好的模型文件 ├── datasets/ # 数据集images labels ├── tello_control/ # Tello TT 控制相关脚本 │ ├── track_run.py # 识别追踪主程序 │ └── utils.py # 坐标转换、PID 控制等工具函数 └── 操作说明文档.pdf这个结构对应的是 yolov5 官方仓库的标准组织方式后面训练、推理、调参都能顺着这套目录来不容易迷路。weights 目录下的 .pt 文件就是训练好的模型追踪主程序加载的就是它。这里要提醒一件事best.pt 和 last.pt 是有区别的best.pt 是验证集上 mAP 最高的那一轮权重last.pt 是最后一轮的权重。追踪 demo 默认加载的是 best.pt不要手误换成 last.pt否则识别效果会打折扣。2.2 Tello TT 的两种控制通道本地命令模式与 ROS 模式怎么选Tello TT 全称是 Tello Talent是大疆教育线的一款可编程无人机。它和普通 Tello 最大的差别是TT 带扩展接口官方提供 ROS 支持板载算力可以用来跑轻量模型推理。但实际项目里大多数人不会把 yolov5 直接压在 TT 的板子上跑——算力不够推理一慢无人机飞控就跟着卡顿。常见做法是电脑跑 yolov5通过 WiFi 拿到 TT 的摄像头画面推理出目标坐标后再把控制指令回传给无人机。Tello TT 在 Python 里最顺手的控制库是 djitellopy底层走 UDP 协议8889 端口收发控制指令8890 端口接收状态数据11111 端口接收视频流。连接代码非常简单from djitellopy import Tello tello Tello() tello.connect() # 建立 UDP 控制连接 tello.streamon() # 打开摄像头视频流 print(tello.get_battery()) # 读取电量起飞前确认 tello.takeoff() # 起飞这段代码里connect 是核心它会自动完成握手并开始接收状态包streamon 打开视频流后面 yolov5 推理用的就是这一路画面。get_battery 强烈建议每次起飞前都调一下真机飞行电量低于 20% 时电压跌落很快容易出现突然掉高。Tello 的指令模式适合做“电脑推理→遥控飞行”这种外脑架构如果你用的是 ROS 机器人操作系统TT 官方也提供了 tello_ros 功能包但配置和调试成本高不少毕设场景一般用不到本地命令模式就够了。2.3 核心链路把一帧画面变成一条飞行指令要经过哪几步整套追踪程序从宏观上看是一个五步闭环获取视频帧 → yolov5 推理 → 提取目标检测框坐标 → 计算与画面中心的偏差 → 通过 PID 输出 Tello 控制指令。理解了这个循环后面看源码就不会晕。while True: frame tello.get_frame_read().frame # 1. 取一帧 results model(frame) # 2. yolov5 推理 det parse_detections(results) # 3. 提取目标框 if det is not None: dx center_x(det) - frame_width / 2 # 4. 计算偏差 yaw pid_yaw.update(dx) tello.send_rc_control(0, 0, 0, int(yaw)) # 5. 发指令这里最关键的是最后一步send_rc_control 接收四个参数分别是左右平移、前后平移、上下升降、偏航范围都是 -100 到 100。注意这是遥控增量指令不是绝对位置指令所以 PID 输出得先转成整数再传进去。整套循环跑起来后无人机就像“盯住”目标一样目标往左移它就左转目标离远它就前推摇杆。3. 把旗和圈训进 YOLOv5数据集组织、训练命令与验证指标3.1 数据集长什么样旗、圈两类目标的标注与目录规范这套项目的数据集目标是“旗”和“圈”也就是类别 0 对应旗子类别 1 对应圈形目标。这是 Tello TT 竞赛里非常经典的组合——旗子用于识别导航圈用于穿环飞行。训练前先确认数据集目录是不是标准的 YOLO 格式否则 yolov5 会直接报错找不到标签文件。datasets/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 训练标签 │ └── val/ # 验证标签 └── flag_circle.yaml # 数据配置文件labels 目录下的每个 txt 文件和对应图片同名里面每行是一个目标格式是“类别 x_center y_center width height”四个坐标值都归一化到 0~1 之间。例如一张图里有一面旗子位于画面中心偏左对应 txt 内容可能是0 0.45 0.52 0.18 0.36第一个 0 表示类别是旗后面是归一化中心坐标和宽高。判断数据标注有没有问题最简单的方法是打开一张训练图看检测框是否贴合目标轮廓。真实项目里翻车最多的不是训练参数而是标注错位——标签和图片没对齐模型训出来全是乱框。3.2 训练命令与参数为什么用小的预训练权重起步yolov5 训练自己的数据集不需要从零训练一般用官方在 COCO 上预训练好的 yolov5s.pt 作为起点这样收敛快、精度也不差。训练入口是 train.py关键参数就那么几个python train.py \ --data flag_circle.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 200 \ --cache每个参数的含义--data 指定数据集配置文件里面写清楚了 train 和 val 的路径、类别数和类别名--weights 指定预训练权重路径--img 是输入图片的像素尺寸640 是 yolov5 的默认值目标小就降到 416 提升速度目标大就升到 800 提升小目标精度--batch 是每批图片数量取决于 GPU 显存8GB 显存跑 640 分辨率建议用 16显存不够减半--epochs 是训练轮数200 轮对中小数据集足够了--cache 把所有图片预加载到内存省去每次读盘的时间。如果你的显存比较紧张常见做法是加一行 --workers 4 控制数据读取线程数同时把 --batch 调成 8。模型文件 yolov5s.pt 是最小的一版权重体积和推理延时都低适合后续要部署到边缘设备的场景。追求更高精度再用 yolov5m、yolov5l但推理时间会明显增加无人机场景要权衡。3.3 训练过程中那些 tfevents 文件到底怎么看包里那一串 events.out.tfevents.1640873323.* 文件是 TensorBoard 的事件文件。yolov5 训练过程中每跑一轮都会往 runs/train/exp* 目录下写入这些文件。启动可视化也非常简单tensorboard --logdirruns/train然后在浏览器打开 http://localhost:6006 就能看到训练曲线。需要重点盯的是 Box Loss、Cls Loss 和 mAP0.5 这三条线。正常的训练曲线是前 50 轮 loss 快速下降100 轮后进入缓慢下降阶段mAP0.5 稳定在 0.9 以上就算可以收手。如果看到 loss 在后期反复震荡、mAP 没有上升趋势说明学习率设置得偏高或者训练数据里某个类别样本太少。判断模型是否过拟合有一个很实用的技巧看训练集 loss 和验证集 loss 的差值。两者差距越来越大就是典型的过拟合信号解决手段是加大数据增强、减少 epochs 或换轻量模型。yolov5 的模型调优不是玄学有这些曲线数据做支撑每调一个参数都能看到反馈。4. 从检测框到控制指令坐标换算、PID 追踪与三种测距方案4.1 加载权重做推理conf-thres 和 iou-thres 分别管什么训练完成后weights/best.pt 就是后续追踪程序的“大脑”。推理阶段有两个阈值最影响实际表现置信度阈值 conf-thres 和 IoU 阈值 iou-thres。很多人只调 conf忽略 iou结果检测框重复叠加、目标坐标抖动得很厉害。import torch model torch.hub.load(yolov5, custom, pathweights/best.pt, sourcelocal) model.conf 0.45 # 置信度阈值低于该分数的目标直接丢弃 model.iou 0.45 # IoU阈值重叠超过该比例的重复框会被抑制conf 设置过低比如 0.1会出现大量误检无人机对着一个路牌就开始追设置过高比如 0.8则会漏检目标稍微变形就丢失。一般建议 0.4~0.5 起步实测环境中识别率不理想再往下调。iou 是 NMS 去重时的重叠阈值0.45 是常见默认值目标密集重叠的场景可以看情况调到 0.3。4.2 从检测框到飞行控制PID 参数是怎么定出来的yolov5 输出的是检测框的像素坐标要变成无人机的飞行指令核心逻辑是目标框中心离画面中心越远无人机转角越大。直接按比例转容易来回震荡所以需要 PID 控制。下面这段代码是一个单轴偏航的 P 控制示例class PIDYaw: def __init__(self, kp0.6, ki0.01, kd0.05): self.kp kp self.ki ki self.kd kd self.integral 0 self.pre_error 0 def update(self, dx): self.integral dx derivative dx - self.pre_error output self.kp * dx self.ki * self.integral self.kd * derivative self.pre_error dx return max(-100, min(100, int(output)))kp 是比例系数决定响应速度ki 是积分系数用来消除稳态偏差kd 是微分系数抑制震荡。Tello 的偏航输出范围是 -100~100所以最后一步必须做限幅。我自己的经验是 kp 从 0.5 起步先不加积分和微分看无人机是否能稳住目标再逐步加 kd 消除摆动。kp 过大飞机会原地抽搐kp 过小则追不上目标这个参数值得花半小时在真机上慢慢试。4.3 测距方案ToF、Apriltag 和“目标尺寸焦距”哪个靠谱Tello TT 机身自带一个下视 ToF 传感器但它是朝下的用于测高不能测前方目标距离。所以要做“追踪测距”实际上得靠视觉方案。这套项目里目标是旗和圈最适合的是第三种方案已知目标的真实物理尺寸用焦距公式估算距离。# 已知圈的真实直径 D0.6m相机焦距 f 由标定或厂家参数获取 # 检测到圈在画面中的像素直径 d_pixel distance D * f / d_pixel这里的 f 是焦距单位是像素。Tello 摄像头的水平视场角大约 82.6°可以用公式 f (image_width / 2) / tan(FOV/2) 算出来。假设画面宽度是 960 像素代入计算得到 f 约为 590 像素。这个方法是像素测距误差来源主要是目标在画面里不垂直于相机光轴时检测框直径会偏小。真实场景中几厘米到十几厘米的误差对追踪任务来说完全够用。三种测距方案对比如下方案适用场景精度限制ToF 下视传感器高度保持厘米级只能测下方高度Apriltag 视觉标签导航定位毫米级目标必须贴标签目标尺寸焦距旗、圈等已知尺寸目标厘米级需要知道目标真实大小5. 避坑指南Tello TT 追踪项目的五个典型故障与排查路径5.1 现象模型在电脑上识别正常无人机一飞起来画面卡顿、追踪反应迟钝原因整条链路在电脑上跑没问题但一旦把模型推理、UDP 视频流接收、控制指令发送串成单线程循环帧率会掉到 10 帧以内控制周期拉长后无人机看起来像喝醉了一样。解决把推理分辨率降到 416 而不是 640模型推理时间几乎减半。再做一个更稳妥的处理——把视频流接收和模型推理拆成两个线程用队列缓冲最新帧控制循环只消费最新的一帧。丢帧比堵帧好控制指令要的是实时性不是每一帧都处理。5.2 现象目标短暂丢失后无人机不悬停反而朝一个方向乱飞原因追踪代码里没有做“目标丢失保护”。目标丢了几帧后PID 的积分项还在累积输出或者上一帧的检测结果仍然被重复用于控制无人机就会按记忆中的方向继续飞。解决检测不到目标时强制清零 PID 积分并输出悬停指令 send_rc_control(0, 0, 0, 0)。连续丢失超过 30 帧可以直接触发紧急降落这是真机飞行必须有的安全兜底。加一个简单的丢帧计数器代码量不大但能避免一次飞机撞墙的事故。5.3 现象训练时 mAP 很高实际场景一换角度就检测不到原因数据过拟合了训练环境的背景。尤其是“圈”这种目标真实场景里可能是挂在墙上的、放在草地上的、拿在手里的如果训练集里全是同一个场景模型其实学的是“那个背景区域里有个东西”而不是“圈本身”。解决训练数据里加上旋转、亮度变化、随机裁剪等增强手段并尽量采集不同背景、不同光线下的样本。训练时在 train.py 里加上 --augment 参数。如果数据集本身只有几百张图宁可减少 epochs也不要让模型把背景纹理背下来。5.4 现象Tello TT 的 get_battery 读到电量正常但起飞后高度数据跳动原因Tello TT 的下视 ToF 在一个水平、有纹理的表面上工作正常但如果你在纯色地板或者太阳直射的环境飞ToF 数据会跳变导致高度的闭环控制异常。解决起飞前选择有纹理的地面区域避免在纯白或反光表面起飞。如果户外飞行光线的红外分量会影响 ToF建议室内飞。代码里对 get_height() 的返回值做一个滑动平均滤波把跳变滤掉。5.5 现象连接 Tello TT 时频繁掉线视频流闪断原因电脑的无线网卡同时连接了 Tello 的 WiFi 和互联网系统在两者之间自动切换网络导致 UDP 数据包丢失。另一个常见原因是开飞行器之前没有退出大疆的 Tello AppApp 占用了同一个通信端口。解决连接 Tello WiFi 后在系统的网络设置里把“自动连接其他网络”关掉。飞行前彻底关闭 Tello App 和所有占用 UDP 8889 端口的程序。Windows 防火墙首次运行 Python 脚本时也要手动允许放行否则 UDP 数据会被静默拦截。6. 换目标重训从旗、圈到任意检测物的最短路径这套资源跑通之后最有价值的用法是把它改造成自己的目标检测项目。换目标有三个地方必须同步改数据配置文件里的类别名和类别数、标注文件里的类别编号、最后追踪程序里的类别筛选逻辑。yolov5 训练时会自动重新计算 anchor 尺寸所以这一块不用手动改。推荐的工作流程是先准备 100 张目标图片手工标注后只跑 20 个 epoch目的是快速验证标注格式是否正确、模型能不能收敛到 0.9 以上的 mAP。如果这 20 轮跑下来 loss 都没有明显下降说明标注有问题或者类别编号对不上这时候调试的成本最低。验证通过后再补齐训练集跑完整训练。我自己在真机上调试跟踪控制参数时会先把 kp 设成 0.5、ki 设成 0、kd 设成 0然后观察飞机是“跟不上”还是“来回摆”。跟不上就加大 kp来回摆就加 kd每调一次飞 30 秒就降下来看记录比一次性猛调三个参数高效得多。此后再接手任何无人机视觉项目我都会强制自己先跑一遍这条链路训练好模型、在地面用录好的视频回放调 PID、再上真机试飞而不是直接拿真机当调试平台。希望这些经验能帮你少走一圈弯路。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进