免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

自然语言驱动的机械臂抓取:视觉语言模型与点云配准的融合实践

自然语言驱动的机械臂抓取:视觉语言模型与点云配准的融合实践 第一次做带自然语言指令的抓取测试时我盯着机械臂的轨迹看了很久——它明明识别到了用户说的“红色手柄螺丝刀”却还是把旁边那把黑色螺丝刀一起拨到了地上。问题不在视觉识别而在“识别”和“抓取”之间隔着一个六自由度位姿的鸿沟。这个项目的核心就是把视觉语言模型对场景的语义理解和点云配准对目标的精确定位串成一条完整链路再配合眼在手上的安装方式才能让机器人不仅能听懂人话还能把东西稳稳抓起来。这套方案解决的是无人工厂、家庭服务、科研实验中最常见的一类需求操作人员给出自然语言指令机器人在杂乱场景中自主找到目标、估计姿态、规划抓取。项目名称虽然带着“方法研究”四个字但落地属性很强——硬件选型、手眼标定、点云配准参数、VLM部署推理、抓取位姿生成每一环都有大量工程细节。这篇文章就按我实际做的顺序把整个系统从架构到排错完整复盘一遍。1. 项目要解决的痛点单靠视觉识别机器人“看得见”却“抓不着”先说结论传统目标检测方案在面对自然语言指令和杂乱场景时精度和泛化能力都不够用。这是我把视觉语言模型和点云配准拉到同一个系统里的根本原因。1.1 为什么传统视觉方案在这里失效常规的机器人抓取视觉模块走的是“目标检测 2D中心点 深度值”或者“6D位姿估计”这两条路子。但我在实际测试里发现它们各有各的硬伤。目标检测这条路先得为每个物体类别人工标注大量数据。我最早用的YOLOv8模型识别桌面上的螺丝刀、杯子、扳手这类物体没什么问题但指令一旦变成“拿那把红柄螺丝刀”模型就懵了——它只能输出“螺丝刀”这个类别框区分不了红色手柄和黑色手柄。而且2D检测框和物体的实际朝向之间没有任何直接关系矩形中心往点云上一投机器人的夹爪大概率抓在物体侧面一碰就倒。6D位姿估计这条路稍微好一点像PoseCNN、PVN3D这类方法能直接输出物体的位置和旋转但问题在于它们同样依赖“物体类别已知且有训练数据”这个前提。换一个没见过的物体模型就得重新标注、重新训练。在项目迭代阶段我经常是上午换一个目标物下午就得重新折腾数据集这种效率根本撑不起快速实验。更现实的问题是真实场景往往存在遮挡、反光、物体堆叠。我在桌面抓取实验里用深度相机拍一堆金属工具黑色螺丝刀表面在红外结构光下会直接“消失”一块点云2D检测框还在但深度图那一块是空洞。这种情况下无论是检测还是位姿估计都会给出一个错误的抓取点。1.2 视觉语言模型与点云配准的分工逻辑既然单靠哪一头都不行那就要让它们各干各擅长的事。视觉语言模型的长处是“语义理解”。它能把自然语言指令和图像内容对齐输出“目标在图像中的位置”或者“对应的语义分割区域”。比如用户说“把红色手柄的螺丝刀拿过来”Grounding DINO这类模型能直接框出红色手柄螺丝刀所在的区域CLIP或LLaVA能给出更细粒度的属性判断。但它输出的大多是2D信息做不到毫米级的空间位姿估计而且偶尔会幻觉——把不存在的物体也给你框出来。点云配准的长处正好相反。它不关心物体是什么类别只要我有一份目标物体的三维模型点云它就能把模型点云和实测场景点云对齐输出精确到毫米级的刚体变换矩阵。但它有一个前提得有一个“初始猜测”不然算法很容易掉进局部最优解把模型配到完全错误的位置上。而且它对语义一无所知给它一堆点云它能算出位姿但算不出“该抓哪个”。所以整个系统的分工就很清晰了视觉语言模型负责理解语义、锁定位目标的大致图像区域点云配准负责在三维空间里精确求解目标位姿眼在手上的相机安装方式负责让整个感知系统能贴着目标看清楚。三者合起来才构成一个“懂人话、看得准、抓得住”的完整闭环。2. 系统架构与手眼标定坐标系先拧成一股绳这一节是整个项目的地基。坐标系没对齐后面所有的配准和抓取都是空谈。我先说硬件和架构选型再说手眼标定的原理和实操方式。2.1 硬件选型与眼在手上的取舍我的实验平台是一台六轴协作机械臂末端安装了一台RGB-D深度相机再配上两指平行夹爪。相机装在机械臂末端这就是典型的眼在手上Eye-in-Hand结构。为什么选眼在手上而不是眼在手外对比下来有几个原因视野可以随机械臂移动机械臂靠近目标物之后相机离物体很近点云分辨率高细小物体的手柄、纹路都能看清。目标物被其他物体部分遮挡时机械臂换个观察角度就能绕开遮挡而固定相机只能干瞪眼。部署灵活不需要额外搭建相机支架整个系统跟着机械臂走。当然眼在手上也有代价。最明显的一点是相机位姿每次都在变所以系统必须依赖机械臂的运动学解算结果和手眼标定矩阵把相机坐标系下的点云实时变换到机械臂基座坐标系。如果机械臂的绝对定位精度差或者手眼标定矩阵不准那么配准结果的天花板就非常低。另外机械臂运动时相机会跟着晃如果深度相机的曝光和帧率跟不上点云会出现运动模糊和畸变。硬件选型上我用的是一台结构光原理的RGB-D相机工作距离0.3到1.5米近距精度大约±2毫米。这个精度在桌面抓取场景是够用的但如果你的目标物很小比如直径小于1厘米的螺丝建议换成更高精度的工业相机或者激光轮廓仪否则点云本身的噪声就会淹没配准算法的精度。2.2 AXXB手眼标定原理与实操眼在手上的标定问题数学上可以写成一个AXXB的方程。解释一下这个方程在说什么。机械臂末端从位姿P1运动到位姿P2时通过机械臂运动学可以算出末端坐标系的变化矩阵A同时相机在不同位置观察同一个固定标定板可以算出相机坐标系的变化矩阵B。因为相机和末端之间是一个固定不变的刚体变换X所以这两个变化矩阵之间就满足AXXB。解出这个方程就能得到相机相对于机械臂末端的位姿变换矩阵。实操时我用的步骤是在机械臂前方固定一块打印好的标定板棋盘格或Apriltag都可以保证机械臂在多个姿态下相机都能拍到完整的标定板。手动或通过脚本控制机械臂走15到20个不同姿态每个姿态下记录两个数据末端位姿从机械臂控制器读出和标定板在相机坐标系下的位姿通过OpenCV的solvePnP或AprilTag库算出。采集完成后用OpenCV的calibrateHandEye函数求解X输入就是A序列和B序列。求解出的X矩阵就是相机坐标系到末端的变换之后所有相机点云数据都要靠它变换到机械臂基座坐标系。这里有一个非常容易忽略的细节采集姿态时末端姿态的差异一定要拉开。我第一轮标定时偷懒机械臂只在很小的范围内微调结果解出来的X矩阵在重投影验证时误差达到了2厘米。后来重新采集让机械臂大范围俯仰、偏航标定精度立刻提升到5毫米以内。原理很简单AXXB的本质是通过多组大差异的观测来约束X如果姿态变化太小方程接近病态解出来的结果自然不可靠。2.3 标定质量验证不验证就是在给自己埋雷标定做完不能直接开跑我每次都会做两步验证。第一步是重投影验证。把标定板放到机械臂可到达的某个位置记录标定板的角点在图像上的2D位置再根据机械臂位姿、手眼矩阵、相机内参把这些角点的3D坐标投影回图像。如果投影点和实际像素点之间的误差稳定在2到3个像素以内说明标定是可靠的。第二步是实际平移验证。控制机械臂末端移动一个已知距离比如沿基座X轴平移100毫米观察相机坐标系下标定板的相对位移是否也是100毫米。这一步能直接检验整个坐标变换链路是否有系统性的尺度或旋转误差。我遇到过最坑的一次标定问题是相机和末端之间的安装法兰本身就有0.5毫米的加工公差。这个量级在标定求解时会被当成噪声吸收掉但机械臂换个姿态后误差会被放大到几毫米。后续测试中抓取位置总是偏一点排查了很久才用重投影误差分布曲线定位到这个安装公差。如果你也遇到“标定看起来没问题但抓取总偏”的情况先怀疑机械臂末端法兰和相机支架之间的机械连接再怀疑算法。3. 点云配准的工程化落地从模型点云到实测点云的精确对齐点云配准是整个系统里精度担当。我选用的方案是“粗配准 精配准”两级级联先用全局配准算法估计一个大致变换再用ICP做精修。这样既解决了ICP对初始值敏感的问题又保证了最终位姿精度。3.1 点云预处理把场景里的干扰清干净实测场景点云直接送进配准算法是不行的杂点、背景、地面点会疯狂干扰匹配。我每一步都是按下面的顺序处理的直通滤波PassThrough。根据机械臂工作空间和经验值把点云裁剪到一个固定大小的三维包围盒内只保留桌面以上的区域。这一步能去掉天花板、墙面、机械臂本体等大块无用点。体素降采样Voxel Downsample。我用5毫米的体素大小对点云降采样。降采样有两个好处一是减少点数让配准算法跑得更快二是均匀化点密度避免近处点云密度过大导致配准时偏向局部。统计离群点剔除Statistical Outlier Removal。深度相机在物体边缘会产生大量飞点这些孤立点会让配准时的对应点查找出现错误。我用的是每个点最近邻30个点的平均距离做阈值把距离分布偏差超过2倍标准差的点全删掉。预处理这步看似简单但对最终精度的影响比配准算法本身还大。我做过对比实验同样的场景不处理离群点时配准误差在15毫米左右处理完之后能压到3毫米以内。3.2 粗配准到精配准两级级联谁都不能省粗配准阶段我用的是快速全局配准FGRFast Global Registration。FGR基于点云局部特征FPFH的匹配关系做全局优化不需要好的初始值能在大范围内找到一个合理的变换。而ICP迭代最近点在局部精修上很猛但对初始值非常敏感初始误差超过一定范围就会陷进局部最优解。整个配准流程的核心代码如下基于Open3D实现import open3d as o3d import numpy as np def preprocess_pcd(pcd, voxel_size0.005): # 直通滤波只保留工作空间区域 pcd pcd.crop(o3d.geometry.AxisAlignedBoundingBox( min_boundnp.array([-0.5, -0.5, 0.0]), max_boundnp.array([0.5, 0.5, 0.8]))) # 体素降采样 pcd pcd.voxel_down_sample(voxel_size) # 统计离群点剔除 pcd, _ pcd.remove_statistical_outlier(nb_neighbors30, std_ratio2.0) return pcd def register_model_to_scene(model_pcd, scene_pcd, voxel_size0.005): # 预处理后的输入 source preprocess_pcd(model_pcd, voxel_size) target preprocess_pcd(scene_pcd, voxel_size) # 计算FPFH特征 source.estimate_normals( o3d.geometry.KDTreeSearchParamHybrid(radiusvoxel_size*5, max_nn30)) target.estimate_normals( o3d.geometry.KDTreeSearchParamHybrid(radiusvoxel_size*5, max_nn30)) source_fpfh o3d.pipelines.registration.compute_fpfh_feature( source, o3d.geometry.KDTreeSearchParamHybrid(radiusvoxel_size*10, max_nn100)) target_fpfh o3d.pipelines.registration.compute_fpfh_feature( target, o3d.geometry.KDTreeSearchParamHybrid(radiusvoxel_size*10, max_nn100)) # 第一阶段FGR粗配准 result_fgr o3d.pipelines.registration.registration_fgr_based_on_feature_matching( source, target, source_fpfh, target_fpfh, o3d.pipelines.registration.FastGlobalRegistrationOption( maximum_correspondence_distancevoxel_size*4)) # 第二阶段点面ICP精配准 result_icp o3d.pipelines.registration.registration_icp( source, target, max_correspondence_distance0.005, initresult_fgr.transformation, estimation_methodo3d.pipelines.registration. TransformationEstimationPointToPlane()) return result_icp.transformation这套流程里粗配准负责“找对方向”精配准负责“找准位置”缺一不可。我试过直接拿FGR的结果去抓取误差在5到8毫米抓大件物体也许够用但抓小圆柱体时夹爪会偏直接拿ICP从单位矩阵开始迭代则经常配到旁边的物体上去成功率惨不忍睹。3.3 关键参数和经验值从失败的实验里总结出来的配准这块的参数坑非常多。我列一下自己调稳定的几组参数并说明为什么这么设参数项推荐值设置逻辑体素降采样尺寸5mm太小则点云噪声大太大则丢失物体细节5mm在0.3-1米工作距离下平衡了速度和精度FGR最大对应距离20mm 4倍体素小于这个值则匹配数量不足粗配准容易失败ICP最大对应距离5mm精配准阶段要小才能保证收敛到最精细的局部最优ICP迭代次数50次实测30次基本收敛留冗余应对退化场景FPFH特征搜索半径50mm 10倍体素太小则特征没有区分度太大则计算量爆炸最近邻数量30兼顾法向估计稳定性和计算速度有一个很容易踩的坑是物体表面如果高度对称比如圆柱形水杯、球形物体点云配准会存在旋转方向上的退化情况。ICP可能收敛到了两个不同的姿态上都满足“点到面距离最小”但实际上一个是正的、一个是倒的。这个问题在数学上是配准的不可观性算法层面没法彻底解决只能靠上游VLM的语义信息来加约束——我后面专门加了一道判断用VLM给出的物体朝向先验来否决掉明显不合常理的配准结果。另外如果场景是高度重复的结构比如一排相同的孔洞板FPFH特征会非常相似粗配准也会翻车。这种情况下我会让机械臂移动到一个不同的视角重新采集点云靠多个视角的配准结果互相投票而不是寄希望于单帧点云一次配准成功。4. 视觉语言模型如何引导配准语义先验、ROI裁剪与初始位姿点云配准本身再强也得知道“要对齐哪个物体”。这就要靠视觉语言模型来完成从自然语言指令到三维感兴趣区域ROI的映射。4.1 视觉语言模型的推理链路我在这个项目里采用的是“Grounding DINO做检测 MobileSAM做分割”的组合方案。Grounding DINO 接收文本和图像输出目标物体的边界框MobileSAM 接收这个框的提示输出像素级的语义分割掩码。整个链路是将自然语言指令比如“红色手柄螺丝刀”作为文本提示输入Grounding DINO。模型输出候选边界框和置信度。取置信度最高的边界框作为MobileSAM的提示输入。MobileSAM输出该物体的像素级分割掩码。实际部署时我用了TensorRT对两个模型做了加速在单张显卡上单帧推理耗时大约800毫秒这个速度虽然不能实时但配合机械臂的“拍摄-推理-移动-再拍摄”的工作流完全够用。Prompt的写法直接影响模型的输出质量。实测下来描述里带上颜色、材质、空间关系比单说一个类别名要稳定得多。比如“拿红色的螺丝刀”比“拿螺丝刀”的检测置信度高不少如果目标物在场景里有多个同类物体“桌面上靠左的那个银色杯子”这种带空间约束的描述能显著降低误检。这一点和纯目标检测模型很不一样VLM是真的会去“读”指令里的每一个修饰词。4.2 从2D分割掩码到3D点云ROI拿到2D分割掩码之后还不能直接用得把它投影到3D点云上。这一步需要对齐RGB图像和深度图。RGB-D相机通常能直接输出对齐好的彩色图和深度图但不同相机品牌的对齐精度不一样我建议自己做一次标定校验不然掩码边缘的投影误差会被放大到三维空间里。投影过程如下根据相机内参焦距、主点把分割掩码内的每个像素坐标转换为相机坐标系下的归一化坐标。用深度值乘以归一化坐标得到每个像素点在相机坐标系下的三维坐标。用手眼标定矩阵和机械臂末端位姿把这些点变换到机械臂基座坐标系。这样我就能从完整场景点云中裁出一个只包含目标物的ROI点云再把这个ROI点云和模型点云做配准。ROI裁剪的好处非常大配准算法不再需要关心场景里的其他物体和背景既减少了误匹配又大幅加快了配准速度。这里有一个细节我想单独说一下如果分割掩码边缘不准ROI点云会带上背景物体的点导致配准结果偏移。所以我做掩码的时候会做一个形态学腐蚀操作把掩码向内缩几个像素宁可损失一点目标物边缘也不能混入背景点。4.3 初始位姿估计和VLM幻觉处理粗配准虽然不依赖初始值但如果初始值离真实位姿太远配准的收敛速度会慢很多甚至失败。我利用VLM的输出估计了一个更合理的初始变换用ROI点云的质心作为初始平移。用ROI点云的主成分分析PCA方向作为初始旋转的粗略估计。如果VLM还能给出物体的类别先验比如“杯子是竖直的”就再把初始旋转约束到竖直方向附近。这一招让FGR的迭代次数几乎减半而且配准失败率明显下降。VLM幻觉是这个方案里绕不开的另一个坑。所谓幻觉指的是模型在图像里根本没有目标物的情况下仍然给出一个不存在的边界框。我第一次做空桌面测试时指令是“拿蓝色的杯子”桌面上明明什么都没有Grounding DINO还是给了一个边界框置信度居然有0.6然后整个系统就像模像样地对着空气做了一次点云配准和抓取规划。处理幻觉的办法我总结为三道防线第一道设置边界框置信度阈值低于0.5直接拒绝。第二道检查ROI点云是否合理。如果ROI点云点数过少比如少于100点、点云直径和目标物尺寸差异太大直接判定为无效检测。第三道验证抓取位姿。把配准后的模型位姿投影回图像计算模型投影轮廓和分割掩码的重合度IoU低于阈值的配准结果直接丢弃并触发机械臂移动到新视角重新观察。三道防线叠加后我的系统在空桌面上的“幻觉空抓”次数降到了几乎为零。这个过程也说明了一个道理视觉语言模型负责的是“给线索”而不是“下结论”最终的抓取决策一定要过几何验证这一关。5. 抓取策略与真机部署仿真里跑得通真机上翻车才是开始定位问题解决之后抓取规划相对成熟但真机部署时依然有大量细节。我分三个阶段来复盘抓取位姿生成、仿真验证、真机调试。5.1 抓取位姿生成不只是“对准物体中心”配准得到的变换矩阵描述了目标物体在当前坐标系下的完整六自由度位姿但“知道物体在哪”和“知道怎么抓”是两回事。我生成抓取位姿时额外考虑了三个问题抓取方向。两指夹爪通常从目标物的两侧夹取最稳。对于圆柱体夹爪应沿径向夹持对于盘状物夹爪应沿轴向夹持。这个方向信息可以从配准后的模型点云的形态中提取比如计算点云在一个方向上的包围盒尺寸选择尺寸较短且表面平行的方向作为夹持方向。预抓取位置。机械臂不能直接从远处冲向抓取点需要先移动到目标物上方或侧方的一个偏移位置再沿夹持方向缓慢推进。我设置的预抓取偏移一般是目标物边界框对角线长度的1.2倍避免机械臂运动过程中碰倒其他物体。抓取高度的补偿。夹爪中心并不等于相机坐标系原点也不等于配准结果的原点。我用的夹爪两个指片的闭合中心与配准坐标系原点之间有一个固定偏移这个偏移量必须提前标定出来并叠加上去否则夹爪永远会偏几毫米。抓取位姿生成之后我还会在仿真里预演一遍整个轨迹确认机械臂不会和桌面、周边物体发生碰撞再下发到真机执行。5.2 仿真到实物部署差异比想象中大仿真我用的是Isaac Sim配合MoveIt做运动规划验证。仿真阶段一切顺利——机械臂每次都能规划出平滑无碰撞的轨迹抓取成功率高达95%以上。但一到真机各种问题全冒出来了。最大的差异在点云质量。仿真里的深度相机数据是理想无噪声的配准算法跑得又快又准真机的深度图在黑色物体、反光金属和玻璃表面会产生大面积噪声和空洞。我做了下面几个针对性处理对黑色物体增加相机曝光时间和激光投影强度用多帧点云叠加降噪。对反光表面在物体表面喷一层可水洗的显影剂不影响抓取实验结果。对玻璃等透明物体直接放弃深度信息改用多视角配准加VLM先验约束。第二大的差异是执行延迟。仿真里从拍摄到开始运动只需要1秒真机上VLM推理800毫秒、点云配准300毫秒、运动规划500毫秒整个感知-规划过程要2秒左右。这意味着机械臂的运动轨迹必须考虑目标物是否可能移动。如果目标物是静止的这个延迟无所谓如果目标是传送带上的物体就得引入目标跟踪模块或者把感知频率提高到10赫兹以上。5.3 真机调试踩坑记录从“偏了5毫米”到“完全抓错”调试阶段我记录了一堆问题这里挑三个最典型的放在表格里给同样做抓取的朋友参考现象根因解决方案夹爪总是偏向目标物右侧约5毫米手眼标定矩阵有系统性偏差重新做手眼标定采集时拉开姿态差异检查末端法兰安装公差目标物有纹理时配准很准纯色表面时配准漂移纯色表面FPFH特征区分度不够增加配准约束使用多视角点云合并后再配准VLM框出了目标但ROI点云里混入背景点掩码边缘不够精确对掩码做腐蚀同时缩小ROI包围盒的膨胀系数另外机械臂每次抓取失败之后我的重试逻辑不是简单地把机械臂挪回原位再来一次而是先移动到新视角重新拍摄点云重新跑一遍VLM和配准更新目标位姿后再抓。这个设计很关键因为失败往往意味着之前感知到的位姿已经不可靠了如果还用旧数据重试失败模式会反复重演。实测下来加入“失败后重感知”的重试机制后抓取成功率从75%提升到了90%以上。6. 实测效果与调参优先级哪些参数值得折腾项目跑完一轮我在标准测试集上记录了一些关键数据也给后续做类似系统的朋友一个参考基线。6.1 测试结果与时间开销测试场景是桌面上摆放8到12个日常物体杯子、螺丝刀、扳手、胶带、瓶子等随机遮挡程度中等。记录了三个维度的指标指标数值目标识别成功率VLM正确定位并分割95%点云配准成功率配准误差小于5毫米88%完整抓取成功率一次抓取成功不包含重试83%加入重试机制后的综合抓取成功率91%单次任务平均耗时拍摄到抓取完成8.5秒配准失败的主要来源是反光物体和透明物体这个问题属于物理传感器层面的限制短期内只能靠多视角融合来缓解很难完全消除。如果后续换更高精度的工业相机或者激光雷达这部分成功率还有提升空间。6.2 调参优先级先稳住几何再调语义这个项目调来调去我最大的心得是调参顺序千万别搞反。先调点云配准这条几何链路。确保工作空间内的标准物体在没有遮挡的干净场景下配准误差能稳定压到5毫米以内。如果这一步都达不到后面全是空中楼阁。几何链路里最优先检查的是手眼标定、深度相机内参、点云预处理参数这三项。再调VLM和ROI裁剪。确认模型在目标物体上能稳定生成完整的掩码且掩码投影到点云后不混入过多背景点。这一步我花了大量时间写Prompt、调置信度阈值效果提升非常明显。最后才调抓取策略。只有当感知模块的每一环都稳定了抓取姿势的优化才有意义。在调试工具方面我强烈建议把整个系统的中间过程全部可视化原始点云、ROI点云、配准后的模型点云、生成的抓取位姿、机械臂当前位姿全部画在同一个三维场景里。我调试时几乎不看日志文件直接看三维可视化一眼就能看出是哪一环出了问题。有一次配准结果偏了我看到可视化图像里模型点云和场景点云明显错开立刻定位到是FPFH参数设置的问题整个过程不到一分钟。6.3 后续可以扩展的方向这套系统的架构本身有很好的扩展性。我目前已经在尝试的方向包括把单目标抓取扩展为多目标连续抓取通过大语言模型把复杂的自然语言任务拆解为一系列子任务逐个执行。增加主动感知策略让机械臂在“看不清”的时候主动移动视角再观察而不是硬着头皮抓。引入机械臂力觉反馈在抓取的接触阶段做柔性控制减少对视觉精度的依赖。最后再分享一个小技巧。我每次调试时都会把机械臂基座、相机、目标物模型三个坐标系用不同颜色的坐标轴画出来。坐标系对齐了项目就成功了一半坐标系没对齐后面所有算法都是在给错误打补丁。这个习惯帮我省下了大量排查时间。
返回列表