ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv5的无人机目标识别追踪与测距:Tello TT实战

基于YOLOv5的无人机目标识别追踪与测距:Tello TT实战 简介一套基于YOLOv5与大疆教育无人机Tello TT的完整目标识别与追踪测距方案专为毕业设计、期末大作业及课程设计场景打造尤其适合有Python基础、想快速上手无人机视觉应用的学生。压缩包共1672个文件约269.35MB主要包含758张jpg图像训练/测试样本、694个txt标注文件YOLO格式目标框坐标、94个yaml配置模型结构及训练参数、50个Python源码训练、检测与追踪测距、9个预训练pt模型可直接部署的权重及md说明文档数据集、配置、代码和权重一应俱全省去自行采集与训练的繁琐环节。已有461人浏览学习代码注释详尽新手也能理解内置TensorBoard训练日志可查看损失曲线并辅助调参与复盘。整套资料结构清晰部署简单曾获98分并获导师认可是课程设计与毕设的高分参考可大幅节省从零搭建项目的时间。1. 基于YOLOv5加大疆教育无人机Tello TT的目标识别与追踪测距到底能做什么基于YOLOv5加大疆教育无人机Tello TT做目标识别、追踪和测距是我最近在课程设计和竞赛群里看到问得最多的一套组合。先说结论这套方案里真正决定追踪稳定性的瓶颈不是模型mAP而是从图传到控制指令的端到端时延。它的典型形态是——地面电脑上跑YOLOv5识别视频帧锁定目标后通过SDK把速度指令发给飞机飞机本身只做执行不承担推理。适合三类人正在做无人机课程设计或毕业设计的、带学生打无人机竞赛的、想验证视觉识别到运动控制全链路闭环的工程师。如果你手里已经有一台能飞的Tello TT按这条路线走一周内能搭出一个可演示的目标锁定最小系统后面再慢慢补追踪与测距的稳定性。2. 环境与数据准备用conda跑通YOLOv5并训练自己的数据集2.1 用conda把YOLOv5环境一次配好几个容易翻车的小参数常见做法是先创建独立conda环境再把依赖装进去。这里有一个血泪教训不要直接克隆YOLOv5最新主干代码就跑版本更新频繁依赖和命令行参数经常变训练到一半报错最难受。我一般会把仓库版本定在一个稳定tag上。# 1. 创建独立环境Python 3.8 在 YOLOv5 各版本里兼容性最稳 conda create -n yolov5 python3.8 -y conda activate yolov5 # 2. 拉取代码后先不要急着跑把版本定住 git clone yolov5官方仓库 cd yolov5 git tag # 查看当前可用版本选择一个稳定版本 # 3. 安装依赖 pip install -r requirements.txt依赖装完后先跑一次官方detect.py验证环境不要直接上自己的模型和无人机。验证命令很简单python detect.py --weights yolov5s.pt --source data/images/bus.jpg如果输出了runs/detect/exp下的图片说明torch、CUDA和模型权重都正常。这里容易翻车的是Python版本3.10以上跑旧版YOLOv5会遇到torch兼容问题3.8最稳。还要确认CUDA可用python -c import torch; print(torch.cuda.is_available())返回True才说明GPU推理链路是通的。很多新手在这步看到False就开始调代码其实多半是装了CPU版torch重装对应CUDA版本的torch就好。2.2 把VOC/自采数据转成YOLO格式四个坐标坑YOLOv5训练用的标签是纯文本每行一个目标格式是class x_center y_center width height坐标全部归一化到0到1之间。手里如果是VOC格式的xml标注或者自己用LabelImg标完导出的xml都需要转成这个格式。转换脚本的逻辑其实很简单# voc2yolo.py # 输入: VOC格式xml输出: 同名txt放到labels目录 import xml.etree.ElementTree as ET class_names [person, ball] # 按训练顺序从0开始 def convert_annotation(xml_file, img_w, img_h): tree ET.parse(xml_file) root tree.getroot() lines [] for obj in root.iter(object): cls obj.find(name).text cls_id class_names.index(cls) # 类别id必须从0起 box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # 转成中心点宽高再归一化 dw 1.0 / img_w dh 1.0 / img_h cx (x1 x2) / 2.0 * dw cy (y1 y2) / 2.0 * dh w (x2 - x1) * dw h (y2 - y1) * dh lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) return lines这段代码背后有四个坐标相关的坑我在实际转换时逐一踩过第一xml里xmax、ymax是右下角坐标转中心点时要加xmin除以2不能直接拿宽高算。第二归一化必须除以图片真实宽高不能除以640或训练分辨率训练时会自动缩放但标签坐标的基准是原图尺寸。第三类别id从0开始class_names列表的顺序一旦固定就不能改否则训练出来的模型推理结果会错位。第四训练集和验证集不能有重叠图片从同一个文件夹随机划分时尤其容易漏重叠会导致验证mAP虚高真机部署时立刻现原形。转换完的txt直接放在数据集目录下的labels/train和labels/val里图片放在images/train和images/valYOLOv5默认会自动找同名标签。2.3 用YOLOv5训练自己的数据集data.yaml、超参数和训练命令训练自己的数据集核心是写对data.yaml。很多新手在这里写错路径导致训练时标签全部找不到表现为loss正常但mAP一直为0。一个可用的data.yaml长这样# data.yaml # 路径写相对路径整个数据集文件夹拷到哪都能用 train: ./datasets/tello_dataset/images/train val: ./datasets/tello_dataset/images/val nc: 2 # 类别数 names: [person, ball] # 与2.2节class_names顺序一致yaml写好后训练命令按官方模板走就够python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --hyp hyp.scratch-low.yaml \ --device 0参数说明--img 640是训练输入分辨率不是推理分辨率真机部署时图传帧可以缩到480来提速--batch 16在8G显存上比较稳显存小就降到8--weights yolov5s.pt是官方预训练权重小数据集上从预训练权重起步比从头训练收敛快很多--hyp是超参数文件默认的hyp.scratch-low.yaml已经适配大多数场景先跑通一轮再考虑改超参数。关于yolov5超参数我的建议是不要一上来就动学习率、增强系数这些。先用默认把流程跑通记录mAP然后一次只改一个参数。比如追踪场景对查准率要求高可以把hsv_h这类颜色增强调低因为无人机飞行时的光照变化本身已经够大过度增强反而让模型学不到稳定的颜色特征。先花时间把数据标签做干净比调超参数收益大得多。训练结束后看runs/train/exp目录下的results.png和weights/best.pt。best.pt是按验证集mAP最优保存的权重这个文件就是后面部署要用的。3. 部署链路把YOLOv5接到Tello TT图传上的最小系统3.1 Tello TT的SDK架构为什么模型跑在地面端而不是飞机上先明确一个边界Tello TT机身算力非常有限机载芯片无法跑PyTorch推理。常见做法是地面PC通过Wi-Fi接收图传视频流在PC上跑YOLOv5推理再把控制指令通过SDK发给飞机。这就是“yolov5部署”在这套方案里的真实含义——部署到地面端不是部署到飞机上。Tello TT的SDK通过UDP端口通信控制指令是文本格式。和本方案相关的指令就这几个指令用途说明command进入SDK模式连接后必须先发takeoff起飞起飞后悬停land降落紧急情况直接调用rc left_right forward_backward up_down yaw速度控制四通道取值范围-100到100Python控制Tello TT最常用的是djitellopy库封装了图传和指令发送。部署链路是Tello TT通过Wi-Fi把720p图传推给PCPC用OpenCV逐帧解码YOLOv5对帧做检测得到目标框后换算控制量再通过UDP发送rc指令。这个链路有一个绕不开的延迟通常100到200毫秒所以控制频率不宜太高后面会细说。3.2 用djitellopy订阅图传、跑推理后将检测框叠加显示部署第一步是跑通“图传→推理→显示”的最小循环。代码不长重点在模型加载和图传读取# tello_detect.py from djitellopy import Tello import cv2 import torch # 加载训练好的权重sourcelocal 表示用本地yolov5仓库 model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/exp/best.pt, sourcelocal) model.conf 0.50 # 置信度阈值 model.max_det 1 # 追踪场景只保留最高置信度的目标 tello Tello() tello.connect() tello.streamon() try: while True: # get_frame_read() 返回的是BGR格式帧 frame tello.get_frame_read().frame # 缩小推理帧提升整体循环频率 small cv2.resize(frame, (640, 480)) results model(small) # results.render() 在帧上画出检测框并返回 cv2.imshow(YOLOv5 Tello TT, results.render()[0]) if cv2.waitKey(1) ord(q): break finally: tello.streamoff() cv2.destroyAllWindows()参数说明model.conf是置信度阈值飞行场景建议不低于0.5太低会把背景误检为目标model.max_det 1很关键追踪只需要一个目标保留多个目标会在后面取最大值时引入不必要的判断sourcelocal表示加载本地仓库不联网拉取离线环境也必须这么写。这里有一个容易翻车的细节cv2.resize(frame, (640, 480))的第二参数是(宽, 高)不是(高, 宽)。图传是960x720我一般先缩到640x480跑推理因为追踪场景帧率比单帧精度更影响控制效果。如果推理帧率低于10fps先降分辨率再考虑换更轻的yolov5n模型。3.3 先录制视频验证检测链路为什么我不建议直接上真机调试直接上真机调试效率很低图传抖动、飞机漂移和检测问题混在一起很难定位。我一般先把Tello TT的图传录制一段视频在电脑上循环跑检测把链路先调通。# offline_test.py 用视频文件替代图传 import cv2 import torch model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/exp/best.pt, sourcelocal) cap cv2.VideoCapture(flight_rec.mp4) # 飞行时录的视频 while True: ok, frame cap.read() if not ok: break results model(frame, size640) # 只保留conf最高的检测框用于后续追踪逻辑调试 det results.pandas().xyxy[0] if not det.empty: top det.iloc[0] cx (top[xmin] top[xmax]) / 2 cy (top[ymin] top[ymax]) / 2 conf top[confidence] cv2.imshow(offline, results.render()[0]) if cv2.waitKey(1) ord(q): break这段代码把YOLOv5后处理暴露出来了results.pandas().xyxy[0]是一个DataFrame每行包含检测框坐标、置信度、类别名。追踪测距要用到的主要就是cx、cy和检测框高度这三个量在离线视频上可以先跑通验证检测是否稳定。自检标准很简单目标从画面一端走到另一端时中心点轨迹是平滑的没有跳变和来回抖。4. 追踪与测距从图像像素到Tello TT的rc控制指令4.1 单目测距的几何原理与焦距标定Tello TT没有机载激光测距常见做法是用单目视觉估计距离。原理是相似三角形已知目标真实高度、相机焦距、目标在图像里的像素高度距离就能算出来。def estimate_distance(pixel_h, real_h_mm, focal_px): 单目测距 pixel_h: 检测框在图像中的像素高度 real_h_mm: 目标的真实高度/直径单位mm focal_px: 相机焦距单位像素标定得到 if pixel_h 1: return None return real_h_mm * focal_px / pixel_h / 1000.0 # 返回米焦距focal_px怎么标定用A4纸就能做。把A4纸竖着放在距离相机1米、2米、3米的位置分别记录检测框的像素高度p_h然后算焦距# focal distance * pixel_h / real_h # real_h 取A4纸短边 210mm focal_1m 1.0 * p_h_1m / 0.21 focal_2m 2.0 * p_h_2m / 0.21 focal_px (focal_1m focal_2m) / 2 # 取平均注意检测框的高度并不等于目标真实高度。人形目标框通常会带上背景直接用框高算距离会偏近我一般会乘一个0.85到0.95的经验系数。追踪一个固定目标比如足球、交通锥时标定就简单很多——目标真实高度固定检测框就是目标本身系数取1.0。4.2 像素偏差到rc追踪控制的最小PD闭环追踪控制的本质是让目标中心尽量靠近画面中心同时保持目标距离在设定值附近。误差量有三个横向偏差err_x、纵向偏差err_y、距离偏差err_d。转为Tello TT的rc指令时我通常这样映射# 假设画面宽高为 W, H目标中心为 cx, cy测距为 dist W, H 960, 720 err_x cx - W / 2 # 目标偏左为负 err_y cy - H / 2 # 目标偏上为负 err_d dist - target_dist # 太远为正 # 比例控制先不加积分项减少超调 def clamp(v, lo, hi): return max(lo, min(hi, v)) roll int(clamp(-err_x * 0.12, -100, 100)) # 横向偏移 - 左右横滚 pitch int(clamp(err_d * 30, -100, 100)) # 距离偏差 - 前后飞行 throttle int(clamp(-err_y * 0.12, -50, 50)) # 纵向偏移 - 升降 yaw int(clamp(-err_x * 0.08, -30, 30)) # 小幅偏航辅助 tello.send_rc_control(roll, pitch, throttle, yaw)逻辑说明err_x控制roll和yaw两个通道roll负责快速横向修正yaw负责让机头朝向目标yaw系数取roll的三分之一左右避免飞机原地打转err_d控制pitch目标太远就前飞靠近太近就后退err_y控制throttle目标在画面上方说明飞机偏高需要下降。这里有个关键参数Tello TT的rc指令取值范围是-100到100四个通道都需要做幅值限制。我把throttle限制在-50到50因为垂直方向的突变最容易让画面剧烈抖动影响后续检测。控制频率控制在10Hz以内给Wi-Fi链路留出响应余量发得太频繁指令会积压在UDP缓存里飞机反而反应不过来。4.3 直接影响追踪质量的三个参数置信度阈值、EMA滤波和目标切换同样的检测模型参数不同追踪体验天差地别。我常用的初始参数如下参数初始值说明model.conf0.50低于0.4时追踪会跟着背景跑EMA平滑系数0.40.2偏稳偏钝0.6偏灵敏目标丢失保持时间0.5秒超过后切悬停不再用旧数据目标高度系数0.85~0.95框高不等于目标真实高EMA滤波是必备的。检测框中心点逐帧抖动很厉害直接把原始cx、cy送进控制会让飞机不停抽搐。我一般对cx、cy、pixel_h三个量分别做一阶指数平滑class EMA: def __init__(self, alpha0.4): self.alpha alpha self.value None def __call__(self, x): if self.value is None: self.value x else: self.value self.alpha * x (1 - self.alpha) * self.value return self.value # 用法 ema_cx EMA(0.4) smoothed_cx ema_cx(cx)alpha越大滤波越灵敏但越容易抖alpha越小轨迹越平滑但滞后越大。我一般从0.4起步如果飞机明显前后抽动就降到0.25。目标切换是另一个容易被忽略的点。追踪场景一旦跑丢了目标系统会怎么处理常见做法是连续0.5秒检测不到目标就自动悬停而不是继续用最后一帧的位置往前飞。0.5秒是经验值Tello TT的悬停本身就有漂移时间太长飞机飘远难以找回太短则检测一抖就误判丢失。5. 五个翻车现场追踪测距里常见问题的现象、原因与排查5.1 训练时mAP一直为0但loss看着是正常的现象训练几十轮后loss曲线正常下降但验证集mAP全是0best.pt也出来了放检测里什么都框不到。原因概率最高的不是模型问题是标签路径或类别设置问题。常见有三类标签txt文件和图片文件名对不上、类别id超出了data.yaml里的nc、训练集和验证集划分时把同一目标的图片混用了。解决先用官方val.py带--verbose跑一遍看每个类别的AP输出然后写脚本对比images/val和labels/val的同名文件数量最后把标签可视化画到原图上人工看框的位置对不对。这三步能定位绝大多数标签问题。记住一个原则loss正常不代表标签正确YOLOv5对错误标签的容忍度比想象中高。5.2 CUDA out of memorybatch不背锅img尺寸也是元凶现象训练刚开始显存直接爆掉报CUDA out of memory。原因大部分情况不是batch size太大的问题而是--img设置过大。YOLOv5在训练时会把输入缩放到--img指定尺寸这个大分辨率本身极耗显存。还有人电脑上挂了多个Python进程抢占显存。解决先跑nvidia-smi看显存被谁占了关掉多余进程然后把batch降到8--img从640降到512这两步能解决90%的显存问题。如果还要更大batch可以加--cache ram配合梯度累积但初期没必要。5.3 图传卡顿导致飞机“点头病”Wi-Fi干扰比模型更致命现象地面端画面掉帧到10fps以下追踪时飞机一冲一停像在点头。原因Tello TT通过2.4G Wi-Fi直连这个频段受蓝牙、手机热点、USB 3.0接口干扰非常明显。图传是UDP丢包后画面就卡住控制指令同样会延迟整个闭环就进入“看到旧画面、发出旧指令”的恶性循环。解决飞行前关闭电脑蓝牙和手机热点用外置USB Wi-Fi网卡替代内置网卡外置天线接收效果会好很多地面端推理分辨率降到480p把帧率拉回15fps以上。这条经验很朴素但我在多个场地验证过信号干扰导致的问题比重训模型还常见。5.4 白天强光下检测框乱跳先查自动曝光别急着调超参现象室内检测好好的拿到室外阳光下检测框开始乱跳置信度忽高忽低目标明明在画面里却偶尔跟丢。原因强光下自动曝光让目标过曝纹理细节丢失YOLOv5对整体亮度变化的鲁棒性没有想象中好。SDK没开放手动曝光时退一步的做法是对输入帧做CLAHE增强把过亮区域的局部对比度拉回来# clahe_enhance.py 对过曝帧做局部对比度增强 import cv2 def enhance_frame(frame): lab cv2.cvtColor(frame, cv2.COLOR_BGR2LAB) clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) lab[..., 0] clahe.apply(lab[..., 0]) return cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)解决优先选侧光或阴影区飞行还是不行就在检测前加这一层增强。这里有个“玄学”成分CLAHE的clipLimit不是越大越好2.0左右起步放大到3.0会容易出现噪声。换个场地先录视频回放测试比飞机飞起来再调效率高十倍。5.5 距离忽远忽近、飞机前后抽动单目测距被框高噪声放大现象追踪时飞机保持距离不理想前后抽动明显。看打印出来的dist数值在1.8米到3.2米之间来回跳但目标实际没动。原因单目测距对像素高度的噪声是倒数放大关系检测框高度差5个像素在远距离上能造成半米的距离误差。检测框本身包含了目标周围背景框高抖动直接被放大到距离上再传到pitch控制飞机就前后抽动。解决三管齐下。第一对pixel_h做EMA平滑平滑系数取0.3左右距离输出会稳定很多第二限制单步距离变化量比如两帧之间距离变化超过0.3米就丢弃这一帧用上一帧的值第三给目标高度乘经验系数把框高和真实高度的系统性偏差校正掉。这三条都做之后距离误差一般能控制在15%以内。6. 进阶技巧飞行数据回采与增量训练让模型越飞越准换一个场地光照、背景、目标角度都变了训练集里没有的场景开始在真机上冒出来。最常见的表现是目标在画面里稍微转个角度置信度就跌破阈值。与其反复调超参数我倾向于用飞行数据回采做增量训练。飞行时把那些“检测不自信”的帧存下来落地后快速标注加入训练集再训一轮。这比从零采集数据效率高得多因为回采的帧本来就覆盖了这个场地真正会遇到的角度和光照。# recolect.py 在检测循环中保存低置信度帧 import time # 每帧检测完成后 top_conf det.iloc[0][confidence] if not det.empty else 0 if top_conf 0.35 and frame is not None: ts int(time.time()) cv2.imwrite(frecall/{ts}.jpg, frame)保存下来的帧不用全部标注人工挑出目标清晰、和之前训练集差异大的几十张就够了然后用LabelImg重新框一遍放在一个新目录里和原训练集合并增量训练10到20个epoch。注意训练时把每个epoch的验证集结果打印出来观察新增数据有没有让旧场景掉点。验证方法我习惯用回放式验证飞行时录一段完整视频落地后用同一套代码在电脑上离线跑统计目标中心的抖动幅度和距离误差的均方根。这个数值比看飞机飞得稳不稳更客观因为人能感觉到飞机晃但说不清差多少。我每次换场地都会先飞一段采集数据再增量训练一次宁可多花半天标数据也懒得调超参数据比玄学靠谱。希望帮到你。本文还有配套的精品资源点击获取
返回列表