资讯动态

YOLOv3结合ROS的实时目标检测与机械臂抓取角度回归实践

发布时间:2026/9/15 5:44:29 来源:尧图企业网站定制
简介面向ROS开发者的YOLO实时目标抓取检测功能包将YOLOv3物体检测与机械臂抓取相结合可在Ubuntu 16.04/18.04、ROS Kinetic/Melodic环境下运行。包内覆盖物体检测、旋转角度抓取、Gazebo实时螺丝检测与抓握、零件排列机器人等典型场景适合机器人抓取、视觉分拣方向的工程师和研究者快速搭建原型。资源共129个文件压缩包30.15MB核心文件类型包括多个yolov3系列模型cfg配置、launch启动脚本、Python与C节点源码、yaml参数配置、msg消息定义、训练权重放置说明等配置和代码分离便于针对自己的相机和机械臂进行二次修改同时还配有备份文件与Markdown说明便于追踪版本改动和梳理运行逻辑已有69人学习。整体提供较完整的YOLOv3_ROS检测实现含依赖安装、模型配置、Gazebo仿真运行等说明可帮助读者理解从目标检测到抓取角度估计的完整流程。对于需要复现实时抓取检测、改造抓取角度算法或扩充识别类别的ROS项目这套包能提供直接可参考的工程结构。1. 为什么把 YOLOv3 塞进 ROS 抓取流水线机械臂抓取这件事难的不是识别出“这里有个螺丝”而是要在几十毫秒内同时给出“螺丝在哪、旋转了多少度、该从哪个角度伸进去”。常见的做法是把目标检测和位姿估计拆成两个独立模块先跑一个目标检测网络再用点云或模板匹配算角度延迟高不说两个模型各自的误差还会叠加。这个 YOLO 实时目标抓取检测 ROS 包直接把角度回归头挂在了 YOLOv3 的检测分支上输入 RGB 图像就同时输出目标的类别、边界框和旋转角在 Gazebo 里实测螺丝抓取场景可以做到实时。适合手里有 ROS 机器人、想绕开传统视觉库抓取方案的开发者也适合刚接触深度学习抓取、想找一个能跑通的参考实现的人。2. YOLOv3_ROS 包结构与检测原理拆解2.1 从 .action 到 image_interface消息链路怎么走包里的CheckForObjects.action定义了抓取检测的动作接口注意它不是 ROS 里常见的srv而是actionlib格式。action 的优点是客户端发起请求后可以持续收到反馈目标抓取场景里机械臂需要一边接近物体一边根据视觉反馈修正末端位姿用 action 比用 service 更合理。定义里通常包含三部分# CheckForObjects.action # 请求部分 sensor_msgs/Image image --- # 结果部分 yolov3_pytorch_ros/BoundingBoxes bounding_boxes float32 grasp_angle --- # 反馈部分 float32 progress代码逻辑上image_interface.c负责把 ROS 图像话题转换成网络输入。它做的事情很具体先从sensor_msgs::Image里拷贝图像数据再通过cv_bridge转成 OpenCV 的Mat最后按照 YOLO 的 letterbox 方式把图像等比例缩放到 416×416 或 608×608多余部分用灰度填充。这里最容易出错的是图像编码如果相机输出的是BGR8而网络训练时用的是RGB检测结果会明显变差所以image_interface.c里都有一个cvtColor的开关默认不开启需要根据你的模型训练数据手动改。2.2 cfg 文件与权重匹配yolov3.cfg 为什么会出现三次项目里罗列了yolov3.cfg、yolov3-voc.cfg、yolov3-cai.cfg、yolov2.cfg其实这些是针对不同训练数据集的网络结构定义。yolov3.cfg是 COCO 80 类yolov3-voc.cfg是把最后的 80 类改成 20 类yolov3-cai.cfg是这个抓取包自定义的数据集配置通常只有一类或两类比如“螺丝”“垫片”。很多人在这一步踩坑把从网上下载的yolov3.weights和yolov3-cai.cfg混在一起加载结果cfg里的filters数量跟权重文件不匹配程序直接段错误。核心规则是cfg文件里每个yolo层前面的卷积层filters 3 × (classes 5)。如果classes1filters 就是 18classes20filters 就是 75。修改自定义数据集时只要改了classes就必须同步改掉最后一个卷积层的 filters否则 Darknet 在读取权重时会因为维度对不上而报错。源码里加载模型使用的是torch.load配合yolov3_pytorch_ros的权重映射函数所以如果你用官方 Darknet 权重得先转成 PyTorch 格式或者直接用包自带的转换脚本。2.3 旋转角度从哪里来抓取检测的“多一个头”设计普通 YOLOv3 的输出是一个张量每个网格预测边界框的 x、y、w、h 和类别概率。这个抓取包在原输出的末尾追加了一个角度预测分支输出的是目标在图像平面内的旋转角 θ。角度不是直接回归一个绝对值而是用两个分量sin θ和cos θ表示这样避免角度在 -180° 和 180° 交界处发生跳变模型更容易收敛。# 角度分支的损失计算示意 import torch import torch.nn.functional as F angle_pred model_output[..., 4] # 假设第5个通道是角度分量 angle_target torch.atan2(sin_target, cos_target) # 用atan2还原角度 loss_angle F.smooth_l1_loss(angle_pred, angle_target, reductionmean)这里没有直接对角度做分类而是回归连续值因为实际抓取场景中螺丝的旋转角度是任意的离散化会引入量化误差。推理时拿到sin θ和cos θ后用atan2还原真实角度再通过相机内参和手眼标定把图像平面的角度映射到机器人基座坐标系。需要注意这个角度是绕着相机光轴旋转的如果相机安装倾角不是零需要先做旋转矩阵补偿。3. 从零编译与运行catkin_make 与依赖安装实操3.1 环境准备Ubuntu 18.04 ROS Melodic 的版本核对这个包在 Ubuntu 16.04 ROS Kinetic 和 Ubuntu 18.04 ROS Melodic 上都能跑但不建议直接用最新版 Ubuntu 22.04因为cv_bridge对 OpenCV 版本的绑定比较敏感。Melodic 默认带的 OpenCV 是 3.2而 YOLOv3 PyTorch 推理部分往往会拉一个较新的 OpenCV 到自定义环境里两套版本混在一起就会引出Symbol not found的问题。如果只是做抓取仿真我一般会用 Melodic Python 3.6 PyTorch 1.4 左右的组合兼容性最稳。依赖安装可以直接用项目里的requirements.txt但建议先按下面顺序验证基础环境# 先确认ROS环境再装Python依赖 source /opt/ros/melodic/setup.bash python3 -m pip install --upgrade pip cd yolov3_pytorch_ros sudo pip3 install -r requirements.txtrequirements.txt里通常会锁torch、torchvision、opencv-python、numpy的版本。如果你本机已经有 TensorFlow 之类的大依赖建议用python3 -m venv建虚拟环境但注意虚拟环境里的 Python 版本必须与 ROS 的cv_bridge编译所用的 Python 一致否则导入cv_bridge时会报ModuleNotFoundError。我实际遇到最多的问题是torch装成了 CPU 版检测速度直接掉到每秒 5 帧以下所以要去 PyTorch 官网选cu101或cu102对应的版本。3.2 catkin_make 编译与两个典型报错编译前先确认工作区里只有一个yolov3_pytorch_ros包避免和其他包重名。执行cd ~/catkin_ws catkin_make yolov3_pytorch_ros source devel/setup.bash注意这里用的是catkin_make加包名因为工作区里可能还有别的包只编译目标包会快很多。第一个典型报错是找不到yolov3_pytorch_ros/CheckForObjectsAction.h原因是catkin_make还没生成 action 消息头文件。解决方法是先单独编译消息生成catkin_make generate_messages第二个报错是libopencv_core.so.3.2: cannot open shared object file常见原因是系统里有多个 OpenCV 版本CMake 找到了/usr/local/lib下的 4.x 库而cv_bridge链接的是 3.2。查看当前链接关系ldd devel/lib/yolov3_pytorch_ros/*.so | grep opencv如果看到libopencv_core.so.4就得在CMakeLists.txt里显式指定 OpenCV 路径set(OpenCV_DIR /usr/lib/x86_64-linux-gnu/cmake/opencv3)改完后重新catkin_make注意先删掉build目录里旧的 CMake 缓存。3.3 启动检测节点话题与参数表运行前把权重文件放进models文件夹yolov3_cai.weights要跟yolov3-cai.cfg对应上。启动命令roslaunch yolov3_pytorch_ros detect.launch image_topic:/camera/rgb/image_rawdetect.launch里有一组常用参数我一般会这样调整参数名默认值说明image_topic/camera/rgb/image_raw输入图像话题pub_topic/yolov3/detections检测结果话题model_configyolov3-cai.cfg网络结构文件weights_fileyolov3_cai.weights权重文件conf_threshold0.5置信度阈值抓取场景建议 0.7nms_threshold0.4非极大抑制阈值grasp_angle_ontrue是否输出抓取角度启动后可以用rostopic echo /yolov3/detections查看输出一条消息里会包含多个BoundingBox每个框带xmin、ymin、xmax、ymax、class_name、probability和grasp_angle。grasp_angle的单位是弧度范围在 [-π, π]。4. Gazebo 仿真与螺丝抓取实测4.1 搭建随机排列的螺丝场景Gazebo 仿真环境中实时螺丝旋转检测通常要在模型里加入摩擦系数和表面纹理否则视觉检测没问题但机械臂一碰就滑走。先在 urdf 里给螺丝的圆柱面加friction参数同时用sensor_msgs/CameraInfo标定仿真相机内参。流程是启动 Gazebo 世界加载螺丝模型用随机分布插件把 812 个螺丝放到传送带或桌面上然后启动相机驱动节点。# 启动仿真环境与相机 roslaunch gazebo_ros empty_world.launch roslaunch screw_grasp_gazebo spawn_objects.launch rosrun image_transport republish compressed in:/camera/rgb/image_raw raw out:/camera/rgb/image_decoded相机输出的原始话题如果开了压缩YOLO 节点可能会收到compressed格式image_interface.c默认不处理所以要先用image_transport解压。这里我建议直接在 launch 文件里把image_transport设成raw减少中间环节。4.2 旋转角度检测的坐标变换检测出的grasp_angle是图像坐标系里的角度要变成机械臂能用的抓取角必须做两步变换。第一步是去畸变仿真相机没有畸变但真实相机一定要先用camera_calibration标定否则边缘目标的抓取角度会偏 5° 以上。第二步是手眼标定把相机坐标系下的角度转到机械臂基座坐标系常见做法是用ar_track_alvar做一个标定板通过tf2拿到相机到机械臂末端的变换矩阵。实际操作里经常会发现检测框中心点与螺丝实际重心不重合导致抓取位置偏移。这是因为 YOLOv3 的边界框是轴对齐的而螺丝旋转后框会包含大量背景。可以用角度信息把边界框反向旋转在旋转后的框内重新找质量中心质心再映射回原图import cv2 import numpy as np # rect: (cx, cy, w, h, angle) 来自YOLO输出 cx, cy, w, h, angle 320, 240, 80, 20, 0.61 M cv2.getRotationMatrix2D((cx, cy), angle * 180 / np.pi, 1.0) # 旋转四个角点 corners np.array([[cx - w/2, cy - h/2], [cx w/2, cy - h/2], [cx w/2, cy h/2], [cx - w/2, cy h/2]]) rotated_corners cv2.transform(np.array([corners]), M)[0]这段代码先把原始框的四个点按检测角度旋转得到的rotated_corners就是贴合螺丝轮廓的四个角点取这四个点的均值作为抓取点比直接用框中心稳定很多。4.3 抓取点可视化的验证方法调参时如果每次都把机械臂伸下去试效率太低。我一般会先发一张叠加了抓取角度的可视化图用image_view或rqt_image_view直接看rostopic echo /yolov3/grasp_vis -n 1可视化节点会把每个检测框画出来并且在中心点画一条射线方向就是抓取角度。验证标准是射线必须穿过螺丝的长轴也就是螺丝两端连续的方向。如果射线歪了优先检查grasp_angle的分量符号很多模型的sin θ输出在 [-1,1] 没归一化导致角度膨胀可以在后处理里加个tanh限制。更稳妥的方法是手动把相机图像保存下来离线跑一次检测把结果跟 OpenCV 的minAreaRect做对比minAreaRect算出的角度可以作为 ground truth 来校准网络输出。5. 调参与进阶自定义数据集训练与抓取角度修正5.1 训练自己的 YOLOv3 模型并替换权重如果只抓螺丝默认权重够用换成轴承、芯片或其他零件时就要训练自己的模型。这个 ROS 包的检测部分兼容 Darknet 权重所以你可以用 YOLOv3 训练自己的数据集后转成 PyTorch 格式。标注时除了画矩形框还要额外给每个目标标一个旋转角这个包使用的标注格式是class_id x_center y_center width height angle其中angle单位是弧度。可以用 LabelImg 加一个角度插件来标注或者写个脚本根据掩膜计算minAreaRect自动生成角度。训练命令不在这里展开但有一个重要原则抓取用的检测模型角度分支的 loss 权重不要给太大否则网络会牺牲边界框精度去拟合角度。我一般把角度 loss 权重设为0.5边界框 loss 权重保持1.0。训练到第 50 轮左右先用下面的脚本检查角度误差python3 tools/eval_angle.py --weights yolov3_cai.weights --img_dir ./val_images --gt_dir ./val_labelseval_angle.py会输出平均角度误差MAE正常应该在 5° 以内超过 10° 说明标注噪声太大或者角度分支没有收敛。需要检查标注时是不是把“螺丝头方向”和“螺纹方向”搞混了这两个方向相差 180°网络没法区分会导致损失震荡。5.2 与鱼香ROS环境集成的坑很多人在 Ubuntu 18.04 上装 ROS 时用的是鱼香ROS一键安装脚本装完后 ROS 环境没问题但 OpenCV 会被脚本里的libopencv-dev升级到 4.x。此时直接编译这个 YOLO 包会撞上cv_bridge的 OpenCV 版本不匹配。解决办法是重新安装 Melodic 自带版本的cv_bridgesudo apt remove ros-melodic-cv-bridge sudo apt install ros-melodic-cv-bridge1.13.0-0*装完后再检查pkg-config --modversion opencv如果还是 4.x可以在CMakeLists.txt里把find_package(OpenCV 3 REQUIRED)改成find_package(OpenCV 3.2 REQUIRED)。编译过一次成功后后续每次重新编译前先source /opt/ros/melodic/setup.bash避免找不到roslib。5.3 快速验证抓取成功率的脚本最终验证不能只看可视化要统计真实抓取成功率。最简单的方法是写一个 ROS 节点订阅检测结果并在机械臂执行抓取后读取力传感器数值rostopic echo /gripper/force -n 50 | grep force | awk {sum$2} END {print sum/NR}如果力矩平均值大于设定阈值就认为抓取成功。把检测角度和实际抓取位姿记录下来跑 50 次后按角度误差分段统计成功率你会发现误差小于 3° 时成功率超过 95%大于 10° 时成功率直接掉到 60% 以下。针对角度误差大的样本常见做法是加一个角度卡尔曼滤波用前后几帧的角度做平滑因为螺丝静止时角度不应该突变。最后一个小技巧相机帧率不需要太高YOLO 推理 15fps 足够但曝光时间要手动固定曝光自动调节时暗部螺丝的边界框会抖动带动角度输出一起跳。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价