ARTICLE DETAIL

资讯详情

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

6dof-graspnet实战:从点云输入到机械臂抓取位姿估计与部署

6dof-graspnet实战:从点云输入到机械臂抓取位姿估计与部署 简介6dof-graspnet-master是一个聚焦六自由度6DOF抓取姿态预测的深度学习项目面向机器人操作、自动化仓储等应用场景适合具备深度学习与计算机视觉基础的研究者或开发者。压缩包共54个文件大小约9.83MB目录结构清晰。文件类型以Python源码为主包含模型结构定义、训练与评估脚本、抓取估计器及可视化工具并配有npy点云数据、STL/OBJ三维模型、YAML配置文件等可支撑从数据读取、模型训练到姿态预测的完整流程。目前已有627人学习下载项目里还提供了示例程序、物体渲染器、预训练数据及授权说明便于快速复现实验也能帮助新手理解6DOF抓取网络的设计思路。对研究抓取检测或从事机器人抓取落地的人员来说这套代码在算法复现、模型调试和二次开发上都具有实用参考价值。1. 6dof-graspnet 在解决什么问题从抓得到到抓得准的距离6dof-graspnet 是一个把深度学习用在机械臂抓取上的典型项目输入是深度相机拍到的场景点云输出是夹爪的 6 自由度位姿和张开宽度。很多初学者以为抓取就是识别出物体中心然后垂直往下压但真实料箱里物体互相堆叠垂直下压几乎必翻车。这个项目的价值在于它同时估计抓取点、抓取方向和夹爪开度并且给每个候选抓取打质量分让机械臂从能碰到变成能抓稳。如果你正在做人形机器人抓取、工业上下料或者移动机械臂抓取方向的研究这套方案值得你完整复现一遍。它既不是纯目标检测也不是机械臂运动规划而是卡在两者中间的那层抓取位姿估计。2. 数据与标签6D 抓取位姿在 graspnet 里的表示方式2.1 坐标系约定与标注格式先读懂一次抓取被存成什么6 自由度抓取的核心问题是夹爪以什么姿态、什么位置、多大开度去接触物体。在 graspnet 系列的标注里一次抓取通常被存成一个 4x4 齐次变换矩阵外加一个夹爪宽度数值。这个矩阵的物理含义是夹爪坐标系原点放在物体表面的接触点附近三个坐标轴分别表示夹爪在场景坐标系里的朝向。其中夹爪的 z 轴方向特别关键它通常被约定为夹爪闭合时手指的运动方向。后面做手眼标定和机器人部署时所有坐标转换都依赖这个约定如果这里理解偏了后面所有位姿都是错的。import numpy as np import json # 打开场景标注文件通常是一个 JSON 或 NPZ 结构 with open(scene_annotation.json, r) as f: ann json.load(f) # 常见的存储形式 # grasp_poses : (N, 4, 4) 的齐次变换矩阵夹爪位姿 # grasp_widths : (N,) 的数组夹爪张开宽度单位是米 # grasp_scores : (N,) 的数组抓取质量分数0~1 grasp_poses np.array(ann[grasp_poses], dtypenp.float32) grasp_widths np.array(ann[grasp_widths], dtypenp.float32) grasp_scores np.array(ann[grasp_scores], dtypenp.float32) # 取出第 0 个抓取拆成位置和旋转 pose grasp_poses[0] position pose[:3, 3] # 夹爪坐标系原点在场景坐标系下的位置 rotation pose[:3, :3] # 旋转矩阵列向量分别对应夹爪的 x/y/z 轴 width grasp_widths[0] # 用旋转矩阵把夹爪 z 轴方向投影到场景坐标系 gripper_z rotation[:, 2] # 这个方向用于后续的碰撞检查和姿态过滤 print(接触点坐标:, position) print(夹爪宽度:, width) print(夹爪闭合方向:, gripper_z)这段代码解决的是看懂标注的问题。写训练逻辑之前一定要先跑一遍这类读取代码把数据打印出来看一眼点云坐标范围是不是真实物理尺寸、位姿矩阵是不是落在物体表面附近、宽度值是否在夹爪行程内。我习惯把每个场景的标注可视化出来用 open3d 同时画场景点云和夹爪模型这一步能发现至少一半的数据问题。特别要检查的是旋转矩阵的行列式是否接近 1如果等于 -1说明坐标系是镜像的后续训练会反复抖动。2.2 从公开数据集到自采数据一个可用的转换思路GraspNet-1Billion 这类大规模抓取数据集提供了几百个场景、上亿级别的抓取标注但它覆盖的物体和你的实际工况往往存在差距。工业现场的工件、物流场景的包装盒、家庭场景的杯子形态差异都很大。常见的做法是先用公开数据训练一个基座模型再用自采数据做微调。自采数据的关键不是采集 RGB 图而是获得带标注的抓取位姿。import open3d as o3d import numpy as np # 读取深度相机生成的点云做体素降采样和裁剪 pcd o3d.io.read_point_cloud(my_object.ply) pcd pcd.voxel_down_sample(voxel_size0.005) # 5mm 体素兼顾分辨率和内存 # 手动选取桌面上方的物体区域 bbox o3d.geometry.AxisAlignedBoundingBox( min_boundnp.array([-0.3, -0.3, 0.0]), max_boundnp.array([ 0.3, 0.3, 0.5]) ) pcd_cropped pcd.crop(bbox) points np.asarray(pcd_cropped.points) # 如果点少于预期说明深度图丢帧或裁剪范围不对 assert points.shape[0] 5000, f点数太少只剩 {points.shape[0]} 个点把点云转成训练样本的核心是你需要在点云上生成候选抓取然后做物理碰撞检测过滤掉与桌面或物体相交的位姿。这一步如果没有现成工具可以先用最简单的规则把每个点作为接触点把夹爪闭合方向旋转到与局部法线垂直再把宽度设置为物体局部厚度的 1.2 倍。这样生成的标签噪声很大但用来微调一个预训练模型是够用的。参数上我一般把 voxel_size 设为 0.005 米点云点数上限设 30000超过就随机采样这组参数在大部分抓取任务里表现都比较稳。3. 模型结构从深度图点云到抓取位姿的完整推理链路3.1 抓取提议与评估两个子网络为什么拆分6dof-graspnet 的完整模型链路由两部分组成抓取提议网络和抓取评估网络。第一阶段输入场景点云输出一组稀疏的候选抓取包括接触点位置、抓取方向和夹爪宽度第二阶段把每个候选抓取在局部区域重新编码输出一个质量分数。拆成两段的好处是计算量可控——第一阶段做密集采样第二阶段只对少量候选做精打分。如果只保留一个网络直接回归最终位姿候选抓取数量会爆炸训练也很难收敛。import torch # 示意结构输入点是 (B, N, 3)经过体素化后进入主干网络 def forward_inference(points, model_gpn, model_eval, k200): # points: 场景点云形状 (N, 3)需要先做中心化和归一化 point_cloud torch.from_numpy(points).float().unsqueeze(0).cuda() # 第一个网络抓取提议 # 输出 graspness 分数表示每个点附近有多大可能存在可行抓取 graspness model_gpn(point_cloud) # 形状 (1, N) # 选出分数最高的 k 个点作为接触点候选 topk_idx torch.topk(graspness, kk, dim1).indices[0] selected_points point_cloud[0, topk_idx] # (k, 3) # 第二个网络对每个候选评估质量 # 这里会把每个接触点周围半径 0.1m 内的点取出来做局部编码 quality model_eval(selected_points) # 形状 (k,) return selected_points, quality这段示意代码展示了推理时的数据流。注意两个网络输入数据的差异提议网络看全场景评估网络只看局部。实际训练时提议网络和评估网络是分开训练的先训提议网络再固定提议网络去训评估网络。不要一边端到端联合训练否则评估网络会依赖提议网络的中间特征导致部署时两个网络必须同时在线推理链路变脆。3.2 可落地的深度学习环境配置miniconda、PyTorch 与显存预算这个项目对深度学习环境的要求不低。官方实现基于 PyTorch并且依赖 Open3D、NumPy、SciPy 等库。环境配置是复现时翻车率最高的环节核心问题集中在 CUDA 版本和 PyTorch 版本不匹配、Open3D 与 Python 版本冲突这两处。我一般用 miniconda 创建独立环境把 Python 版本固定在 3.8 或 3.9避免系统自带 Python 被污染。# 创建独立环境Python 版本锁定 3.8 conda create -n graspnet python3.8 -y conda activate graspnet # 安装 PyTorch注意 cudatoolkit 版本要和驱动匹配 conda install pytorch1.12.0 torchvision0.13.0 cudatoolkit11.3 -c pytorch -y # 安装点云处理和科学计算依赖 pip install open3d0.16.0 numpy scipy # 克隆代码后安装项目依赖以项目内 requirements.txt 为准 pip install -r requirements.txt参数说明Python 3.8 是最稳妥的选择Open3D 0.16 对 Python 3.8 的 wheel 最全cudatoolkit 11.3 可以兼容大部分 RTX 30 系显卡如果你的卡是 40 系需要把 PyTorch 升到 2.x、CUDA 升到 12.x。显存方面推理单张场景点云需要 6~8GB 显存训练抓取提议网络一张 24GB 的卡勉强能跑小 batch完整训练建议用 4 张 24GB 卡或者直接租服务器跑深度学习。我自己的经验是不要在一张 8GB 卡上尝试全量训练光是把 30000 个点的特征塞进显存就会直接 OOM。3.3 训练脚本参数与日志判读loss 下降了不代表抓取成功训练命令看起来和普通 PyTorch 项目差不多但有几个参数直接决定训练是否有效。第一个是是否加载预训练权重第二个是点云采样策略第三个是摩擦系数。很多人在小数据集上从零训练结果 loss 不降这不是代码问题而是数据太少、网络过拟合到噪声上了。# 常见的训练命令格式具体参数以仓库内脚本为准 python train.py \ --dataset_root /data/graspnet \ --num_epochs 200 \ --batch_size 4 \ --lr 0.001 \ --num_point 30000 \ --voxel_size 0.005 \ --pretrained ./checkpoints/pretrained_model.pth参数说明dataset_root 指向数据集根目录目录结构不能改否则数据加载器会报路径错num_point 是每次输入网络的点云点数太大影响显存太小丢失几何细节voxel_size 是体素化分辨率0.005 对应 5mm适合小物体场景如果是托盘上的大箱子可以调到 0.01pretrained 建议填上预训练权重从零训练的成本很高。训练日志里我一般盯两个指标一是验证集上的抓取成功率二是每个类别的平均精度而不是只看总 loss。你经常看到的现象是 loss 稳步下降到某个平台但评估结果依然很差这说明网络在背数据而不是学抓取。遇到这种情况第一时间检查数据增强点云有没有随机旋转、有没有做高度扰动、夹爪宽度有没有做抖动。没有增强的抓取模型在小数据上极易过拟合loss 好看但实际一抓就掉。4. 评估与推理仿真 AP 和真实机械臂之间隔着什么4.1 用评估脚本输出 AP 曲线命令、参数与结果解读训练完模型后不要急着接机械臂先在仿真数据上跑一遍评估算出不同摩擦系数下的抓取成功率曲线。这一条评估曲线能回答我的模型到底学到了什么程度。评估脚本通常会遍历测试集的所有场景对每个场景生成候选抓取再和标注做匹配最终输出平均精度。# 评估命令的一般形式 python evaluate.py \ --dataset_root /data/graspnet \ --checkpoint ./checkpoints/final_model.pth \ --num_evaluations 200 \ --friction_coefficient 0.5参数说明num_evaluations 是每个场景采样的抓取候选数量数量越大评估越稳但耗时线性增长我一般设 200friction_coefficient 是接触模型的摩擦系数0.5 对应常见塑料/金属表面如果工件表面很光滑比如玻璃瓶建议设置成 0.3这时候 AP 会明显下降这是正常的物理上本就更难抓。解读 AP 结果时有一个常见误区只看整体 AP。我建议按物体类别拆开看特别是把已知物体和未知物体的 AP 分开统计。如果已知物体 AP 高、未知物体 AP 低说明网络记住了物体形状如果两者差距不大说明网络学到了真正的几何可抓性。后者才是 6dof-graspnet 这类方案的价值所在。4.2 把位姿换算到机械臂基座手眼标定与坐标系变换仿真评估通过后接真实机械臂要解决一个关键问题网络输出的位姿在相机坐标系下而机械臂运动需要基座坐标系下的位姿。两者之间隔着一个手眼变换矩阵这个矩阵通过手眼标定获得。常见的实现是 eye-to-hand 结构相机固定在支架上标定得到的是相机到机器人基座的变换 T_cam_to_base。import numpy as np # T_cam_to_base通过手眼标定得到相机坐标系到机器人基座坐标系 T_cam_to_base np.load(calibration.npy) # 4x4 齐次矩阵 # 网络输出的抓取位姿夹爪坐标系到相机坐标系 T_grasp_in_cam np.eye(4) T_grasp_in_cam[:3, :3] rotation # 来自网络输出的旋转 T_grasp_in_cam[:3, 3] position # 来自网络输出的位置 # 换算到机械臂基座坐标系 T_grasp_in_base T_cam_to_base T_grasp_in_cam # 机械臂运动学接口通常需要位置 四元数 from scipy.spatial.transform import Rotation as R quat R.from_matrix(T_grasp_in_base[:3, :3]).as_quat() # xyzw 顺序这段代码的坑在于旋转矩阵到四元数的顺序。PyTorch 和 scipy 默认输出顺序不一样机械臂控制库又可能要求 wxyz 顺序或者 xyzw 顺序三个环节只要一个没对齐末端姿态就是反的。我踩过这个坑之后每次写完坐标变换代码都会先打印一个已知位姿做验证把机械臂移到某个固定姿态读实际四元数再和变换代码算出来的对比对上才继续。另一个容易忽略的环节是点云裁剪。网络训练时输入的是一整张桌面点云还是裁剪后的工件点云决定了部署时你要不要做预处理。我一般会在推理前先做两件事用 RANSAC 提取桌平面并移除再根据工作台尺寸裁剪出感兴趣区域。把不属于工作范围的背景点发到网络里轻则影响抓取分数排序重则在平面上生成一堆伪抓取位姿。5. 复现 6dof-graspnet 的 5 个高频踩坑记录5.1 环境编译与依赖版本不匹配现象按照 README 安装依赖后import graspnet 直接报错提示找不到某个 .so 文件或者 Open3D 版本冲突代码里读取点云的函数和库内部实现不兼容。原因深度学习环境的 Python 版本和点云库的编译版本不匹配。6dof-graspnet 这类项目通常依赖多个编译型库任何一环版本漂移都会在导入时报错。最新热词里深度学习环境配置相关的提问半数以上都卡在这一步。解决严格按照 2.2 小节的 conda 环境方式安装先创建全新环境逐条安装锁定版本的依赖每装一个就 import 测试一下。不要用 pip 直接往系统环境里塞也不要让 conda 和 pip 混着装同一套库。装完后打开 Python 交互命令行手动 import open3d 和项目主模块确认全部通过再开始训练。5.2 训练 loss 不降或者指数爆炸现象loss 在前几十个 epoch 里没有明显下降或者直接变成 nan。点云数据是 float32 且包含无效点或距离很远的杂点。原因数据归一化没做干净。点云坐标如果包含 NaN 或者极端离群点loss 反向传播时梯度会爆炸。另一个常见原因是学习率设置过大抓取网络对姿态回归比较敏感。解决先检查数据预处理里的合法性过滤把超过工作空间边界的点、深度值为 0 的点、坐标为 NaN 的点全部剔除。然后把学习率从默认的 0.001 降到 0.0005 试一个短的训练周期观察前 20 个 epoch 的 loss 是否稳定下降。如果还是爆炸把 batch_size 减半有时候是显存不够导致的静默截断。5.3 数据路径结构不对导致加载失败现象训练启动时报错提示找不到某个场景目录或者提示数据文件缺失。明明下载了数据集目录结构也和文档一致。原因数据集往往附带一个检查脚本它会校验目录树的完整结构。很多人只下载了标注文件漏掉了场景点云或者未标注物体的点云文件。另外Windows 环境下的路径分隔符和 Linux 不一致也会导致相对路径拼接错误。解决先运行数据集自带的 check 脚本确认全部文件就位然后确认代码里数据集根目录是绝对路径还是相对路径运行时的工作目录是否和预期一致。我一般会在启动训练前用脚本打印一个场景的完整文件列表看到实际路径后再决定改代码还是改目录软链接。5.4 推理结果里出现大量穿过桌面的位姿现象模型输出的抓取位姿有不少是插进桌面的接触点在桌面以下或者夹爪闭合方向指向桌面内部。这些位姿在可视化时非常明显。原因训练数据里如果有大量桌面点网络会学到桌面附近存在抓取候选的假模式。推理时又没做桌面点过滤就把桌面当成了可抓物体。另一个原因是评估时的摩擦系数设置过高物理上不可能实现的接触被算成了可行。解决训练前把数据里的桌平面点移除或者至少将桌面区域标注为不可抓取。推理时用 RANSAC 平面检测把桌面点云做分割只把物体点云输入网络。同时把评估摩擦系数从默认的 0.5 降到 0.3~0.4看位姿分布是否更合理。5.5 真实机械臂抓取时位姿反转、角度偏差大现象同样的模型仿真里 AP 很好一上真实机械臂末端到达的位置和朝向明显不对甚至夹爪朝反方向闭合。原因坐标变换链某一环符号错了。最常见的是手眼标定矩阵方向反了相机到基座变成了基座到相机其次是旋转矩阵到四元数的顺序问题再就是相机深度图本身做了镜像翻转导致点云左右颠倒。解决不要直接上真实机械臂调试。先做离线验证拍一张已知物体的点云让网络输出位姿再用标定矩阵做变换最后把变换结果显示在点云上。确认可视化里夹爪方向是朝物体而不是朝下、朝外。然后做一次空跑抓取机械臂移动到输出位姿但不闭合夹爪人工观察朝向是否正确确认后再实际抓取。6. 进阶把 6dof-graspnet 部署到真实机械臂的三个增量技巧第一个技巧是抓取位姿的时域稳定性验证。深度相机的单帧点云带有噪声网络偶尔会在连续几帧里输出差异很大的位姿。我用一个 5 帧的滑动窗口收集候选抓取只有当同一个接触点在 3 帧以上重复出现且位置偏差小于 2 厘米时才把它送过去做质量打分。这个技巧能过滤掉超过一半的抖动位姿对抓取成功率的提升比调模型参数还明显。第二个技巧是路径规划阶段考虑夹爪的进入方向。6dof-graspnet 输出的位姿是抓取接触点处的姿态但机械臂在执行时末端要沿着夹爪轴线从远处平移到接触点。如果中间有障碍物最常见的做法是让机械臂先退到接触点法线方向 15 厘米处再直线进给。这个提前量需要在运动规划代码里手动加上模型本身不会给你这条路径。第三个技巧是抓取质量阈值不要固定。我习惯把阈值设成一个自适应值取当前场景所有候选抓取质量分数的中位数中位数以下全部丢弃中位数以上按分数从高到低逐个尝试。这样在物体密集、整体抓取难度大的场景里机械臂至少会去试最优的那几个候选而不是死等一个超过固定阈值的位姿。难点场景下成功率比固定阈值高 10 个百分点左右。这三个技巧做完整个 6dof-graspnet 从训练到部署的链路才算闭环。我现在做抓取项目时已经不看整体 loss而是直接看机械臂连续 50 次抓取的成功数和失败时的点云快照。每个失败快照都留着隔几天回看能发现一堆训练时想不到的边界情况。这条路我走了一年多最大的体会是抓取位姿估计不是黑匣子把数据、坐标系和环境三项基本功做扎实比换一个大模型更管用。希望帮到你。本文还有配套的精品资源点击获取
返回列表