简介:面向机械臂视觉平面抓取任务的 Python 源码工程,基于 GRCNN 残差卷积神经网络完成抓取位姿估计与执行,适合计算机、电子信息等专业用于课程设计、期末大作业、毕业设计或算法研究。项目覆盖深度相机数据读取、相机标定、抓取生成、模型训练与机械臂控制等环节,目录按 inference、models、hardware、utils、data 等模块拆分,便于定位和二次开发。
压缩包共包含 88 个文件,以 34 个 Python 脚本为主体,涵盖训练、离线评估、实时推理、抓取生成与标定流程;另有 Shell 数据获取脚本、配置文件、说明文档、效果图片和 2 篇相关论文 PDF,并在 trained-models 中提供 Cornell 与 Jacquard 数据集的预训练权重。整体大小约 72.49MB,结构清晰。
目前已有 310 人学习下载。下载后可直接参考项目说明运行,借助预训练模型快速复现视觉平面抓取流程;也可替换数据集、调整网络参数继续训练,适合需要完整工程代码和真实抓取验证场景的研究者与学生。
1. 为什么平面抓取检测要从矩形框回归转向GRCNN
机械臂平面抓取看起来是个小问题:从桌面上识别物体,算出夹爪以什么角度、在哪个点闭合。但真正跑起来就知道,传统“先检测物体再估计抓取点”的思路在复杂形状和堆叠场景下很脆,因为检测框表述的是物体范围,而不是夹爪能稳定施力的位置。GRCNN把整张RGB-D图映射为像素级的抓取质量图、角度图和宽度图,相当于让网络直接回答“每个像素点是不是好的抓取中心”。资源里cornell和jacquard两组预训练模型的完整python源码,覆盖从数据下载、训练到RealSense实时推理的全流程。
对做机器人视觉或可靠性调试的工程师来说,这套代码的价值在于你能同时看到离线评估和在线抓取两条链路,而不只是一个孤立的模型文件。它也适合作为课程设计或毕设项目的参考资料,用来理解抓取检测与机械臂控制的完整衔接方式。
2. GRCNN的抓取表示与生成式残差网络结构
2.1 抓取矩形为什么用五维参数
平面抓取通常用五个量描述一个抓取矩形:中心坐标(x,y)、夹爪朝向角度θ、开口宽度w、矩形高度h。平行板夹爪稳定抓取的前提是两个夹爪面都与物体产生接触,且接触力近似对称。传统目标检测得到的边界框描述“物体在哪里”,而抓取矩形描述“夹爪应该怎么放”,两者经常出现很大偏移。GRCNN在每个像素位置都生成一个抓取假设,然后用质量图表示该假设的可靠程度。这比先生成候选框再做分类回归的结构更简洁,也更容易在嵌入式设备上跑实时推理。
实现里,models目录下的grconvnet3就是为这个目标设计的。后处理只提取质量图的局部峰值,而不是像检测网络那样做多框NMS,所以整个链路的计算开销集中在encoder-decoder上,后端优化空间很大。如果你之前调过YOLO系检测器,会明显感到这里少了很多anchor调参,训练时只需要关注质量阈值和角度分辨率。
2.2 输入四通道与输出三通道的语义
网络输入是R、G、B、D四个通道,其中D是深度图,通常先裁剪到有效范围再归一化到[0,1]。输出是三个通道:
- 质量图Q:每个像素作为抓取中心的置信度;
- 角度图:用cos(2θ)和sin(2θ)两个通道编码;
- 宽度图W:夹爪开口宽度,单位是像素。
角度用2θ编码是容易踩坑的地方。如果直接回归θ,0度和180度在数值上相差很大,但物理上完全等价,网络会在边界处产生很大的梯度噪声。编码成cos2θ和sin2θ之后,角度差转成三角函数空间的距离,训练稳定很多。后处理中解码角度的语句通常是angle = np.arctan2(sin_pred, cos_pred) / 2。在调试时,如果发现预测角度总是相差90度,先检查解码时是否忘了除以2。
2.3 损失函数的代码形态
Cornell数据集的标注是稀疏的抓取矩形,要让每个像素都参与训练,需要把稀疏标注展开成稠密的热力图。损失函数的关键代码如下:
def compute_loss(q_pred, cos_pred, sin_pred, w_pred, q_label, cos_label, sin_label, w_label, valid): loss_q = torch.mean((q_pred - q_label) ** 2) loss_angle = torch.mean(((cos_pred - cos_label) ** 2 + (sin_pred - sin_label) ** 2) * valid) loss_width = torch.mean(((w_pred - w_label) ** 2) * valid) return loss_q + loss_angle + loss_width逻辑说明:质量图使用全图L2,让网络学会输出平滑置信度;角度和宽度只在标注有效区域计算损失,valid是深度图有效掩码,可以避免空洞深度值干扰。参数说明:三个loss直接相加,没有额外权重,因为实际测试中三者量纲接近,普通L2即可收敛。如果发现角度输出震荡,优先检查valid是否正确剔除了深度为零的区域;深度图中黑边像素如果没被mask掉,角度损失会被无效区域带偏。
2.4 两类数据集的差异决定训练策略
下载脚本get_cornell.sh和get_jacquard.sh对应两种完全不同的数据来源。Cornell是真实传感器采集,数量少但真实感强;Jacquard来自物理仿真,数量大且标注精确,但存在sim-to-real gap。选择哪个数据集要根据你的部署环境来定。
| 数据集 | 样本规模 | 标注来源 | 典型使用场景 |
|---|---|---|---|
| Cornell | 约8000张RGB-D | 人工标注抓取矩形 | 单物体桌面、实验室验证 |
| Jacquard | 5万+张深度图 | 仿真自动生成 | 多物体抓取、训练更稳定模型 |
在实际项目中,我一般先用Jacquard预训练,再用Cornell微调。这样既能利用仿真数据的规模,又能把模型拉回真实图像分布。dataset_processing里生成训练样本时,随机旋转和裁剪是默认开启的,这能有效提升角度估计的泛化能力。注意下载时保持目录结构一致,run_offline.py会按固定相对路径读取图片和标注。
3. 工程走读:从相机标定到抓取生成的完整链路
3.1 相机标定决定抓取坐标的准确性
hardware目录下的run_calibration.py同时处理相机内参标定和外参获取。GRCNN输出的抓取点是在图像像素坐标系下的,要变成机械臂能执行的坐标,必须先通过内参转成相机坐标系,再通过手眼矩阵转成机械臂基座坐标系。标定这一步省了,之后所有抓取点都会系统性偏移。
python run_calibration.py --source camera --pattern 9x6 --square 0.025 --save camera_params.npz逻辑说明:--source camera表示使用实时相机流采集棋盘格图像,--pattern 9x6指定内部角点数量为9列6行,--square 0.025是棋盘格单格边长25mm。脚本会在检测到足够多角点后计算内参矩阵与畸变系数,并保存为npz文件。如果只用离线图片,可以把--source换成图片文件夹路径。
参数说明:内参矩阵中的fx、fy、cx、cy决定像素坐标与相机坐标的换算关系。畸变系数不矫正的话,图像边缘的抓取点位置误差很容易超过5mm,对小型夹爪来说已经是很大的偏差。标定完内参后,还需要用棋盘格或ArUco标定板做手眼标定,得到相机到机械臂末端的变换矩阵。这一步在源码里没有完整实现,通常作为外参配置保存在JSON文件中供camera.py读取。
3.2 RealSense深度流对齐
get_realsense_rgbd_image.py专门处理深度图和彩色图的对齐问题。如果直接读取原始深度流,深度图的坐标系与RGB图像不一致,后续把抓取点的像素坐标映射回三维空间时会直接出错。以下是对齐的核心代码:
import pyrealsense2 as rs pipeline = rs.pipeline() config = rs.config() config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30) config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30) pipeline.start(config) align = rs.align(rs.stream.color) frames = pipeline.wait_for_frames() aligned = align.process(frames) depth = aligned.get_depth_frame() color = aligned.get_color_frame()逻辑说明:先分别开启彩色和深度流,再用rs.align(rs.stream.color)构造对齐器,将深度图投影到彩色相机视角下。这样返回的depth与color像素一一对应。参数说明:这里分辨率统一设置为640×480,后续模型输入裁剪到224×224;不建议直接以低分辨率运行深度流,因为深度传感器在低分辨率下会增大噪声,影响宽度回归的稳定性。
拿到对齐后的RGB-D序列后,还需要做深度滤波。常见做法是对深度图做中值滤波,再用形态学闭运算填补小的空洞。否则,透明塑料瓶、黑色橡胶这类物体在深度图上会出现大量无效像素,GRCNN会把这些空洞当作极近距离物体,产生错误的抓取点。这里要特别注意深度值的单位,RealSense返回的深度默认是毫米,喂给网络前要除以1000并截断到0~1米之间。
3.3 抓取生成器的调用方式
run_grasp_generator.py是离线推理和实时推理共用的入口。它加载预训练模型,对输入的RGB-D图像执行前向推理,再通过post_process.py把原始预测转换成具体的抓取矩形集合。
python run_grasp_generator.py \ --model trained-models/cornell-randsplit-rgbd-grconvnet3-drop1-ch32 \ --rgbd rgbd.npy \ --output grasps.npy逻辑说明:rgbd.npy是四通道输入数组,grasps.npy保存后处理得到的多个抓取候选。候选按质量分从高到低排列。参数说明:drop1是训练时的dropout概率,ch32是网络初始通道数。cornell-randsplit模型在单物体桌面上表现稳定;jacquard-rgbd模型对多物体场景更鲁棒。
后处理过程中有两个关键参数:质量阈值和角度分辨率。质量阈值控制什么置信度的抓取点可以执行,质量阈值太低会频繁抓空;角度分辨率控制局部极大值检测时角度的离散步长,默认取20度一格就够用,过细会让多次检测结果抖动。post_process.py里还包含一个去重逻辑,会删除中心距离小于15像素的重复抓取点,这个距离阈值也要根据相机安装高度调整。
3.4 离线评估指标怎么看
evaluate.py在数据集上跑模型,计算预测抓取矩形与标注矩形的重合度。常用的评估指标如下:
| 指标 | 计算方式 | 合理通过线 |
|---|---|---|
| Rectangle Metric | 预测与标注矩形的角度差、中心距离、宽度差加权 | > 0.8 |
| 单次抓取成功率 | 夹爪闭合后物体保持不掉落 | > 80% |
Rectangle Metric是论文里最常用的指标,但它只衡量抓取矩形与标注的几何相似度,并不代表真实机械臂一定会成功。见过很多模型在Cornell上指标很高、上机械臂却抓不住的情况,主要原因是评估时没有考虑物体表面摩擦力和夹爪动力学。因此,可靠的做法是把evaluate.py的分数作为粗筛条件,真机验证作为最终结论。在跑评估前,先确认数据集的划分方式保持一致,否则不同模型之间没有可比性。
4. 训练、迁移与坑点:让GRCNN在你的场景里可用
4.1 train_network.py 的核心参数
train_network.py负责完整训练流程,包括数据加载、增强、训练循环和checkpoint保存。关键命令行参数如下:
python train_network.py \ --dataset cornell \ --dataset-path data/cornell \ --model grconvnet3 \ --epochs 50 \ --batch-size 32 \ --lr 1e-3 \ --dropout 0.1 \ --channel-size 32逻辑说明:--dataset选择数据集格式,--model指定模型结构,--channel-size控制第一层卷积通道数,所有后续层通道数会按倍数扩展。--dropout在网络末端和解码器部分生效,用来抑制过拟合。Jacquard数据集比较大,建议先按data/get_jacquard.sh下载并转换,再替换--dataset jacquard。
参数选择上,常用配置如下:
| 参数 | 推荐范围 | 对结果的影响 |
|---|---|---|
| channel-size | 16 / 32 / 64 | 通道越多拟合能力越强,但推理变慢 |
| dropout | 0.1(低噪声数据) / 1(噪声大) | 太高会让模型欠拟合 |
| lr | 1e-3起,20轮后降为1e-4 | 学习率过大角度损失震荡 |
| batch-size | 16 / 32 | 受限于显存,太小则梯度噪声大 |
我一般会先用channel-size=16跑通流程,确认数据流水线没问题,再用32训练正式模型。一上来就用64通道会浪费很多时间在调试数据问题上。训练过程中建议每个epoch结束都保存一次checkpoint,避免训练中断后从头再来。
4.2 预训练模型的命名规则
trained-models目录里的模型名称包含了完整配置信息,例如cornell-randsplit-rgbd-grconvnet3-drop1-ch32:
cornell:训练数据集;randsplit:随机划分训练验证集;rgbd:输入为对齐后的四通道RGB-D;grconvnet3:模型结构版本;drop1:dropout率为0.1;ch32:基础通道数为32。
理解命名规则后,选择模型就不会只看目录大小。如果部署环境是常见的桌面单物体抓取,cornell-randsplit-rgbd-grconvnet3-drop1-ch32是第一选择;如果场景有堆叠或遮挡更严重,优先尝试jacquard-rgbd-grconvnet3-drop0-ch32。这些模型可以直接被run_grasp_generator.py加载,不需要额外转换格式。
4.3 部署时的三个主要偏差来源
第一个是坐标系偏差。GRCNN输出的是像素坐标,要经过相机内参、手眼矩阵、机械臂基座三跳转换。每一步的误差都会线性叠加。做手眼标定时,我习惯把棋盘格在机械臂工作空间内移动十个不同位姿,计算重投影误差,若超过0.5mm就重新标定。像素坐标到机械臂坐标的转换可以写成下面这段代码:
def pixel_to_robot(u, v, depth, K, T_cam_to_robot): z = depth[v, u] / 1000.0 x_cam = (u - K[0, 2]) * z / K[0, 0] y_cam = (v - K[1, 2]) * z / K[1, 1] p_cam = np.array([x_cam, y_cam, z, 1.0]) p_robot = T_cam_to_robot @ p_cam return p_robot[:3]逻辑说明:先由深度值和相机内参把像素坐标转换为相机坐标系下的三维点,再通过手眼矩阵T_cam_to_robot变换到机械臂基座坐标系。参数说明:深度值在RealSense里单位是毫米,需要除以1000变成米;T_cam_to_robot是4x4齐次变换矩阵,来自手眼标定结果。如果直接把这个矩阵当3x3旋转矩阵用,抓取点会在某个方向上产生固定偏移。
第二个是深度图噪声。真实相机的深度在物体边缘会跳动,在黑色表面会缺失。网络训练时使用的是仿真或精心处理过的干净深度图,上线后直接喂原图会让质量图出现很多假峰。解决方案是在输入网络前做一次中值滤波,并在后处理时把深度异常值对应的像素质量分强制降为0。
第三个是机械臂偏差。这个问题在“机械臂抓取”类项目里最容易被忽略。机械臂出厂运动学参数与真实结构之间总存在微小偏差,表现为夹爪实际到达位置与理论坐标差几毫米。对于小型夹具,这个偏差直接导致抓取点从物体表面滑脱。解决办法是手动示教几个点,计算固定偏移量并补偿到最终坐标中。如果你用的是ur10这类工业臂,想把抓取指令发给机械臂,需要把grasp_generator的输出转换成机械臂基座坐标后,再通过ROS的trajectory接口执行;这个源码包里没有ROS封装,但坐标格式是通用的,写一个发布节点把目标位姿发到/arm_controller/goal话题即可。
4.4 训练完成后的检查清单
模型训练完成后,先不要直接上真机。用验证集跑一遍evaluate.py,确认Rectangle Metric在0.85以上。然后录制一段真实相机的RGB-D序列,离线运行run_grasp_generator.py,把抓取矩形画在图像上肉眼检查。最后再进入实时环路。确认无误后再把模型替换进run_realtime.py,此时剩下的就只是机械臂执行层的参数调试了。
5. 进阶:影子测试与抓取失败排查
5.1 影子测试:不启动机械臂也能验证算法
在把抓取代码和机械臂接起来之前,可以先做“影子测试”。用get_realsense_rgbd_image.py录制一段包含目标物体的深度与彩色序列,保存成npy文件,然后循环运行run_grasp_generator.py,把生成的抓取矩形叠加到原图上。这样能发现大量明显问题,比如角度方向反了、宽度超过夹爪最大开口、质量图峰值偏到背景上。影子测试的成本极低,却能避免机械臂空跑带来的风险。没有实体机械臂时,还可以先加载仿真环境验证坐标转换,但仿真深度图过于理想,不能替代真实传感器测试。
import numpy as np rgbd = np.load('scene.npy') # 调用 grasp_generator 得到候选 grasps = generator.predict(rgbd, threshold=0.8) for g in grasps: print(g.x, g.y, g.angle, g.width, g.quality)逻辑说明:threshold=0.8表示只保留质量分大于0.8的候选点,输出结果可以直接用来判断是否满足机械臂执行条件。参数说明:如果打印出来的候选点数量为0,说明当前场景太复杂,需要降低阈值或调整相机角度;如果候选点角度几乎都在同一方向,说明输入图像中桌面纹理被误判断为物体边缘。
5.2 抓取失败模式的快速定位
真机抓取失败时,不要急着调网络参数,先区分失败环节属于哪一层。是图像没看清,还是坐标算错,又或者是机械臂执行时偏差,处理方式完全不同。可以从下面的表开始对照。
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 夹爪落在物体旁边 | 相机外参偏差或机械臂偏差 | 检查手眼矩阵,手动示教补偿 |
| 夹爪碰到物体但抓不起来 | 宽度回归过大或过小 | 检查宽度通道输出,对比物体实际尺寸 |
| 抓取点飘在背景上 | 深度图空洞或质量阈值太低 | 提升threshold到0.85,检查深度滤波 |
| 角度明显反向 | 相机坐标系与机械臂坐标系方向约定不一致 | 在固定点放置标记物,验证旋转方向 |
这个表基本覆盖了视觉平面抓取上线后80%的现场问题。角度反向是最隐蔽的一种,因为离线测试时看起来图像上矩形是正的,但机械臂执行时由于坐标轴转置,180度翻转后夹爪正好与物体平行相切。遇到这种情况,只需在抓取点坐标转换时对角度进行坐标系变换,不要直接在像素坐标系下调节。
最后一点:在机械臂执行前,把质量分低于0.85的候选点全部丢弃。虽然单帧召回率会下降,但整体抓取成功率通常反而更高,因为低置信度抓取点造成的失败代价远大于多等一帧的代价。
本文还有配套的精品资源,点击获取