平面抓取检测实战:基于深度学习的机械臂抓取与pybullet仿真
发布时间:2026/10/2 1:45:59来源:尧图网络
简介一份基于深度学习的平面抓取检测与机械臂控制Python源码包依托PyBullet仿真环境实现主要面向机器人方向的研究生、工程师以及正在完成抓取相关课题的开发者。资源包共1031个文件、约43.49MB包含387个OBJ三维网格、155个STL模型、149个URDF机器人描述文件、69个MTL材质、37个Python脚本以及57个PYC编译文件同时附有XML配置、SDF/VTK仿真资源、PNG/JPG图像样本和PTH权重文件等覆盖从仿真场景搭建、物体模型导入、抓取网络训练到机械臂运动控制的完整工程链路。目录保留PyBullet原生组织结构模型、脚本、配置相对独立便于按模块阅读和二次开发。当前已有612人学习下载适合希望快速进入平面抓取检测领域并动手实践的读者。通过该源码可直观理解抓取姿态表示、抓取质量评估、碰撞检测以及机械臂逆运动学求解等关键环节并可在PyBullet中直接运行示例观察不同策略下的抓取效果为后续迁移到真实机器人提供扎实基础。1. 平面抓取检测这套源码在解决什么问题从“看见物体”到“知道往哪儿夹”平面抓取检测这几个字其实是把一套完整链路压缩成了四个任务用深度学习从视觉输入里找到可抓取位置把结果交给机械臂控制最后在 pybullet 仿真里验证能不能夹起来。它解决的是机械臂抓取里最尴尬的一环——物体明明在桌面上深度图里也看得清清楚楚但机械臂就是不知道该往哪儿下爪子。适合正在做机械臂抓取课题、或者想在没有真机的条件下先把感知-决策-执行闭环跑通的人。这套方案里最反直觉的一点是检测网络本身往往不是瓶颈真正让成功率拉开差距的是仿真数据生成和坐标变换这两件看起来不起眼的杂活。2. 抓取表示与模型选型把抓取问题压缩成五维回归平面抓取检测之所以能成为一套独立的工程方案是因为它接受了“机械臂从正上方垂直于桌面抓取”这个约束。一旦接受了这个约束原本六自由度的抓取位姿就被压缩成了五个参数网络输出、数据标注、仿真验证全都跟着简化。这一章先把这五个参数讲清楚再讨论常见的两类模型结构该怎么选最后落到网络输出头的设计上。2.1 五维抓取矩形平面抓取为什么只需要一个旋转角六自由度抓取位姿需要描述三维位置和三个旋转角在真实场景里数据要靠人工标注或者昂贵的三维重建才能拿到。平面抓取则假设夹爪始终平行于桌面法线从正上方下压于是旋转自由度只剩绕桌面法线的一维姿态从“三维旋转矩阵”退化成了一个角度。常见的做法是用一个五维抓取矩形来表示候选抓取dataclass class GraspRect: center_x: float # 抓取中心在图像坐标系下的 x center_y: float # 抓取中心在图像坐标系下的 y theta: float # 绕桌面法线的旋转角弧度制 width: float # 夹爪需要张开到的宽度单位 mm depth: float # 夹爪沿接近方向进入物体的深度单位 mm score: float 1.0 # 抓取质量0~1这里最关键的是theta的语义它表示夹爪中心线在水平面内与图像 x 轴的夹角角度变化范围是 0 到 π而不是 0 到 2π。因为平行夹爪旋转 180° 之后完全等价这一条会在后面的损失函数设计里反复起作用。width对应夹爪开度depth对应夹爪手指伸进物体边缘的距离这两个值直接送给机械臂控制层不需要网络去预测沿 z 轴的接近距离因为平面抓取默认从固定的下压高度出发深度图里那一个像素的深度值就是接近距离的答案。如果看到这里觉得“少了一个自由度不完整”那说明你还没被真实数据标注毒打过平面简化换来的可复现性远大于损失的侧方抓取覆盖度。2.2 两阶段检测与单阶段回归省时间还是省语义拿到五维表示之后下一个问题是网络结构走哪条路线。方案 A 是经典的两阶段先用目标检测框出每个物体再对每个框做抓取姿态估计方案 B 是单阶段回归输入整张深度图直接输出逐像素的抓取质量、角度和宽度。两条路线的取舍在工程上非常明确不是精度问题而是数据成本问题。对比项两阶段检测姿态估计单阶段逐像素回归输出内容物体框每个框的抓取参数逐像素的抓取质量与参数样本标注成本需要物体级类别与框标注只需要“这里能不能抓”的真值漏检风险目标检测漏检则整体失败单一网络承担全部判断语义能力能区分“抓 A 避开 B”只能按质量最高选择仿真数据生成难度高低这套源码面向的是桌面杂散物体整理这类场景常见做法是选方案 B。理由很直接仿真里随机撒一把物体程序自动生成“该不该抓、从哪个角度抓”的标签全程不需要人工标一个框。如果你要做的是“先抓红色再抓蓝色”这种有语义约束的任务那两阶段更合适但代价是训练成本翻倍且两个模型之间的误差会相互放大。我的建议是第一个闭环先走单阶段语义约束通过后处理规则补上这比一开始就上两阶段稳妥得多。2.3 网络输出头设计质量图、角度图和宽度图单阶段方案的具体输出头设计业内常见的做法是“一个编码器-解码器主体三个 1x1 卷积分支”输入是单通道深度图输出是三个与输入同分辨率的热力图。编码器用一个轻量骨架下采样几次提取高层语义特征解码器依靠跨层连接把物体边缘这类细节恢复到原始分辨率。这里给一个输出头的最小实现class GraspHead(nn.Module): def __init__(self, in_channels, num_angles1): super().__init__() # 质量分支: 判断每个像素作为夹爪中心能否抓取成功 self.qual nn.Conv2d(in_channels, 1, kernel_size1) # 角度分支: 输出 2 通道, 分别编码 cos(2*theta) 和 sin(2*theta) self.angle nn.Conv2d(in_channels, 2, kernel_size1) # 宽度分支: 输出归一化夹爪开度 [0, 1] self.width nn.Conv2d(in_channels, 1, kernel_size1) def forward(self, x): q torch.sigmoid(self.qual(x)) ang self.angle(x) # 推理时用 atan2 恢复实际角度 w torch.sigmoid(self.width(x)) return q, ang, w质量分支用 sigmoid 输出 0~1 的概率宽度分支同样用 sigmoid 把开度压制到 [0,1]再乘机械臂最大开度换算成毫米。角度分支是这批输出头里最容易出错的地方它不直接回归 theta而是输出 cos(2θ) 和 sin(2θ) 两个值。原因是 θ 和 θπ 表示同一个抓取姿态如果直接回归网络会在 0 附近遇到数值跳变训练出来的角度图在关键位置会反复横跳。用 2θ 的复平面编码把周期性抹平推理时torch.atan2(sin, cos) / 2还原角度即可。编码器骨架不必追求大模型一个轻量结构在 224x224 的输入上足够提取桌面物体的边缘和高度信息重骨干反而会在小数据集上过拟合。3. pybullet 仿真平台机械臂动起来、相机出图与抓取真值生成数据从哪来答案几乎只有一个仿真生成。原因很简单真机采深度图再人工标注抓取点一晚上只能标几十张pybullet 里一秒钟能渲染好几帧深度图真值标签随场景状态直接读取。做抓取仿真pybullet 和 mujoco 哪个好的争论其实不该存在mujoco 的刚体接触解算更快但 pybullet 的 URDF 生态更完整内置机械臂模型多而且getCameraImage直接给出深度缓冲几乎是为抓取数据生成量身定做的。这一章从环境搭建讲到真值生成每一步都有可复制的命令和代码。3.1 场景搭建与关节控制让机械臂在仿真里动起来先说环境。假设你已经把深度学习基础环境装好包括 Python 和 PyTorch那么额外的依赖其实很少pip install pybullet numpy opencv-pythonpybullet 的安装不需要编译装完就能用。接下来初始化一个带重力的世界加载桌面和机械臂模型。pybullet 内置了多种机械臂 URDF这里选用常见的 Panda 机械臂它自带平行夹爪和平面抓取任务刚好匹配import pybullet as p import pybullet_data p.connect(p.GUI) # GUI 模式方便调试, 批量生成数据时改成 p.DIRECT p.setGravity(0, 0, -9.81) p.setTimeStep(1.0 / 240.0) # 240Hz 的物理步长, 接触稳定不穿模 p.setAdditionalSearchPath(pybullet_data.getDataPath()) plane p.loadURDF(plane.urdf) # 地面 table p.loadURDF(table/table.urdf) # 桌面, 高度通常 0.75m 左右 robot p.loadURDF(franka_panda/panda.urdf, basePosition[0, 0, 0.75])初始化之后先别急着上深度学习模型第一步要把机械臂控制跑通。pybullet 默认的关节控制是位置控制模式给定目标关节角内部的 PID 会驱动关节运动。直接操作机械臂最常用的方式是先做逆运动学给定末端目标位置和姿态让 pybullet 算出关节角再下发到关节控制接口。def move_to_pose(robot, target_pos, target_quat, link_idx11): joint_poses p.calculateInverseKinematics( robot, link_idx, target_pos, target_quat, maxNumIterations100, residualThreshold1e-4 ) p.setJointMotorControlArray( robot, [0,1,2,3,4,5,6], controlModep.POSITION_CONTROL, targetPositionsjoint_poses[:7] )这段代码里link_idx11是 Panda 末端夹爪的 link 索引不同 URDF 索引不一样建议先打印所有 link 名字确认。calculateInverseKinematics接受末端位置和四元数姿态作为目标返回一组关节角位置控制模式下机械臂会平滑跟踪这组关节角。注意逆运动学不是闭式解maxNumIterations太小会解出离谱的位形通常给 100 次以上。初次跑通这一步时把p.setRealTimeSimulation(1)打开看到机械臂跟着目标点动了再关掉换成固定步长推进。3.2 深度相机与像素深度恢复内参、外参与点云转换平面抓取检测的输入是深度图不是 RGB 图。深度图丢弃了纹理和颜色信息却直接给出了几何距离这让模型天然对光影不敏感也是仿真到真机迁移时最稳的一个模态。pybullet 里getCameraImage可以同时渲染 RGB 和深度但深度缓冲返回的是归一化浮点值不是真实物理距离这一步是翻车高发区。def render_depth(camera_eye, camera_target, width224, height224): view_matrix p.computeViewMatrix( cameraEyePositioncamera_eye, cameraTargetPositioncamera_target, cameraUpVector[0, 0, 1] ) proj_matrix p.computeProjectionMatrixFOV( fov60.0, aspectwidth / height, nearVal0.1, farVal5.0 ) _, _, depth_buffer, _, _ p.getCameraImage( width, height, viewMatrixview_matrix, projectionMatrixproj_matrix, rendererp.ER_TINY_RENDERER ) # OpenGL 深度缓冲转真实距离 near, far 0.1, 5.0 depth far * near / (far - (far - near) * depth_buffer) return depth转换公式的来源是透视投影下深度缓冲与视点距离成反比关系直接用原始 buffer 值喂给网络会让模型学到一种“假距离”。拿到真实深度之后想要继续做几何处理还需要把像素坐标和深度反投影成三维点云这在后面机械臂控制里会再次用到def depth_to_points(depth, fx, fy, cx, cy): h, w depth.shape v, u np.meshgrid(np.arange(h), np.arange(w), indexingij) x (u - cx) * depth / fx y (v - cy) * depth / fy pts np.stack([x, y, depth], axis-1) # 单位与 depth 一致 return pts相机内参 fx、fy、cx、cy 是虚拟相机自己设定的不需要标定但每个值都要收敛到现实相机参数附近才有迁移意义。常见做法是设 fxfy400对应 224x224 图像、60° 视场角主点放在图像中心。相机外参由eye和target决定平面抓取让相机光轴垂直向下eye在桌面上方 0.8 米target指向桌面中心这样生成的深度图里桌面是一个均匀平面物体是亮斑模型学起来非常干净。如果你想模拟真实相机的斜视安装把eye偏离中心即可但第一个版本不要加这些花活。3.3 随机摆盘与真值生成抓取标签不是人标出来的深度图有了还差标签。平面抓取的真值生成不需要逐像素人工标注常见做法是对每个物体做几何分析把物体的包围盒投影到桌面平面在包围盒中心附近按一定角度步长采样夹爪位姿再用物理仿真检查这个位姿合不合法。合法性检查分两步夹爪和桌面有没有碰撞、夹爪闭合后能不能把物体包裹住。def generate_grasp_label(robot, object_body, table_body, samples_per_obj18): # 读取物体在世界系下的位姿与 AABB pos, orn p.getBasePositionAndOrientation(object_body) aabb_min, aabb_max p.getAABB(object_body) obj_h aabb_max[2] - aabb_min[2] # 在包围盒中心附近采样角度 labels [] for k in range(samples_per_obj): theta k * np.pi / samples_per_obj grasp_x (aabb_min[0] aabb_max[0]) / 2 grasp_y (aabb_min[1] aabb_max[1]) / 2 # 简化检查: 夹爪中心点是否在物体投影范围内, 以及是否与桌面碰撞 in_range is_inside_object(grasp_x, grasp_y, aabb_min, aabb_max) collides check_collision(robot, table_body, grasp_x, grasp_y, theta) if in_range and not collides: labels.append(GraspRect(grasp_x, grasp_y, theta, obj_w40.0, depthobj_h / 2)) return labels这个简化版本里有两个参数可以调obj_w40.0是夹爪开度估计值40 毫米覆盖了大多数小物体的宽度samples_per_obj决定角度分辨率18 个样本对应 10° 的采样步长。想要更精细就提高到 36。注意负样本怎么处理把采样点故意偏移到物体外面、或者让夹爪和桌面相交的位置记为质量标签 0训练时专门采一部分这样样本网络才不会对空桌面疯狂输出高分。物体摆放用随机撒点加碰撞拒绝保证物体不重叠也不飞出去物体模型直接用 pybullet 内置的 cube、cylinder 和 sphere 起步跑通之后再引入带纹理的 YCB 模型。这一节是整套源码里代码量最大但成就感最足的部分因为一旦真值生成稳定训练数据就是无限量供应的。4. 训练抓取检测模型损失函数、数据增强与物理评估训练阶段的目标不是让 loss 降到最低而是让“放进 pybullet 里真正抓一把”的成功率上去。这一章先讲深度图数据管线怎么处理再讲三个输出头各自的损失函数如何平衡最后讲如何用物理仿真替代人眼判断模型好坏。4.1 深度图数据管线截断、归一化与同步标签的增强仿真出来的深度图是 float 数组取值范围从桌面到相机视场远端直接做 min-max 归一化会让桌面平面占据大部分数值区间物体和桌面的对比度被压缩。常见做法是先做物理截断把近处和远处的无效深度切掉再做标准化。比如相机距离桌面约 0.8 米物体最高 0.1 米深度取值范围集中在 0.7~0.9 米区间超出这个窗口的像素视为无效值填 0。这一步比换模型结构更管用很多项目训练半天不收敛第一件事就是可视化输入检查深度图是不是一片灰。def preprocess_depth(depth): # 截断到 [min_depth, max_depth], 单位米 depth np.clip(depth, 0.7, 0.9) depth (depth - 0.7) / (0.9 - 0.7) # 归一化到 [0,1] depth (depth - 0.5) / 0.5 # 再标准化到 [-1,1] return torch.from_numpy(depth).unsqueeze(0).float()preprocess_depth的两个阈值要和相机安装高度严格对应换相机位置就必须改参数。数据增强是所有抓取检测训练的重头戏但这里的坑在于图像做了旋转平移标签必须跟着变。旋转角度 θ 要减去图像的旋转角抓取中心点坐标要做相同的仿射变换。用torchvision.transforms只能处理图像所以更稳妥的做法是把图像和标签拼在一起做变换或者干脆只对深度图做在线增强标签在读取时同步调整。增强的强度建议平移 ±16 像素旋转 ±30°噪声标准差 0.01千万别加太大否则仿真深度图的几何精度优势就被毁了。4.2 损失函数质量、角度与宽度三个头的平衡三个输出头的损失函数必须分开设计。质量头是二分类问题用 BCE 损失角度头是回归问题但回归目标是 cos(2θ) 和 sin(2θ)用 L1 或者 SmoothL1宽度头同样是回归输出归一化开度用 SmoothL1。这里最容易踩的坑是损失权重失衡质量图的负样本像素远多于正样本如果不加权模型会学到“全输出 0”所以要对负样本降权。def grasp_loss(pred_q, pred_ang, pred_w, gt_q, gt_ang, gt_w, weight0.5): # 质量损失: 正负样本权重比 1:0.5 bce F.binary_cross_entropy_with_logits(pred_q, gt_q, pos_weighttorch.tensor([weight])) # 角度与宽度损失只在正样本像素上计算 mask (gt_q 0.5).float() ang_loss F.smooth_l1_loss(pred_ang * mask, gt_ang * mask, reductionsum) w_loss F.smooth_l1_loss(pred_w * mask, gt_w * mask, reductionsum) ang_loss ang_loss / (mask.sum() 1) w_loss w_loss / (mask.sum() 1) return bce 2.0 * ang_loss 1.0 * w_losspos_weight0.5表示负样本的损失贡献减半这个值取决于正负样本比例一般先从 0.3 试起。角度损失权重设为质量损失的 2 倍是因为角度误差对抓取成败的影响最直接偏 20° 就很容易夹空。mask的使用是关键中的关键在质量图分数极低的位置角度和宽度本身无意义如果算进去会引入大量噪声梯度。还有一种做法是只取质量图 top k 像素的损失效果类似但 mask 写法更直观。另外真值的质量图不应是离散的 0/1而应在正样本中心周围做高斯扩展让网络学习“离中心越近质量越高”的连续分布这会显著提升推理时峰值定位的稳定性。4.3 每个 epoch 跑一次物理仿真评估拿成功率代替 loss 玄学训练集和验证集上的 loss 下降只能说明网络在拟合标签不能说明它真的会抓。深度学习训练里最玄学的部分就是 loss 与最终效果脱节质量图峰值定位偏移一点点角度和宽度完全正确也会导致夹爪擦着物体边缘过去。所以每个 epoch 结束之后必须拿当前模型在固定测试场景里跑一遍真实抓取统计成功率。def evaluate_grasp_success(model, test_scene_fn, n_trials20): success 0 for _ in range(n_trials): scene test_scene_fn() # 重置摆盘 depth render_depth(scene) # 采集深度图 q, ang, w model(depth) # 推理 grasp post_process(q, ang, w) # 取质量图峰值, 恢复角度和宽度 trials execute_grasp(scene, grasp) # pybullet 里执行夹取 success int(scene.is_lifted()) # 抬升后物体离开桌面即成功 return success / n_trialspost_process负责在质量图上做非极大抑制找到局部极大值作为候选抓取中心然后从角度图和宽度图对应位置取值。执行时让机械臂先移动到抓取点上方 60 毫米处再垂直下压到抓取深度闭合夹爪抬升判断物体质心是否随之升高。每个 epoch 跑 20 次抓取成功率作为早停依据。损失函数和成功率偶尔确实会同步下降但更多时候你要面对的是 loss 在降、成功率原地不动这时候优先去查角度图是不是出现了周期跳变或者宽度预测是否接近夹爪开度上限。5. 避坑与排查抓取成功率上不去的五个高频原因这一章写的是这个项目里最容易被忽略、却又直接决定成败的五个坑按“现象、原因、解决”的顺序记录。每一条都是真实调试时会撞上的问题不是理论推演。5.1 深度图整体偏暗与角度在 0°和 180°之间跳变现象模型训练 loss 很低但是仿真抓取成功率一直不到三成。可视化深度图输入时发现物体边缘有一圈异常的亮边换一个随机摆盘模型预测的抓取角度在 89° 和 -89° 之间来回横跳夹爪方向完全不对。原因深度图没做物理截断和归一化。仿真深度缓冲是反向映射的浮点值直接喂给网络会让模型把边缘深度跳变当成强特征。角度跳变则是角度损失函数直接回归 θ 的副作用θ 和 θπ 在数值上相差 π但物理上完全等价网络在训练时被互相矛盾的标签拉扯只能输出中间值。解决先按第 4 章的preprocess_depth做截断和归一化确认输入张量的数值范围稳定再把角度头改成 cos(2θ)/sin(2θ) 编码推理阶段统一用atan2恢复两处缺一不可。这个坑基本是训练跑不通的固定元凶。5.2 真值生成少了桌面碰撞检查模型学会往桌面空插现象质量图上物体轮廓外的大片空白桌面区域出现高分斑点机械臂执行时直接冲着桌面插下去夹爪和桌面碰撞物体纹丝不动。原因真值生成时只给物体包围盒内部打正样本没有在空桌面区域生成负样本或者负样本做了但没检查候选抓取位姿是否与桌面碰撞。网络学到的是“哪里有平面就往哪里抓”而不是“哪里能夹起物体”。解决数据生成时增加碰撞检测候选夹爪与桌面几何体求交的样本直接标为质量 0推理后处理再加一道高度规则——抓取点的深度值对应的高度低于桌面高度加最小物体高度阈值直接抑制该候选。两道防线同时上空桌面误检基本清零。5.3 逆运动学在奇异点附近抖动夹爪方向漂移十几度现象目标抓取点接近工作空间边缘时机械臂运动过程中夹爪方向在相邻帧之间突然漂移夹取失败同一组目标点换个初始关节角结果完全不一样。原因逆运动学在奇异位姿附近雅可比矩阵退化pybullet 的calculateInverseKinematics默认找最近解前后两帧的解可能落在不同的解分支上造成关节角跳变。仿真里看起来是抖动真机上直接就是电机过流报警。解决不要连续追踪目标点每一帧。先规划一条路径把中间点线性插值成 10 到 20 个路点每个路点单独做 IK并且把上一路点的关节角作为当前 IK 的初始猜测让解在解空间里连续移动。另外给 IK 调用加上关节角变化惩罚的约束避免大幅度甩关节。5.4 仿真成功率九成但夹爪闭合后物体从指间滑脱现象物理评估里机械臂动作完全正确下压位置、角度都对但抬升时物体从夹爪里滑出来成功率突然掉一半。检查日志发现夹爪虽然闭合到位但立刻就开始抬升物体还没被夹稳。原因仿真夹爪的摩擦系数和闭合时序没调。pybullet 默认的 link 摩擦系数偏高而且夹爪闭合状态到物体稳定之间需要时间闭合瞬间物体的接触力尚未建立过早抬升等于没夹住。解决把夹爪指尖 link 的lateralFriction从默认的 1.0 调低到 0.2~0.4让接触更容易打滑提高模型对抓取姿态误差的容忍度控制层在夹爪完全闭合后增加 80~100 毫秒的等待延时再执行抬升。这个参数组合也是迁移到真机前的第一组调整对象。5.5 换了物体模型库成功率断崖式下跌现象用几何体训练完成功率很高换成带纹理的 YCB 模型评估成功率直接掉到两成以下。深度图可视化看不出明显异常loss 也正常。原因仿真几何体的表面是完美平面深度图过于干净网络学到了“物体边缘就是深度突变”这种捷径没有学到真正的几何轮廓特征。带纹理模型的表面有更多凹凸和反光深度图噪声模式完全不同。解决数据增强里加入深度噪声和边缘随机腐蚀模拟真实深度相机的不完美同时在数据生成时混入不同模型库的物体而不是训练几何体、评估换模型。域随机化的强度要循序渐进加得太猛会让模型学不到几何特征加太少则迁移时翻车。6. 把检测结果变成机械臂动作像素坐标到基座坐标的五个步骤模型输出的五维抓取矩形是在相机图像坐标系下表达的机械臂认的是基座坐标系这中间差了一次坐标变换。别小看这一步很多项目模型推理很漂亮一到执行就抓到空气就是因为漏了深度图反投影和外参变换。核心公式像素坐标 (u, v) 结合深度 d用相机内参恢复相机系坐标再乘相机到基座的外参矩阵得到基座系下的目标位置。def pixel_to_base(u, v, depth, fx, fy, cx, cy, cam_to_base): z depth[v, u] x_cam (u - cx) * z / fx y_cam (v - cy) * z / fy p_cam np.array([x_cam, y_cam, z, 1.0]) return cam_to_base p_cam # 得到基座系下抓取点cam_to_base是 4x4 齐次变换矩阵在 pybullet 里可以从相机 link 的世界位姿直接获取。拿到基座系抓取点之后按表格里的时序执行一次完整夹取步骤动作关键参数1模型推理并取质量图峰值峰值领域半径 8 像素质量阈值 0.52像素坐标深度变换到基座系深度截断 [0.7, 0.9] 米3计算预抓取点目标点正上方 60 毫米4IK 求解并移动到预抓取点maxNumIterations1005垂直下压到抓取深度桌面高度 物体高度的一半6闭合夹爪并等待闭合后等待 100 毫秒7抬升撤离抬升高度 120 毫米这套流程里第 5 步的抓取深度最容易出错。物体高度来自深度图上抓取点邻域的 z 值减去桌面平面 z 值而不是模型预测的常量。我习惯把每一步的关节角历史和夹爪状态打到日志里抓取失败时直接回放最后 50 步的动作比对着 loss 曲线猜原因高效得多。坐标系变换这一段是纯线性代数没有玄学空间每一处矩阵都写成代码注释跑通了就稳定复现。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网