尧图精选

基于CNN的机械臂抓取位置检测:从模型训练到部署实践

🕒 发布时间:2026/9/19 15:44:16 📁 来源:尧图网络
简介这份PDF收录了发表于《计算机测量与控制》的学术论文面向机器人、深度学习和计算机视觉方向的研究者与工程师聚焦如何用CNN解决复杂环境下抓取位置检测精准度低的问题。文中给出了完整的检测流程依据切线斜率划分模板点并计算匹配距离引入GA算法寻优将彩色图像和深度图像中的可抓取/不可抓取信息预处理为适合CNN的数据格式最终实验检测精准度最高达0.988。包体为单个PDF文件容量4.25MB内容包含中英文摘要、原理阐述、方法设计与实验验证适合作为机器人抓取、CNN视觉检测方向的参考文献或专业指导材料。已有348人浏览学习对于需要快速掌握该技术路线或准备相关课题的读者能够直接获取一篇结构完整的原始文献省去检索和筛选时间。1. 抓取位置检测为什么值得单独做一个 CNN 模型很多项目一开始就上 3D 点云分割把抓取问题做成「找可抓表面」。但实际产线或实验台上吸盘和两指夹爪处理的平面抓取、料筐抓取绝大多数信息在前视或顶视相机的一张图里就能表达。基于 CNN 的抓取位置检测就是用图像直接预测抓取矩形中心点、旋转角度、张开宽度再交给机械臂执行。相比传统的手写特征提取CNN 对光照变化和物体堆叠的容忍度高很多相比点云方案计算量和传感器成本都低一个量级。这套方向适合两类人一类是把识别算法往机械臂应用落地的工程师另一类是准备用深度学习做机器人抓取课题的研究生。顺着标题往下拆会涉及四个层面抓取怎么用数据表示、网络结构怎么选、训练指标怎么设置、以及模型输出怎么变成机器人能真正执行的位姿。想清楚这四层你既能在仿真数据集上复现指标也能在真实机械臂上做出一版能用的检测模块。2. 先把抓取位置变成数据抓取矩形表示、输入图像与数据集2.1 抓取矩形五元组x、y、角度、张开宽度和夹爪尺寸深度学习模型不擅长直接输出「抓哪里」它更擅长输出一个固定维度的向量或热图。所以第一步是确定抓取位置的数学表达。抓取检测领域最常用的是带方向的矩形表示一组五元组写成 g (x, y, θ, w, h)。其中 (x, y) 是夹爪中心在图像中的坐标θ 是夹爪相对于图像水平轴的旋转角w 是夹爪开口张开的宽度h 是夹爪闭合时两个手指的宽度。θ 的取值一般只在 0 到 π 之间因为夹爪旋转 π 之后跟原来等价这个性质后面设计输出头时要用到。w 必须和实际夹爪的行程对齐否则模型预测出一个很宽的开口执行器却根本张不到。许多公开数据集在标注时直接采用这种矩形框一张图上能标出多个可用抓取位姿模型要学的是在物体边缘、可抓表面和相机视角限制下给出一组合理的五元组。2.1.1 为什么用矩形而不是单点曾经有不少工作尝试只预测一个「抓取点」再单独算接近角。这种做法在规则工件上行得通但物体堆叠时抓取点周围的局部几何信息不足以区分「能抓」和「不能抓」。矩形框天然携带了朝向和张开量的上下文评价两个抓取之间的差异也有了统一的几何度量——交并比。后续所有训练和验证都会围绕这五元组展开。2.2 深度图配 CNN为什么选图像而非手工特征做抓取位置检测上一节确定了输出形式这一节解决输入。抓取位置检测的输入通常有两种流派一是传统几何方法提取表面法向、凸包、边缘等手工特征再套用启发式规则二是把图像直接喂给 CNN让模型自己学出「哪里可抓」。后者之所以胜出原因在于深度卷积网络的两个先验局部性和权值共享。前馈神经网络把每个像素展平成向量会破坏空间结构参数规模还随输入尺寸平方级膨胀CNN 通过卷积核扫过整幅图既保留位置关系又大幅降低参数数量。输入选深度图还是 RGB 图同样有讲究。抓取本质上依赖几何边缘和空间边界不是颜色纹理。彩色图上花纹复杂的物体反而会干扰模型而深度图对纹理不敏感能直接反映物体表面凹凸。常见做法是用单通道深度图必要时叠加灰度图构成双通道输入。深度相机原始数据常有空洞和噪点预处理一般会做这几件事用中值滤波去掉孤立点、用最近邻或双边滤波补洞、按固定距离范围裁剪、最后归一化到 0 到 1。import numpy as np from scipy.ndimage import median_filter def preprocess_depth(depth_raw, min_dist0.2, max_dist1.5, size(224, 224)): # 固定距离范围截断滤除背景和离群噪声 depth np.clip((depth_raw - min_dist) / (max_dist - min_dist), 0.0, 1.0) # 中值滤波去掉深度图上的孤立跳变点 depth median_filter(depth, size3) # 最近邻插值缩放保持深度边缘锐利不引入渐变伪影 depth np.expand_dims(depth, axis-1) return depth这段代码的要点在于距离裁剪不是可选项深度相机在物体边界处经常出现极大极小值不裁掉会把后续归一化带偏中值滤波核大小取 3 就够核太大会抹掉细小倒角特征机器人抓取恰恰容易忽略这类小结构。缩放用最近邻而不是双线性因为双线性插值会在物体边缘制造出平滑过渡的假深度等于给网络注入了错误监督信号。2.3 抓取数据集与自建标签的规范化流程训练数据有两条路用公开数据集或者自建标注。公开数据集里 Cornell Grasp Detection 和 Jacquard 是出现频率最高的两个名字前者是真实深度和彩色图像后者主要是合成场景。合成数据的优点是量大、标注一致性好缺点是传感器噪声和物体材质仿真不足真实数据相反。业界常用的做法是混合训练先在合成数据上预训练再用少量真实数据微调。数据来源图像形态标注方式适用阶段Cornell 类真实数据集深度图 RGB每张图多个带角度矩形框微调、最终验证Jacquard 类合成数据集仿真深度图自动生成的密集标注框预训练、扩大样本量自建标注现场深度图人工画矩形记录夹爪宽度贴近产线、排查 Badcase自建标注流程一般分成四步固定相机位姿采集一批深度图在每张图上画出所有可行抓取矩形把矩形参数按 2.1 的五元组存入 JSON并记录对应夹爪型号最后做数据检查重点关注角度是否超出 0 到 π 范围、开口宽度是否超出夹爪行程这类低级错误。标注工具不必自己开发LabelImg 类工具改一下输出格式就够用。3. CNN 结构选型轻量全卷积网络与抓取输出头设计3.1 从分类网络到像素级抓取预测全卷积结构的优势确定输入输出之后下一步是选网络骨架。一个常见误区是把抓取检测当作图像分类任务用 ResNet 提取特征后接全连接层回归五元组。这种思路实现简单但存在明显短板全连接层把空间信息压平模型一次只能输出一个抓取点物体堆叠时多个可行抓取位置共享同一张图单点回归容易取平均输出的位姿会落在两个物体之间谁都抓不到。更可靠的做法是采用全卷积结构输出一张像素级的抓取质量图。网络对每个像素都预测「这里放夹爪的成功概率」再配合该位置的角度和宽度。类似语义分割的 encoder-decoder 形态在这个任务里成了主流选择。下采样过程扩大感受野让模型看到物体全貌上采样过程恢复分辨率让中心点定位更精细。如果不需要实时性可以在编码器和解码器之间加跳跃连接把浅层边缘信息带到深层如果面向机械臂实时抓取尽量少用跳跃连接省下的时间能显著提高系统吞吐。3.1.1 为什么不用大模型加大算力硬扛抓取位置检测并不需要 ImageNet 级别的千类分类能力它关心的几何特征相对简单边缘、凸包、对称性。盲目上 ResNet152 这类大网络参数翻了几十倍精度提升却很有限推理延迟却直接推高到几百毫秒。机械臂抓取是一个闭环过程从相机取帧到输出位姿最好控制在 50 毫秒以内。这个量级下轻量网络的性价比远高于大网络。3.2 轻量 encoder-decoder 的 PyTorch 最小实现下面给出一个可运行的抓取检测网络骨架参考了 Pixel-wise Grasp Detection 这类工作的常见设计。输入是单通道深度图输出四个通道中心质量图 q、角度双通道 sin2θ 和 cos2θ、宽度图 w。角度拆成两个分量回归是为了避免 θ 在 0 和 π 附近因周期性产生突变这是抓取检测特有的设计细节。import torch import torch.nn as nn class GraspCNN(nn.Module): def __init__(self, in_channels1): super().__init__() # 编码器逐步压缩分辨率扩大感受野 self.enc1 nn.Sequential( nn.Conv2d(in_channels, 16, 3, padding1), nn.BatchNorm2d(16), nn.ReLU(inplaceTrue)) self.enc2 nn.Sequential( nn.Conv2d(16, 32, 3, padding1), nn.BatchNorm2d(32), nn.ReLU(inplaceTrue)) # 解码器双线性上采样恢复分辨率 self.dec1 nn.Sequential( nn.Conv2d(32 16, 24, 3, padding1), nn.BatchNorm2d(24), nn.ReLU(inplaceTrue)) self.dec2 nn.Conv2d(24, 4, 1) # 4通道输出对应4个预测目标 def forward(self, x): x1 self.enc1(x) # 输出 16 通道分辨率与输入一致 x2 self.enc2(x1) # 输出 32 通道 x2 nn.functional.interpolate(x2, scale_factor2, modebilinear) x torch.cat([x1, x2], dim1) # 跳跃连接补充边缘信息 x self.dec1(x) return self.dec2(x) model GraspCNN(in_channels1)这个结构的参数量约 5 万级别配上 224×224 的输入在普通 GPU 上能跑出毫秒级延迟。整体流程是先经过两组常规卷积再做一次二倍上采样上采样后的特征和浅层特征拼接等于把高分辨率边缘信息重新引入。最后一层用 1×1 卷积把所有特征压缩成四个目标通道。实际工程里可以把 BatchNorm2d 换成 GroupNorm避免小 batch 下 batch 统计量抖动带来的训练不收敛问题。3.3 输出头选角度回归还是分桶分类角度是最容易出错的一个头。回归方式直接输出 sin2θ 和 cos2θ训练时加一个 arctan 还原层分桶方式则是把 180° 划分成 N 个区间让网络做分类。分桶的好处是训练稳定坏处是离散误差18 个桶每个桶的粒度是 10°这个误差在机械臂末端会被放大成数十毫米的偏移。回归方式没有离散误差但需要额外注意两个分量之间的单位一致性。工程上更常用的是回归方式因为抓取角度差 5 度以内的候选位姿在实际抓取中往往同样有效。宽度头不需要精细到毫米按夹爪行程离散成几个等级即可这样能明显压缩宽度头的回归难度。还有一点容易被忽略中心质量图、角度图和宽度图三个头的监督范围不一样训练 loss 必须分开处理否则背景像素的角度误差会主导梯度。4. 训练抓取检测网络loss 组合、参数配置与 IOC 评价4.1 抓取中心、角度与宽度分开监督组合 loss 与样本均衡一张 224×224 的深度图里可抓取的像素可能只占百分之几中心质量图天然存在严重的正负样本不平衡。处理方式有两种一是把质量图做成高斯分布在标注矩形中心处生成一个向四周衰减的热图让网络学一个软目标二是用加权交叉熵把正样本权重调高。前者更常见因为软标签能让中心点周围像素也提供有效梯度而不是被简单当作背景。角度和宽度的 loss 只在正样本位置上计算。具体做法是从中心质量图中取出真实标注点或取预测质量高于阈值的像素在这些位置上计算回归误差。下面的代码展示组合 loss 的基本写法中心质量用 BCE角度用 MSE。def grasp_loss(pred, target): # pred: [B, 4, H, W] - [质量, sin2θ, cos2θ, 宽度] # target: [B, 4, H, W]与 pred 尺寸一致 center_pred pred[:, 0] center_gt target[:, 0] # 中心质量图用带权重的二分交叉熵缓解正样本稀少 pos_mask (center_gt 0.1).float() neg_mask (center_gt 0.1).float() n_pos pos_mask.sum() 1 weight pos_mask * (n_pos / pos_mask.sum()) neg_mask * 0.5 center_loss nn.functional.binary_cross_entropy(center_pred, center_gt, weightweight) # 角度回归只在正样本位置计算sin 和 cos 分量的误差同时监督 angle_err (pred[:, 1] - target[:, 1]) ** 2 (pred[:, 2] - target[:, 2]) ** 2 angle_loss (angle_err * pos_mask).sum() / n_pos # 宽度回归同样限制在正样本处 width_err (pred[:, 3] - target[:, 3]) ** 2 width_loss (width_err * pos_mask).sum() / n_pos return center_loss 0.5 * angle_loss 0.2 * width_loss这里权重是一个经验起点中心质量决定「抓不抓」权重给到 1角度决定「怎么转」给 0.5宽度只影响夹爪张开行程对最终结果的影响最小给 0.2。三个 loss 直接相加在量级匹配的情况下够用。如果训练时发现 loss 振荡优先检查角度 loss 是否过大把系数降到 0.2 左右重新跑几轮。4.2 训练超参与数据增强epoch、学习率和随机仿射抓取检测训练有两个容易踩的坑一是随机旋转增强时忘记同步旋转角度标签二是输入分辨率和实际部署不一致导致精度掉点。旋转增强是必须的因为夹爪面对物体的朝向是任意的但旋转角度 θ 需要跟着图像同步变化裁剪增强会让中心坐标偏移同样要对标签做相应变换。超参数推荐取值说明输入分辨率224×224 或 320×240训练与部署保持一致Batch size1632依赖显存小 batch 时用 GroupNorm初始学习率1e-3Adam 优化器配合余弦退火训练轮数3060 epoch合成数据可缩短真实数据取上限增强策略平移、旋转 ±30°、亮度抖动旋转时角度标签同步变换训练轮数这里想多说一句。很多人以为 epoch 越多越好但抓取检测任务里 30 轮之后指标基本进入平台期继续训练只会让模型记住训练集的物体纹理。最终用哪个模型不应当凭 loss 判断而要看验证集上的 IOC 指标这正是下一节要讲的内容。4.3 用 IoU 和角度差计算抓取成功率IOC 指标抓取检测的论文里常用的评价标准是 IOC预测矩形和标注矩形的 IoU 大于 0.25且角度差小于 30°就算一次成功预测。这个标准比分类准确率更贴近实际因为中心偏几个像素、角度差几度机械臂照样能完成抓取。下面的代码计算角度差和质量阈值过滤后的 IOC。import numpy as np def compute_ioc(preds, targets, angle_thresh30.0): # preds/targets: 五元组 (x, y, theta, open_width, gripper_width) correct 0 iou_list [] for p, t in zip(preds, targets): # 用矩形交并比的近似计算中心距离 尺寸差异的加权评分 center_dist np.hypot(p[0] - t[0], p[1] - t[1]) size_ratio min(p[3], t[3]) / (max(p[3], t[3]) 1e-6) iou_approx size_ratio * np.exp(-center_dist / max(t[3], 1e-6)) angle_diff abs(p[2] - t[2]) angle_diff min(angle_diff, np.pi - angle_diff) # 角度周期化到 [0, π/2] angle_ok np.degrees(angle_diff) angle_thresh iou_ok iou_approx 0.25 correct int(iou_ok and angle_ok) iou_list.append(iou_approx) return correct / len(preds), np.mean(iou_list)注意这里用了简化 IoU完整旋转矩形的 IoU 计算要用顶点构成的多边形面积交并比工程上能直接调用 OpenCV 的 rotated rectangle 方法。深层的逻辑是IOC 只衡量视觉定位质量不包含机械臂执行误差。如果视觉 IOC 很高但真实抓取失败率居高不下问题往往出在坐标变换或夹爪控制排查方向应转向下一章的部署环节。5. 把模型输出变成抓取位姿坐标变换、ROS 2 接口与推理优化5.1 从图像坐标系到机械臂基座坐标系的变换链路模型输出的 x, y, depth 都是像素坐标和像素深度机械臂执行器需要的是基座坐标系下的三维位置和末端姿态。这条链路涉及四次变换像素坐标转相机内参坐标得到相机坐标系下的三维点相机坐标系通过外参变换到机械臂基座坐标系基座坐标再转到执行器抓取姿态最后把 θ 映射为末端旋转角度 ZYX 欧拉角中的 Yaw。任何一环标定误差都会让模型的高 IOC 指标在真实抓取中失效。变换关系输入输出常见误差来源内参变换像素坐标 深度值相机系三维点深度标定不准外参变换相机系坐标机械臂基座系坐标手眼标定误差姿态映射图像角度 θ末端 Yaw 角相机安装角度手眼标定是这个链条里最痛苦的一步。常见做法是 Eye-to-Hand 布局相机固定在机架上看机械臂和料筐用标定板采集多组机械臂末端位姿和对应的标定板位姿求解 AXXB 方程。如果抓取每次都朝同一个方向偏固定距离基本是标定板外参出了系统误差如果偏的方向随机优先检查深度图的尺度问题。5.2 ROS 2 里最简抓取检测节点的发布订阅写法把训练好的模型接入机械臂最常见的方式是做成一个 ROS 2 节点订阅相机话题推理得到抓取矩形发布机械臂执行话题。节点内部只处理图像和位姿不涉及运动规划这样模块边界清晰换相机、换夹爪都不需要改模型代码。下面给出节点骨架。ros2 run grasp_detector grasp_node --ros-args \ -p model_path:./checkpoints/grasp_cnn.onnx \ -p score_thresh:0.5节点内部的核心回调函数逻辑大概是收到 Image 消息后转成 NumPy 数组调用预处理函数模型推理拿到四通道输出在质量图上找局部极大值点作为候选抓取中心从候选中心处读取角度和宽度发布 PoseStamped 和 Float32 两个话题。# 简化版从模型输出中提取抓取候选 def extract_candidates(q_map, ang_sin, ang_cos, width_map, thresh0.5): q_map q_map.squeeze() ys, xs np.where(q_map thresh) # 质量超过阈值的像素 cands [] for x, y in zip(xs, ys): theta np.arctan2(ang_sin[y, x], ang_cos[y, x]) / 2 cands.append((x, y, theta, width_map[y, x])) return cands参数 score_thresh 设得太低会输出一堆互相重叠的候选位姿设得太高会出现漏检。一个经验值是先输出质量图直方图看前 10% 像素的分数分布把阈值设在分数明显跌落的拐点附近。宽度消息发布后控制层应该先做「预张开」校验宽度超过当前抓取物预估尺寸时跳过该候选而不是盲目下压。5.3 推理后处理与轻量化去重叠、半精度和量化模型输出的是多个候选框实际机械臂一次只能抓一个所以必须做去重叠。做法是沿用目标检测里的 NMS按质量分排序保留最高分候选删除与其 IoU 超过阈值的候选。抓取场景的 NMS 阈值通常比目标检测严格因为多个候选框中心距离很近时下一个往往不可达。def nms_candidates(cands, iou_thresh0.3): cands sorted(cands, keylambda c: c[3], reverseTrue) keep [] for c in cands: # 与已保留候选的中心距离和角度差都足够大才保留 conflict False for k in keep: dist np.hypot(c[0] - k[0], c[1] - k[1]) ang_diff abs(c[2] - k[2]) if dist k[3] * iou_thresh and ang_diff 0.2: conflict True break if not conflict: keep.append(c) return keep除了 NMS推理侧还能做两层优化第一层是把模型转成 FP16 推理显存占用减半速度提高约三分之一精度损失通常在 1% 以内第二层是转成 TensorRT 引擎并做 INT8 量化速度提升更明显但需要准备校准数据集且对深度图的动态范围敏感。工程上常见配置是 FP16 配合 NMS只有算力紧张时才上 INT8。6. 真实机械臂验证用棋盘格和可重复抓取校准抓取检测链路6.1 离线回放与在线空抓分步验证上线之前先不要把模型直接接到真实抓取流程里。最稳妥的做法是采集一段包含深度图和机械臂实际抓取结果的记录把图像重新离线跑一遍模型观察质量图和输出位姿。离线阶段解决的是「算法本身能不能检测对」在线阶段解决的是「标定和控制能不能执行对」。两者混在一起排查问题很难定位。具体做法是放一块棋盘格在料筐里机械臂末端装一根尖针依次走到模型给出的抓取中心上方记录针尖与棋盘格角点的像素偏差。如果偏移量固定优先怀疑手眼标定如果偏移量随位置改变优先怀疑相机畸变参数。这一步做完后再做无物件的空抓测试验证夹爪开合和姿态命令是否正确到达执行器。6.2 失败类型速查表真实环境下的抓取失败很少是单一原因按现象分类排查效率最高。失败现象优先排查方向位姿整体偏移固定距离手眼标定外参、相机安装松动角度偏 5° 以内但夹不住角度头离散化误差或夹爪行程标定质量图高响应但抓空深度图空洞、物体反光导致深度缺失抓取位置正确但滑落宽度预测偏大、夹爪力控参数不合适给这个表格补充一个可落地的技巧把一次抓取拆成五个观察项记录中心偏差、角度偏差、张开宽度、接触点位置、抬离结果每 5 到 10 次一组做统计。绝大多数情况下看接触点就能快速判断是视觉问题还是执行问题接触点总在物体边缘说明视觉矩形中心偏了接触点正确但物体从夹爪里滑出来问题在控制层不需要动模型。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →