☰
YOLOv5+Tello TT无人机实战:目标检测与追踪测距全流程指南
2026/9/28 5:30:37 网站建设 项目流程

简介:基于YOLOv5与大疆教育无人机Tello TT联合开发的目标识别检测与追踪测距完整工程,定位面向毕业设计、期末课程设计及K12人工智能实践。压缩包内置可运行的Python源码、已标注数据集、训练好的模型权重与图文说明手册,代码附有注释,新手也能按步骤完成部署并复现识别、追踪与测距功能。资源压缩包共1672个文件,大小约269.35MB,主要包含758个jpg图像样本、694个txt标注文件、94个yaml配置、50个py脚本、9个pt模型权重,以及xml、sh、md、dockerfile等辅助文件,覆盖数据准备、模型训练、推理部署全流程。内容预览中可见大量tfevents训练日志,便于查看训练进度与参数调优记录。项目已有461人学习下载,常用于毕业设计选题参考和课程设计高分项目。资源提供的完整数据链路和预训练权重,可直接迁移到不同目标检测场景;说明文档结合目录结构梳理了运行方法,帮助使用者快速上手并进行二次开发。

1. 为什么是yolov5+Tello TT:一套能落地到教室的检测追踪方案

先说结论:用 yolov5 带着大疆教育无人机 Tello TT 做目标识别检测,再叠加追踪测距,最近两年已经成为不少高校实验室、中小学科创课和无人机竞赛队的标准入门路线。原因不复杂——Tello TT 有可编程的SDK、能直接拿到视频流和姿态数据,而 yolov5 是生态最成熟、训练自己的数据集门槛最低的目标检测模型之一,两者一拼,不需要自研飞控,也不用从零写视觉算法,就能在教室里跑出「识别到红色锥桶并锁定距离」的完整闭环。

这套方案适合谁?适合已经会一点Python、想绕过复杂课程设计的人:你要的不是发论文,而是把模型跑起来、把无人机飞起来、把数据测出来。它能解决三个痛点:第一,教学场景里缺的是低成本且能出效果的实验平台;第二,很多开源项目只给了推理代码,没给数据集和训练好的权重,导致复现第一步就卡死;第三,追踪测距的精度到底怎么调,很少有文档讲透。这篇笔记就按「环境 → 数据集 → 训练 → 推理 → 追踪测距 → 避坑」的顺序,把完整落地路径说清楚。

2. 把环境与数据集备齐:yolov5环境配置与TT图像采集的3个前置步骤

2.1 conda建环境与依赖版本:yolov5环境配置里最容易翻车的点

不管你是拿到现成源码压缩包,还是从GitHub拉 yolov5 主分支,第一步都是在 conda 里独立建一个环境。我见过太多新手图省事,直接往 base 环境里 pip install -r requirements.txt,结果把系统里其他项目的 torch 版本冲掉,回头哭都来不及。

常见做法是新建一个专门跑 yolov5 的 conda 环境,Python 版本选 3.8 或 3.9。yolov5 在 3.9 下表现稳定,往上到 3.11 会有一些旧版依赖的坑。命令如下:

conda create -n yolov5_tt python=3.9 -y conda activate yolov5_tt cd yolov5 # 进入yolov5源码目录 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

这里有个关键点:requirements.txt 里锁定的 torch 是 CPU 版还是 GPU 版,取决于你的机器。如果你只有 NVIDIA 显卡,想在训练时启用 CUDA,不要直接用 requirements 里默认的 torch,建议先装 cuda 版 torch,再装其余依赖。我一般会先执行pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118,然后再跑 requirements.txt。原因很简单:yolov5 的后处理和追踪推理在 CPU 上也能跑,但训练自己的数据集时没有 GPU,一个 epoch 可能要等几十分钟,你根本没法调超参数。

装完之后验证环境是否正常,用一行命令:

python -c "import torch; print(torch.__version__, torch.cuda.is_available())"

如果输出2.0.1+cu118 True,说明环境没问题。如果cuda.is_available()是False,先别急着重装,检查驱动和 nvcc 版本是否匹配,这也是我后面要单列的一个踩坑点。

2.2 采集TT图像并做标注:用Tello TT拍出符合yolov5训练要求的数据集

很多同学拿到「完整数据集」压缩包后直接开始训练,但你要明白:那只是作者在特定场景下拍的样本,换到你自己的教室、光线、目标物,准确率会明显下降。所以「基于yolov5+Tello TT」这个方案,真正值钱的部分不是那几千张图片,而是你能自己采集数据、自己标注、自己反复迭代的能力。

Tello TT 采集图像有两条路:一是用官方 Tello App 飞一圈拍视频,然后抽帧;二是直接用 yolo 源码里的 detect.py 配合 Tello 的 SDK 实时保存。更推荐第二条路,因为视频帧率和分辨率可控,还能记录无人机姿态。常见做法是用一个 Python 脚本连接 Tello TT 的 SDK,拿到每一帧 H.264 视频,再用 OpenCV 解码后保存成 jpg。

from djitellopy import Tello import cv2 tello = Tello() tello.connect() tello.streamon() count = 0 while count < 200: # 保存200帧 frame = tello.get_frame_read().frame if frame is None: continue cv2.imwrite(f"dataset/images/tello_{count:04d}.jpg", frame) count += 1 tello.streamoff()

这段代码的逻辑很简单:循环拉流,每帧存一张图。重点是参数设置——解析度默认是 960x720,对 yolov5 训练来说足够;但如果你要识别的是很小的目标(比如30像素以内的交通锥),建议先记住tello.set_video_resolution(Tello.RESOLUTION_720P)这样的设置,不要让图被压缩得过狠。另外,存图时不要只拍悬停画面,要涵盖不同高度、不同角度、不同光照,这样训练出来的模型才有泛化能力。

标注工具我推荐用 LabelImg 或 Label Studio,输出格式选 YOLO 格式——也就是每个图片对应一个 txt,里面每一行写class_id x_center y_center width height,坐标都是归一化到0-1的。如果你拿到的数据集里已经有 label 文件夹,建议花十分钟随机抽几张,把 txt 内容和图片目测对应一下,防止坐标单位不一致(有的工具输出是像素值,yolov5 要的是归一化值)。这一步是很多「数据集跑不通」的根源。

2.3 训练好的模型与权重文件的组织方式

标题里有「训练好的模型」,这个描述很宽泛。在 yolov5 语境下,训练好的模型通常指best.pt和last.pt两个权重文件。best.pt是验证集上 mAP 最高的权重,last.pt是最后一个 epoch 保存的权重。追踪测距阶段我们一定用best.pt,因为它的泛化能力通常更好。

拿到别人给的项目源码时,先看权重文件的后缀。.pt是 PyTorch 权重,可以直接加载;.engine是 TensorRT 序列化后的权重,需要配套的推理环境;.onnx是开放格式,可以用 OpenCV 或 ONNX Runtime 加载。在 Tello TT 这种边缘设备上,.engine更快,但生成它需要先把.pt转成.onnx,再转成.engine。后面第 4 章会展开讲部署。

还有一个小细节:数据集的data.yaml里train和val的路径必须是绝对路径或者相对路径但位置正确。很多项目压缩包解压后,训练命令直接报FileNotFoundError,就是因为 yaml 里写死的是作者机器的路径。我一般会改成相对路径:

train: dataset/images/train val: dataset/images/val nc: 2 names: ['cone', 'person']

这里的nc是类别数,names列表的索引要和标注 txt 里的class_id一一对应。如果顺序错了,训练不会报错,但识别结果会张冠李戴——这也是让你怀疑数据集质量的最隐蔽坑之一。

3. 训练自己的数据集:yolov5超参数与训练脚本的调参笔记

3.1 数据集格式与yaml配置:VOC转yolov5格式的3个边界坑

不管你手里的数据集是 COCO 格式还是 VOC 格式,最终都要转成 yolov5 需要的 YOLO 格式。网上现成转换脚本很多,但你要注意三个边界坑。

第一,VOC 的坐标是xmin ymin xmax ymax,转成 YOLO 需要做归一化,而且必须除以图片实际宽高,不能除以默认值。如果图片是 960x720,而你除的是 720x720,目标框位置整体右偏,训练时 loss 会异常升高但模型仍然能收敛,最后推理时框总是偏一点。

第二,类别映射。VOC 的类别名和 YOLO 的 class_id 是按字母序排列的——yolov5 源码里默认按文件名排序生成标注。比如你有cone和person两类,cone排在前面,class_id 是 0,person是 1。如果你的 txt 文件里写反了,训练出来的模型就永远分不清谁是谁。

第三,数据集拆分。我习惯按train:val = 9:1做随机拆分,但必须保证同一段连续视频抽出的帧不被分到两个集合里——否则训练集和验证集里的图片极其相似,验证 mAP 高得离谱,一到真实场景就露馅。所以先按视频片段分组,再在组内做划分,而不是把所有图片打乱直接分。

这里给一段我常用的 VOC 转 YOLO 脚本核心逻辑,只贴关键部分:

import os import xml.etree.ElementTree as ET def voc2yolo(xml_file, img_w, img_h, class_dict): tree = ET.parse(xml_file) root = tree.getroot() lines = [] for obj in root.iter('object'): name = obj.find('name').text if name not in class_dict: continue box = obj.find('bndbox') xmin = float(box.find('xmin').text) ymin = float(box.find('ymin').text) xmax = float(box.find('xmax').text) ymax = float(box.find('ymax').text) # 关键:用真实宽高归一化 x_center = (xmin + xmax) / 2 / img_w y_center = (ymin + ymax) / 2 / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h lines.append(f"{class_dict[name]} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") return lines

参数说明:img_w和img_h从图片实际尺寸读取,不要从 XML 的size节点取——因为有些标注工具的size字段写的是缩放前的值。class_dict是「类别名 → id」的映射,手动配置即可。

3.2 训练命令与关键超参数:yolov5超参数如何影响小目标检测

Tello TT 的相机架在高处往下看,目标(比如地面交通锥)在画面里通常很小,因此训练超参数要往「小目标友好」方向调。yolov5 默认的hyp.scratch-low.yaml是通用参数,直接拿来训练能出结果,但小目标召回率往往偏低。我一般会改三个地方:

  1. mosaic保持默认 1.0,因为马赛克增强能模拟远景小目标被拼接的效果;
  2. copy_paste提到 0.3 以上,特别是目标比较小的时候,这个增强能把目标从一个图复制粘贴到另一个图,等效于扩充小目标样本;
  3. scale从 0.5 改成 0.9,允许训练时对图片做更大幅度的随机缩放,让模型看到更多不同尺度的目标。

训练命令标准写法如下:

python train.py \ --data dataset/data.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 8 \ --img 640 \ --hyp hyp.scratch-low.yaml \ --device 0

参数说明:--weights yolov5s.pt是预训练权重,用小模型起步。V100 或 3080 上 100 个 epoch 大概一两个小时,如果你只有 CPU,建议把--epochs改成 20 先跑通,再考虑加预算。--batch-size 8对 8GB 显存比较安全,如果你的显卡只有 4GB,改成 4。--img 640是训练输入尺寸,如果 Tello TT 画面里的目标太小,可以试--img 960,但训练和推理速度都会变慢,后面部署到树莓派5这种设备上会吃力。

训练完成后,在runs/train/exp目录里看results.png:重点关注val/box_loss和val/obj_loss是否持续下降。如果两个 loss 在最后 20 个 epoch 还在明显波动,说明学习率没来得及衰减,可以适当增加--epochs或修改hyp里的lr0。这些就是 yolo 玩家常说的「基础笔记」——不是高端理论,而是每个项目都必须重复检查的基线指标。

3.3 后处理:NMS与置信度阈值在TT追踪场景里的调整

训练完只是第一步。真正放到 Tello TT 上跑的时候,你会发现同一个目标在连续几帧里会被模型检测出多个框——尤其是目标小且边缘模糊时。这就是后处理要解决的问题。yolov5 的推理阶段默认用 NMS(非极大值抑制)去掉重叠框,但你可以在推理脚本里调整两个关键阈值:conf_thres和iou_thres。

常见做法是先在离线图片上做一轮遍历,找到适合你场景的阈值。比如:

from pathlib import Path import torch model = torch.hub.load('./yolov5', 'custom', path='weights/best.pt', source='local') model.conf = 0.25 model.iou = 0.45 results = model('test_images/test_01.jpg') results.print()

这段代码用 torch.hub 加载本地权重,设置置信度阈值 0.25、NMS IoU 阈值 0.45。在 Tello TT 的俯视视角下,如果目标是明显的红色锥桶,conf可以放到 0.35,因为这类目标特征太明显,低置信度的框大概率是误检;但如果你要识别的是学生或行人,目标姿态变化大,conf降到 0.15 能找回很多框,代价是误检增加。iou保持 0.45 左右,太大容易把两个紧挨着的同类目标合并成一个框,太小又会让同一个目标产生多个重叠框。追踪测距时,多个重叠框会导致距离跳变——后面会详细说。

4. 在Tello TT上做目标识别检测与追踪测距:从权重到实时推理

4.1 用yolov5推理TT视频流的代码骨架

当你在本地实验跑通了检测,下一步就是让 Tello TT 的实时视频流进入 yolov5 推理循环。有一个绕不开的问题:TT 视频流是 H.264 编码,yolov5 的预处理期望的是 BGR 的 numpy 数组,所以必须用 OpenCV 解码每一帧,再送入模型。

一个最小可跑的推理循环参考如下:

from djitellopy import Tello import cv2 import torch tello = Tello() tello.connect() tello.streamon() # 加载训练好的权重 model = torch.hub.load('./yolov5', 'custom', path='weights/best.pt', source='local') model.conf = 0.30 model.iou = 0.45 model.max_det = 10 # 每帧最多同时追踪10个目标 while True: frame = tello.get_frame_read().frame if frame is None: continue results = model(frame, size=640) rendered = results.render()[0] # 在图像上画框 cv2.imshow('Tello TT Detection', rendered) if cv2.waitKey(1) & 0xFF == ord('q'): break tello.streamoff() cv2.destroyAllWindows()

逻辑说明:results.render()返回的是画好检测框的图片列表,取[0]就是当前帧。model(frame, size=640)内部会做 letterbox 缩放,保持长宽比并填充灰边,所以不用手动 resize。关键参数是model.conf和model.iou,这两个值在实时场景里比训练超参数更敏感——TT 飞行时画面抖动,如果conf设太高,检测框会一闪一闪;设太低,又会出现很多假框。我建议从 0.25 开始调。

4.2 追踪测距:单目测距与PID追踪的简化做法

「追踪测距」这个标题里的第二关键词,在真实项目里指的是两件事:一是用视觉锁定目标并让无人机跟随(追踪),二是估算无人机与目标的距离(测距)。Tello TT 没有深度相机,也没有激光雷达,所以测距只能用单目视觉的近似方法。

最常见做法是已知目标的真实高度或宽度,然后用相似三角形计算距离。比如红色交通锥的真实高度是 30cm,在图像中检测框的高度是 120 像素,相机焦距是 920 像素(Tello TT 的水平视场角约 82 度,可以通过标定得到),那么距离 ≈ (30 / 120) * 920 = 230cm。

这个公式我建议封装成函数:

def estimate_distance(real_height_cm, box_height_pixel, focal_px): return (real_height_cm / box_height_pixel) * focal_px

参数说明:real_height_cm是目标真实尺寸,需要你自己量;box_height_pixel是检测框的height乘以图像高度(因为 yolo 输出是归一化的);focal_px是焦距像素值,可以用 OpenCV 标定棋盘格拿到。这个方法误差在 10%~20% 左右,但胜在简单,不需要额外硬件。

至于追踪,常见做法是 PID 控制器。先计算目标中心与图像中心的偏差,然后把偏差作为 PID 的输入,输出给 Tello 的左右、前后、上下通道。一个简化的比例控制代码示例:

def pid_control(dx, dy, kp=0.01): left_right = kp * dx up_down = -kp * dy return left_right, up_down

注意:这个示例只写了 P 分量,实际飞行时如果没有 D 分量,TT 会在目标附近振荡。我会在循环里维护上一帧偏差,计算误差变化率,加到输出上。另外,TT 的 SDK 指令有频率限制,建议控制在 10~20Hz,太高会出现指令堆积,无人机会突然抽搐。

4.3 部署注意:算力受限时的推理加速

如果你把训练好的模型放到树莓派5上部署——这是很多竞赛队伍的常规做法——那你要面对的是实时性问题。树莓派5 的算力比普通 PC 弱很多,yolov5s 在 640 分辨率下可能只有 2~4 FPS,直接做追踪会让无人机反应迟钝。

我一般会做三件事。第一,把推理分辨率从 640 降到 416 或 320,Latency 能下降 40% 以上,代价是小目标检测率下降。第二,用 ONNX Runtime 代替 PyTorch 推理,因为 ONNX Runtime 对 ARM 平台有优化。转换命令很简单:

python export.py --weights weights/best.pt --include onnx --img 320

第三,如果你有 NVIDIA Jetson 设备,导出成 TensorRT engine 后帧率可以到 20 FPS 以上。但没有 GPU 的树莓派,ONNX 加 320 输入是性价比最高的组合。部署时还有一个隐藏坑:树莓派上如果同时跑 Tello 的 WiFi 接收和 OpenCV 解码,CPU 会爆满,建议把视频解码用硬件加速(树莓派5 可以用cvv4l2之类的 GStreamer 管道)。

5. Tello TT实战避坑:5个让新手反复重跑的现象与对策

5.1 现象:训练损失正常但识别不到TT视角下的小目标

模型在验证集上的 mAP 明明不低,但一放到 Tello TT 的实时画面上,小目标经常漏检。原因很直接:TT 飞行时的运动模糊和俯视角度带来的目标形变,和训练集里的静态图差太多。解决思路不是盲目加大训练集,而是做两步:第一,训练时打开--augment参数,让模型适应随机光照、旋转、缩放;第二,在采集阶段就有意识地把无人机飞到不同高度和偏离角度,制造更多「不完美」的样本。这是很多项目文档都不写但是实际最影响效果的一条。

5.2 现象:推理帧率只有3 FPS,追踪发飘

PC 上跑得好好的,换到树莓派后整个追踪系统像慢动作。原因通常是模型输入太大,且没有做后处理上的帧间复用。我试过把检测结果用简单卡尔曼滤波跟踪,这样即使模型推理只有 5 FPS,控制输出也能平滑到 20Hz。另一个原因是 OpenCV 的视频解码线程和推理线程没有分开,导致解码阻塞推理。解决方式是开两个线程,一个只负责读帧,一个只负责推理,中间用 queue 传递。

5.3 现象:TT飞近后目标丢失,测距跳变

很多人在追踪时发现,无人机越靠近目标,目标越容易飞出画面,测距数值突然变得很大。这不一定是模型问题,而是你的追踪策略只有「往中心飞」,没有限速和边界保护。我给出的对策是:在控制回路里加一个死区——当目标中心偏差小于 20 像素时,不输出水平控制;同时当估计距离小于 50cm 时,强制停止前飞并略微后退。这个策略很简单,但能把整个系统的稳定性提升一个档次。

5.4 现象:conda环境装好后torch与cuda不匹配

明明按 requirements 装好了,torch.cuda.is_available()还是 False。最常见原因是 PyTorch 装成了 CPU 版。排查时先看torch.__version__是否带+cu后缀,如果没有,卸载重装:

pip uninstall torch torchvision -y pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

注意:cu118对应 CUDA 11.8,你的显卡驱动必须支持该版本。可以用nvidia-smi看到驱动支持的最高 CUDA 版本,如果只支持到 11.4,就改用cu113。这是环境配置里最隐蔽但是最不值得浪费时间的坑。

5.5 现象:数据集里有大量重复背景导致过拟合

我拿到过一份别人整理的 Tello TT 数据集,里面 80% 的图片是从一段悬停视频里连续抽帧出来的,背景几乎一样,只有目标位置微微移动。训练出来的模型在自己的测试集上 mAP 很高,换到新环境立刻崩。解决方法是做视频抽帧时限制采样率,比如每 10 帧取一帧,同时把不同飞行路线的视频分开存放,确保训练和验证集来自不同路线。如果你自己也打算做数据集,一定不要偷懒连续抽帧。

6. 让整套系统更耐用的进阶技巧:模型量化与追踪控制回路的验证方法

到了这个阶段,你已经能跑通检测、追踪、测距了。但如果要在竞赛场上稳定比赛,我强烈建议再做两件事:模型量化和控制回路验证。

模型量化方面,如果你实在没有 GPU,在树莓派5上部署,可以把训练好的权重先导出成 int8 量化的 ONNX 模型。常见的做法是用 ONNX Runtime 自带的动态量化工具:

from onnxruntime.quantization import quantize_dynamic, QuantType quantize_dynamic( model_input='best.onnx', model_output='best_int8.onnx', weight_type=QuantType.QUInt8 )

参数说明:QuantType.QUInt8是无符号 8 位量化,对精度影响比QInt8小。量化后模型体积缩小到原来的四分之一,推理速度提升 1.5~2 倍,但检测框的置信度会普遍下降 0.05 左右。应对方式是把推理时的conf阈值调低 0.05,而不是对量化模型修改训练参数。

追踪控制回路的验证,我习惯用日志方式记录每一帧的目标中心坐标、距离估计、控制输出。跑完一次飞行后,把这三组数据画成曲线——如果水平控制输出曲线呈等幅振荡,说明 P 项增益太大;如果目标中心偏差一直收敛不到 0,说明有恒定误差,需要加一点积分项。这个验证方法不需要额外硬件,比凭空调 PID 参数可靠得多。

最后说一个我自己的习惯:每次改动数据集或者训练超参数前,先把旧的best.pt复制一份带日期备份。因为你在第 3 轮调参会把模型调坏,而重训一次的成本往往是一两个小时,有备份就等于有后悔药。做无人机项目的血泪经验是,视觉模型的表现有很强的「玄学」成分,你永远不知道哪次数据增强会让 mAP 掉 3 个点。所以不求一次到位,而是按版本管理数据和权重,每一步都可回滚。希望这些方法能帮到你,让你的 Tello TT 目标识别检测和追踪测距项目少走弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询