ARTICLE DETAIL

资讯详情

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

YOLOv5+MoveIt实战:垃圾分类机器人从感知到抓取的工程实现

YOLOv5+MoveIt实战:垃圾分类机器人从感知到抓取的工程实现 简介在机器人工程实践中目标检测与运动规划是两大核心模块前者让机器“看见”后者让机器“行动”。YOLOv5作为轻量级视觉识别模型以较低算力开销实现高效检测MoveIt则基于ROS生态提供完整的机械臂运动规划与逆运动学求解能力。两者看似独立真正打通却依赖坐标系标定、消息通信与轨迹设计等系统工程细节。垃圾分类机器人正是融合这两项技术的典型场景通过将视觉识别结果转化为机械臂可执行的三维位姿实现从图像输入到抓取投放的完整闭环。这类项目不仅适用于毕业设计与学科竞赛也蕴藏着智能制造、无人分拣等真实工业需求的落地逻辑。围绕其源码与设计文档可以系统学习目标检测、运动规划、手眼标定及ROS通信机制是理解机器人集成开发的高价值案例。 做这个垃圾分类机器人项目之前我自己先踩了一圈硬件和软件的坑。这套东西说白了就是先让摄像头“看见”垃圾是什么再让机械臂“听懂”该把垃圾放到哪里中间串起这一切的就是YOLOv5目标检测和MoveIt运动规划。你拿到的这份源码加设计文档不是那种跑通demo就完事的玩具项目而是一整套从感知到执行都能闭环的工程实现。无论你是做毕业设计、准备机器人相关竞赛还是单纯想把视觉和机械臂两条技术线打通这个项目都非常值得拿来拆开研究。整个项目最值钱的地方不在某个单一算法有多高深而在于它把“识别”和“动作”糅合在一起。很多人单独玩YOLOv5能识别出一堆物体单独装个MoveIt也能让机械臂动起来但一联调就各种拉胯——坐标系对不上、识别到目标却抓不准、机械臂规划半天路径然后卡死。这个源码里恰恰把这一整条链路走通了而且留下了完整的设计文档能帮你少走非常多弯路。1. 项目整体设计思路与系统架构拆解1.1 核心需求不是单纯识别而是识别后要“动手”先别急着打开代码看网络结构先想清楚这个机器人到底要完成什么任务。它面对的是一堆混杂的垃圾可能散落在工作台面上也可能是流水线上缓缓送过来的。机器人要做的事情拆开来看只有三步看清这是什么垃圾、规划一个不会撞到东西的路径、伸手过去抓起来并放到正确的分类桶里。但“看清”这件事和“抓准”这件事是强耦合的。YOLOv5输出的只是图像上的像素坐标框机械臂要执行的是三维空间里的位姿。你从模型拿到的x_center,y_center,width,height这些值要通过相机标定和坐标变换换算成机械臂基坐标系下的x,y,z坐标不然机械臂就是对着空气乱抓。这个项目之所以有价值就是因为源码里这套坐标换算逻辑是完整可用的而不是只停在“识别出垃圾”就结束了。再往细说这个系统还牵扯到一个真实世界里的麻烦问题垃圾类别和放置策略的对应关系。识别出来是塑料瓶应该丢进可回收桶识别出来是废电池应该丢进有害垃圾桶。这个映射逻辑写在控制层里识别模块只负责告诉上层“我看到了什么、置信度多少、在画面里的哪个位置”分类决策和执行动作由机械臂控制节点来处理。这种模块解耦的思路是整套架构能跑稳的关键。1.2 技术选型为什么偏偏是YOLOv5和MoveItYOLOv5到今天依然是个非常务实的选择。它不像一些大模型那样需要极端算力一张普通消费级显卡就能跑训练和推理部署到机器人上也只需要推理阶段很多时候CPU都能扛住中低帧率的实时检测。相比更新版本的YOLO系列YOLOv5的生态更成熟网上的资料和预训练模型一大堆遇到问题随便一搜都能找到解决方案。项目里大概率用的是yolov5s或者yolov5m这种轻量级模型在准确率和速度之间取了相对平衡的点对垃圾识别这种类别不算特别复杂的任务来说完全够用。MoveIt这边就更不用说了它就是ROS生态里做机械臂运动规划的标配框架。它把碰撞检测、逆运动学求解、轨迹规划、执行控制全都封装好了你不用自己从头写机械臂的正逆解算法。MoveIt里集成的OMPLOpen Motion Planning Library提供了一堆现成的规划算法比如RRT、RRT-Connect、PRM这些你要做的只是选一个合适的算法并配置好参数。这个项目能放在ROS里跑本身就说明它具备良好的扩展性以后想换不同型号的机械臂只要重新配置URDF模型就能复用大部分代码。注意YOLOv5和MoveIt本身是两个独立的生态项目源码的价值就在于把这两个东西通过ROS的消息机制串联起来。如果你的环境里ROS版本和Python版本对不上后面联调会非常头疼这部分我在第五节会详细说。1.3 系统总体架构与数据流向从整体架构来看这个项目遵循的是“感知-决策-执行”三层结构。感知层跑YOLOv5识别节点订阅摄像头图像话题输出检测结果决策层根据检测结果中的类别信息决定机械臂的目标动作执行层由MoveIt控制真实机械臂或仿真机械臂完成运动。图片从摄像头发布到/camera/image_raw话题上检测节点拿到图像后跑一轮YOLOv5推理把结果整理成自定义消息包含目标的类别、置信度、以及转换后的三维坐标。控制节点收到这个消息后判断目标类别对应的分类桶位置然后调用MoveIt的API规划一条从当前位姿到目标抓取点的路径。机械臂运动到抓取点上方后控制夹爪或吸盘动作完成抓取再规划一段将垃圾投放到分类桶的路径。整个流程就是这样一环套一环源码里每个节点之间分工清晰很适合作为模板去改造自己的项目。2. YOLOv5视觉识别模块从数据集到模型部署的完整链路2.1 垃圾数据集的准备与标注细节模型识别效果的上限不是由网络结构决定的而是由训练数据决定的。垃圾识别领域有几个公开数据集可供参考比如TrashNet、TACO等但这些数据集的类别定义和拍摄环境跟你的实际应用场景可能不完全一致。项目设计文档里大概率也提到了这一点如果条件允许最好的方案是使用你自己的摄像头拍一批目标垃圾的照片再手动标注。标注这一步看着简单但有几个细节直接影响训练效果。第一每张图里的目标要标全不要漏同一类垃圾的标注框尽量贴合物体边缘不要留太多空白背景也不要裁掉物体。第二类别名不要用中文YOLO系列对标签文件名的处理还是用英文字符串最省心比如plastic_bottle,battery,paper之类的后面写代码做类别映射的时候也方便。第三数据集一定要做增强比如旋转、翻转、亮度调整这样训练出来的模型对光线变化和姿态变化更鲁棒。标注工具我见过项目里用LabelImg的居多因为它直接支持导出YOLO格式的txt标签文件省去了格式转换的时间。标注完的数据目录结构最好跟YOLOv5官方要求的保持一致images目录放原图labels目录放对应的txt文件每个txt文件里每一行是class_id x_center y_center width height所有坐标值都归一化到0到1之间。这个格式看着别扭但这是YOLO的基础后面无论是训练还是推理输出解析都依赖于这个约定。2.2 模型训练配置与超参数调整心得训练之前要准备一个自己的数据集配置文件大概长这样train: ./datasets/trash/train/images val: ./datasets/trash/val/images nc: 4 names: [plastic, metal, paper, battery]类别数nc要根据你自己的分类体系改names列表顺序要和标注时候的类别id一一对应顺序错了模型训练再久也是废的。训练命令比较简单网上到处都能抄到python train.py --data trash.yaml --weights yolov5s.pt --epochs 100 --batch-size 16 --imgsz 640这里我想多说一句训练的时候不用一上来就追大模型YOLOv5s的定位是速度和精度的平衡对垃圾识别这种工业场景已经够用。如果发现某个类别的识别效果特别差首先想的不是换大模型而是检查这个类别的样本数量是不是太少。类别不均衡是垃圾识别里最常见的问题比如“塑料瓶”样本特别多、“过期药品”样本特别少训练出来的模型对少样本类别几乎睁眼瞎。解决办法也很实在给少样本类别多补几张不同角度、不同光线条件下的照片或者用离线数据增强把少样本类别复制几份再随机加上噪声、旋转。还有一个操作层面的小技巧训练时可以把--cos-lr和学习率调低让模型收敛更平稳实测下来对小数据集效果不错。2.3 推理部署把检测结果变成机械臂能用的坐标训练完成后模型保存为best.pt在机器人上运行的是这个训练好的权重不再需要训练环境了只需要推理环境。大多数人会用官方提供的detect.py验证效果但真正集成到项目里时往往要写一个自己的推理脚本因为detect.py默认的职责是给图片画框而在机器人项目里我们关心的是结构化数据输出。常见的做法是用YOLOv5提供的API方式来加载模型import torch model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, force_reloadTrue) model.conf 0.5 model.iou 0.45 results model(frame) boxes results.xyxy[0].cpu().numpy()拿到xyxy格式的边界框后取每个框的中心点(cx, cy)再根据像素坐标和实际工作平面的映射关系算出机械臂应该去抓取的三维坐标。这个映射关系在摄像头垂直安装且工作台高度固定的场景下通常可以用一个平面单应性矩阵来实现。如果机位固定你只需要在代码里配置一次标定参数如果摄像头位置动过一定要重新标定。这个环节是整个项目里最容易出问题的地方我后面会专门展开讲。2.4 易混淆类别与真实场景避坑我实测下来的经验是垃圾识别最大的坑不在模型结构而在类别的物理特征本身。透明塑料瓶在强光下会变成一堆高光区域模型很容易把它误判成玻璃揉成团的纸张和浅色塑料也很像还有脏污的金属表面因为反光不均匀经常让模型在金属和塑料之间来回摇摆。如果你也遇到这种问题有几个处理思路可以试试。第一尽量让垃圾桶里的垃圾“看起来”是标准的——拍摄训练集的时候保持垃圾桶干净光线均匀物体完整展开。第二提高置信度阈值比如从0.5调整到0.6宁可漏检也不要误检因为机械臂抓错了东西比抓不到更难处理。第三在分类策略上做兜底如果置信度低于某个阈值机器人不执行抓取动作而是报警提示人工介入。这种保守策略在真实项目里非常重要。3. MoveIt机械臂控制模块运动规划与抓取策略3.1 机械臂模型与URDF配置MoveIt能知道机械臂能怎么动全靠一份机器人的URDF描述文件。URDF里定义了机械臂的每个link、每个关节的类型、关节的运动范围、以及连杆的质量和惯性参数。很多开源机械臂厂商都会提供自己的URDF文件这是基础中的基础。但MoveIt要真正跑起来还需要在URDF基础上用MoveIt Setup Assistant生成SRDF文件SRDF里定义了规划组、预设位姿、虚拟关节这些MoveIt独有需要的配置。规划组这个概念值得多说两句。一个六轴机械臂通常会把所有关节定义成一个规划组比如arm_group这样MoveIt在做运动规划时会同时求解所有关节的目标角度。如果机械臂末端有夹爪你可以把夹爪定义成另一个规划组跟手臂解耦控制。项目源码里MoveIt相关的配置目录一般就是config/文件夹里面放着urdf/,srdf/,joint_limits.yaml,kinematics.yaml这些文件。如果你要换机械臂型号这几个文件基本都要重新生成不过流程是固定的网上教程也很多。提示如果你拿到的URDF文件在RViz里能显示但MoveIt里规划总失败大概率是碰撞检测配置有问题。碰撞检测需要给机械臂每个link加碰撞几何体这个工作可以在Setup Assistant里做虽然繁琐但别跳过。3.2 运动规划流程和核心接口MoveIt在ROS里的核心交互对象是MoveGroupC里是moveit::planning_interface::MoveGroupInterfacePython里是moveit_commander.MoveGroupCommander。项目源码里控制节点的逻辑基本就是围绕这个接口展开的。从代码层面看一个标准的控制流程是这样的先指定规划组然后设置目标位姿Pose再调用plan()求解轨迹最后执行execute()。下面是一段贴近项目实际用法的Python示例import rospy from moveit_commander import MoveGroupCommander rospy.init_node(robot_controller) arm MoveGroupCommander(arm_group) arm.set_pose_reference_frame(base_link) arm.set_planning_time(5.0) # 设置一个目标位姿这里的位置和姿态由视觉模块计算得到 target_pose geometry_msgs.msg.Pose() target_pose.position.x 0.4 target_pose.position.y 0.1 target_pose.position.z 0.3 target_pose.orientation.w 1.0 arm.set_pose_target(target_pose) plan arm.plan() if plan: arm.execute(plan)这里有一点要特别注意arm.plan()只是做规划它找出一条无碰撞的轨迹但机械臂不会动必须调用execute()才会真实执行。另外set_pose_target()本质上是求解逆运动学把末端的目标位姿转换成各关节的目标角度。如果设置的位姿超出了机械臂的工作空间规划直接失败返回空plan。这个错误排查起来非常隐蔽因为代码不会报错只是plan是空的所以你在写控制节点时一定要加判断逻辑。3.3 抓取与投放的轨迹设计抓取动作不是简单的“把末端移过去然后夹住”这个过程中有非常多的实操细节。先说抓取姿态。夹爪不能水平侧着去夹一个瓶子那样受力不均匀容易把瓶子夹飞。常规做法是让夹爪从目标正上方垂下来垂直夹取这样容错率最高。所以视觉模块算出来的目标点最好只是桌面上的一个二维坐标机械臂移动到该点上方的一个固定高度然后垂直下降。抓取路径建议拆成两段先快速移动到目标上方一定高度比如离桌面10厘米的位置再慢速垂直下降边下降边打开夹爪等夹爪触碰到物体后闭合。这样分段有几个好处一是快速移动阶段可以省时间二是慢速下降阶段可以防止机械臂在碰到物体时速度过快导致物体被撞飞。投放也是一样的道理机械臂抓着垃圾移动到对应分类桶的上方然后张开夹爪让垃圾自由落体落进去。这里要注意投放桶的高度和位置不要把桶放在机械臂工作空间的边缘那样规划的路径会很别扭而且夹爪松开后垃圾可能会砸到桶壁上弹出来。3.4 视觉到机械臂的坐标对齐思路这一节是整个项目里最需要耐心的地方也是新手最容易翻车的环节。摄像头看到的是一张二维图像图像的左上角是原点向右是x像素方向向下是y像素方向机械臂的世界里是三维坐标原点在机械臂基座x、y、z是空间坐标。要把图像里的像素坐标映射到机械臂坐标最常用的思路是手眼标定。手眼标定分两种情况摄像头装在机械臂上跟着动叫眼在手上eye-in-hand摄像头固定在外部看机械臂叫眼在手外eye-to-hand。这个项目里摄像头通常是安装在机械臂旁边或顶部的固定位置属于eye-to-hand。标定的目标是求出一个变换矩阵把像素坐标变换成机械臂基座坐标系下的坐标。实际的标定流程会比较繁琐需要用到标定板或者多次对准测试点来拟合映射参数。源码里如果提供了标定脚本一定要先跑通它再去做识别抓取。有一个更朴素的替代方案如果你只检测一个固定平面上的垃圾可以用四点标定法把桌面上四个已知位置的点和图像里的四个像素点对应起来算一个单应性矩阵然后所有检测到的像素点都乘这个矩阵就能得到桌面坐标。这个方案虽然只能做平面抓取但胜在简单可靠这个项目在大多数情况下就是这么用的。4. 系统联调与源码结构解读4.1 源码目录结构与模块划分拿到源码压缩包解压之后我建议你第一件事不是到处点开看而是先看它的目录结构。这个项目的源码结构基本可以映射到整个系统的功能模块上你看懂目录就能在脑子里画出软件架构图。常见的目录组织方式是这样的detect/目录放YOLOv5识别相关的代码和模型权重moveit_control/目录放机械臂控制节点launch/目录放ROS启动文件config/目录放参数配置和机械臂模型doc/或docs/目录放设计文档。如果看到scripts/目录那一般是放辅助脚本比如标定脚本、测试脚本、数据采集脚本。按照这个思路去读代码可以按“检测节点 - 控制节点 - 通信消息 - 主循环”的顺序来看。先搞清楚检测节点发布了什么话题、消息里包含哪些字段再去看控制节点订阅了哪个话题、怎么处理消息里的数据这样整条链路就串起来了。设计文档里一般会有系统架构图和各模块的接口说明它是你读代码时最好的导航图别跳过直接啃源码。4.2 关键通信链路与消息格式ROS项目的核心是节点间的通信通信靠的是话题Topic、服务Service或动作Action。在这个项目里视觉识别节点把检测结果通过自定义消息发布出来控制节点订阅这个消息。你需要在源码里找到自定义消息的定义通常在msg/目录下后缀是.msg文件。我见过一个比较典型的自定义消息格式大概包含这些字段string category float32 confidence float32 x float32 y float32 zcategory是垃圾类别字符串confidence置信度x y z是换算后的机械臂坐标系目标点。这几个字段的设计很合理因为控制节点拿到这个消息后不需要关心识别是怎么做的只需要根据category决定去哪个桶根据x y z设置目标位姿。这种消息设计体现了很好的解耦思想给你的启发是在你自己的项目里消息格式就是模块之间的接口约定一定要提前设计好。除了检测结果话题控制节点通常还会发布一些状态话题比如robot_state用来反馈机械臂当前正在执行的动作或者发布gripper_cmd话题来控制夹爪开合。这些话题在启动之后可以用rostopic echo命令实时查看调试的时候非常有用。4.3 设计文档里最值得先读的部分这个zip包里最值回票价的其实就是设计文档。我强烈建议你在跑通demo之后再精读一遍文档因为那时候你对系统的理解已经有了基础再看文档会豁然开朗。设计文档通常包含几个核心章节需求分析、系统设计、模块设计、测试方案。需求分析章节会告诉你这个项目要解决的原始问题和约束条件比如垃圾种类范围、识别速度要求、机械臂工作空间限制等。系统设计章节会给出总体架构图和数据流图帮你建立全局视角。模块设计章节会深入到每个函数的输入输出和关键算法逻辑这部分是调试代码时的救命稻草。测试方案章节会提供各个模块的验证方法和预期指标你可以照着它检查自己的环境配置是否正常。有一点实战经验想分享跑项目之前先看文档里的“环境要求”部分确认Ubuntu版本、ROS版本、Python版本、PyTorch版本这些硬性条件。版本不匹配导致的怪问题比代码逻辑本身的问题多得多。5. 高概率踩坑点与排查速查5.1 环境版本不匹配的经典故障YOLOv5对PyTorch版本有要求MoveIt对ROS版本也有要求两个体系叠加在一起后环境问题会被放大。最典型的场景是你按教程装了ROS Noetic对应Ubuntu 20.04但项目里的YOLOv5部分代码是基于Python 3.6的写法Ubuntu 18.04上的ROS Melodic默认环境直接跑就会报语法错误或者依赖不兼容。解决这个问题没有银弹只有两个思路一是严格按照设计文档里的环境要求来搭建用系统镜像或Docker把环境固定下来二是遇到报错就耐心去查具体依赖冲突该升级的升级该降级的降级。我在实际操作中更推荐前者因为Docker容器能极大地减少环境折腾的成本而且不会污染你的主系统。提示很多人花了两三天时间排环境结果发现是CUDA版本太新导致旧版PyTorch的算子不兼容。如果你对深度学习环境不太熟悉先用CPU跑通项目流程再去考虑GPU加速这样能把变量控制到最少。5.2 相机标定误差带来的抓取偏移机械臂抓不准十有八九是标定参数出了问题。标定误差的表现很典型识别出来的目标位置偏差很小但机械臂伸过去就是差那么一两厘米夹爪每次都从物体旁边擦过去。遇到这种问题排查顺序建议如下首先确认摄像头有没有被碰歪哪怕稍微歪了一点平面单应性矩阵就会失效其次检查标定板是否还在原来的工作平面上如果有纸张或杂物垫高了目标实际距离和标定距离不一致抓取高度就出问题最后确认机械臂末端的工具坐标系设置是否正确如果夹爪更换过TCPTool Center Point的位置参数必须同步更新否则机械臂认为的“指尖位置”和真实的夹爪位置对不上。还有一个经常被忽略的点就是YOLOv5给出的检测框中心点并不是物体质心在地面上的投影。比如一个长条形的电池检测框的中心点落在电池中间位置但如果你从正上方垂直夹取你希望夹的位置是电池的重心附近而重心和检测框中心在像素上仍然有偏差。处理思路是针对特定物体可以对检测框中心做一个小偏移校正这个偏移量可以通过实测标定出来。5.3 排查流程与速查表我整理了一份自己排查这个项目问题时常用的速查表按“先看软件流程再看硬件状态”的顺序来能帮你少走很多弯路。现象优先排查点常规解决方案检测节点不输出结果摄像头话题是否发布模型路径是否正确rostopic list查看话题检查权重文件是否存在识别结果有框但抓不到坐标变换参数不匹配重新标定检查像素坐标到机械臂坐标的映射矩阵机械臂规划失败目标点超出工作空间碰撞检测误报修改目标点坐标检查URDF/SRDF的碰撞模型配置机械臂运动抖动算力不足导致规划节流降低识别帧率给控制节点提高线程优先级夹爪夹不准TCP参数不匹配夹爪开合力度不够更新工具坐标系参数调整夹爪开合限位运行一段时间后节点崩溃内存泄漏话题消息队列堆积检查订阅回调是否有队列溢出适当降低发布频率排查的时候记住一个原则优先用ROS自带工具。rosnode info看节点状态rostopic echo看消息内容rqt_graph看节点连接关系。看到消息里坐标值明显不对再去怀疑标定看到节点直接没有连上先查启动文件的参数有没有写错。大部分问题用这几个命令就能定位到具体环节。5.4 从“能跑”到“跑得稳”的调优建议项目跑通之后如果你还有余力可以往这几个方向优化。第一识别速度。YOLOv5推理在CPU上可能需要几百毫秒一帧整个流程下来机械臂等待时间很长可以用TensorRT或ONNX Runtime把模型加速识别延迟能降到一二十毫秒。第二运动速度。MoveIt规划出来的轨迹默认比较保守你可以在运动规划参数里调高速度缩放因子让机械臂走快一些但要注意不要让机械臂在高速运动下丢步或震动。第三异常处理。当前端识别到异常类别或置信度过低时最好让机器人进入一个安全状态而不是盲目执行抓取。另外一点实操体会调试的时候千万不要直接用真实机械臂反复测试极限位置很容易撞到工作台或者夹坏东西。先在RViz仿真环境里把整个流程跑通确认轨迹没有碰撞风险再切换到真实机械臂。很多项目出问题都出在仿真和真实环境之间的参数差异上比如仿真的机械臂关节限位和真实机械臂不一样所以在切换前要仔细核对配置文件。我的经验是这个项目本质上是一个“视觉控制”的集成典范。很多毕设项目只做识别很多机械臂项目只做运动规划真正把两者打通并做成完整产品闭环的案例并不多。如果你能把这个项目从头到尾吃透你收获的不仅是几个API怎么调用更是一整套“如何让机器人在真实世界里干活”的工程方法论。后面如果你想扩展功能比如加入语音交互来提示垃圾类别、加入多机械臂协同或者把识别网络升级成更新的结构这套架构也都能顺滑地扩展出去。本文还有配套的精品资源点击获取
返回列表