19f1c3dca3ead.png

*来源: 第一届3D视觉创新应用竞赛 | 参赛者: 赵晨昊 | 单位:** 深圳大学 *

*硬件平台:** Orbbec Astra Pro 深度相机 + Zora P1 开发板 + 川崎6轴机器人 + 气泵与气动夹具 *

*GitHub:** RobotV_Disorderly-grabbing *


一、项目亮点速览 ✨

想象一下:工厂流水线上,零件乱七八糟地堆在箱子里,机械臂却能像人一样"看一眼"就精准抓起来——不用工人事先摆好,不用担心重叠遮挡。🏭

这不是科幻电影,而是这支团队用 RGB-D 相机 + 6轴机械臂 + 智能算法 实现的真实场景!

六大核心能力一览:

🏷️ 核心能力 🔧 技术实现 💡 亮点
📷 RGB-D 三维感知 Astra Pro 深度相机实时采集点云 毫米级深度精度,直接获取三维信息
🤖 6轴自由抓取 川崎6轴机器人 + 气动夹具 任意姿态下稳定抓取,适应复杂工件
🎯 无序抓取 平面拟合 + 法向量求解抓取姿态 任意摆放都能抓,告别"排排坐"时代
📐 4点手眼标定 SVD分解求解 RT 矩阵 快速标定,无需强度信息
🧠 智能点云处理 聚类分割 + 区域生长 + 直通/体素滤波 自动识别目标,滤除干扰
🔗 UDP 实时通信 Qt 封装网络通信,机器人秒响应 低延迟,工业级可靠性

二、背景与意义 🌍

2.1 行业痛点:2D视觉的"天花板"

基于 2D 机器视觉的平面抓取技术,在工业界已经非常成熟——但有一个致命前提:

⚠️ 2D方案的硬伤 💥 实际后果
零件必须同一平面分开摆放 需要人工预先排列,增加工序
不能有重叠或遮挡 杂乱料箱直接"瞎眼"
只定位二维位置,无三维姿态 无法适应复杂工件的抓取角度

在汽车装配、工件制造等实际生产中,零件往往是杂乱无章地堆放在料箱里的。这时候,传统2D视觉方案直接"躺平"……😅

2.2 我们的思路:上3D!

核心idea: 用 RGB-D 相机获取真实三维点云 → 智能算法分析工件姿态 → 机械臂以正确角度精准抓取

🆚 对比维度 📸 2D 视觉方案 🎯 本方案(RGB-D + 3D)
摆放要求 必须整齐排列 ✅ 任意摆放,乱堆也行
重叠/遮挡 ❌ 无法处理 ✅ 通过三维信息区分
抓取姿态 仅2D位置 ✅ 6维位姿(X, Y, Z, O, A, T)
适用场景 简单平面分拣 ✅ 复杂工业场景

三、系统硬件架构 🛠️

3.1 硬件全家福

🔩 设备 📋 型号/规格 🎯 功能 ⭐ 关键特性
💻 开发板 Zora P1(奥比中光定制) 边缘计算主控,运行视觉算法 适配 Astra 系列相机,支持 Ubuntu/Android
📷 深度相机 Astra Pro(单目结构光) RGB + Depth 数据采集 0.6m~8m 深度范围,640×480 分辨率
🦾 工业机器人 川崎 6轴机器人 执行抓取动作 6自由度,高精度重复定位
🔧 末端执行器 气动夹具 抓取工件 气泵驱动,夹持力可调
🌬️ 气源系统 气泵 + 电控柜 为夹爪提供动力 稳定气压输出
🖥️ 上位机 PC(开发/调试) 算法开发、编译、监控 Qt 集成开发环境

3.2 系统拓扑

19f1c4a8bce33.png

3.3 川崎6轴机器人运动参数

机器人末端执行器的空间位姿由 6个参数 描述:

参数 含义 说明
X 末端 X 坐标 沿世界坐标系 X 轴位置(mm)
Y 末端 Y 坐标 沿世界坐标系 Y 轴位置(mm)
Z 末端 Z 坐标 沿世界坐标系 Z 轴位置(mm)
O 绕 X 轴旋转角 Roll(翻滚角),度
A 绕 Y 轴旋转角 Pitch(俯仰角),度
T 绕 Z 轴旋转角 Yaw(偏航角),度

💡 关键理解: 传统的2D抓取只需要 (X, Y),而本方案通过 RGB-D 相机获取的深度信息,额外计算出 Z 高度 + 三个旋转角 (O, A, T),实现真正的 6-DOF(六自由度)抓取!


四、系统整体流程 🎬

Image Prompt: Minimalist vector hand-drawn flowchart, 16:9 aspect ratio. Five-stage pipeline diagram showing the complete grasping workflow from left to right: (1) Astra Pro camera icon with RGB+D label → (2) Point cloud preprocessing block (filtering + downsampling) → (3) Region Growing segmentation block → (4) Plane fitting + normal vector calculation → (5) Kawasaki robot arm executing grasp. Each stage is connected by arrows, with brief labels underneath. Color scheme: blue for processing blocks, orange for input/output, clean hand-drawn technical style.

4.1 从"看到"到"抓到"的完整链路

19f1c4d6424dd.png

4.2 软件模块划分

🧩 模块 📦 核心组件 🔑 关键技术
视觉感知模块 Astra SDK + OpenNI 深度图→点云转换、实时采集
点云处理模块 PCL 1.8 直通滤波、体素滤波、区域生长分割
姿态估计算块 OpenCV 3.2 + Eigen 平面拟合、法向量、Rodrigues变换
手眼标定模块 SVD分解 4点标定法、坐标系转换矩阵
通信控制模块 Qt + QUdpSocket UDP协议、机器人指令发送

五、核心算法详解 🔬

5.1 点云采集与预处理

5.1.1 从深度图到点云

Astra Pro 通过 OpenNI SDK 输出每帧的 3D 点云数据,核心代码:

// 初始化 Astra 并读取点云
void readPoint(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{
    astra::initialize();
    astra::StreamSet streamSet;
    astra::StreamReader reader = streamSet.create_reader();
    reader.stream<astra::PointStream>().start();
    
    astra::Frame frame = reader.get_latest_frame();
    const auto depthFrame = frame.get<astra::PointFrame>();
    
    for (size_t i = 0; i < 640 * 480 - 1; i++) 
    {
        astra::Vector3f pixelValue = depthFrame.data()[i];
        pcl::PointXYZ point;
        point.x = pixelValue.x;
        point.y = pixelValue.y;
        point.z = pixelValue.z;
        // 深度范围过滤:保留 580mm~630mm 工作距离内的点
        if (pixelValue.z < 580 || pixelValue.z > 630 || pixelValue.y < -150)
            continue;
        cloud->push_back(point);
    }
}

📌 关键细节: 代码中通过 z < 580 || z > 630 将工作距离锁定在 620mm ± 10mm 范围内,有效剔除背景和前景干扰。

5.1.2 直通滤波(PassThrough)

限定 Z 轴范围,去除超出工作区域的无效点:

pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud(cloud);
pass.setFilterFieldName("z");
pass.setFilterLimits(0.0, 1.0);  // 保留 0~1m 范围内的点
pass.filter(*indices);

5.1.3 区域生长分割(Region Growing)

这是整个系统的核心分割算法,利用法向量相似性将散乱点云聚类为独立物体:

pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimator;
normal_estimator.setSearchMethod(tree);
normal_estimator.setInputCloud(cloud);
normal_estimator.setKSearch(50);
normal_estimator.compute(*normals);

pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg;
reg.setMinClusterSize(50);       // 最小聚类点数
reg.setMaxClusterSize(3000);     // 最大聚类点数
reg.setSearchMethod(tree);
reg.setNumberOfNeighbours(30);  // 邻域搜索点数
reg.setInputCloud(cloud);
reg.setInputNormals(normals);
reg.setSmoothnessThreshold(3.0 / 180.0 * M_PI);  // 平滑阈值(弧度)
reg.setCurvatureThreshold(1.0);                   // 曲率阈值

reg.extract(clusters);  // 输出:每个 cluster 的点索引集合

区域生长算法原理:

19f1c509c0f79.png

💡 为什么区域生长适合这个场景? 木块由平面构成,同一平面上的点法向量方向一致,不同平面(如相邻木块)法向量差异大,因此区域生长能天然地将接触但朝向不同的木块分开。

5.2 抓取姿态求解(核心算法 ⭐)

这是整个系统最精彩的部分——从一堆点云到机器人抓取指令的完整推导。

19f1c5506f256.png

5.2.1 平面拟合:找抓取面

从分割出的最大聚类中,拟合出最优平面并提取法向量:

void get2RandomPlaneR(std::vector<cv::Vec4f>& inCloud, cv::Vec4f &Plane, double th)
{
    // 使用 RANSAC 或最小二乘法拟合平面
    // 输出:Plane = (A, B, C, D),其中 (A,B,C) 为法向量,D 为截距
    // ...
}

5.2.2 中心点求解:抓哪里?

将目标聚类中的所有点坐标取平均,得到抓取中心点:

void Calpoint(const std::vector<cv::Vec4f> ptCloud, cv::Vec3f &centerPt)
{
    int ptNum = ptCloud.size();
    for (int i = 0; i < ptNum; i++) {
        centerPt[0] += ptCloud[i][0];  // X 累加
        centerPt[1] += ptCloud[i][1];  // Y 累加
        centerPt[2] += ptCloud[i][2];  // Z 累加
    }
    centerPt = centerPt / ptNum;  // 取平均 → 中心点坐标
}

5.2.3 抓取姿态计算:以什么角度抓?

这是算法的精髓——利用平面法向量推导出机器人的三个旋转角 (O, A, T):

// 平面法向量(抓取方向)
cv::Vec3f Vec_N;
Vec_N[0] = planeParm[0];  // 法向量 X 分量
Vec_N[1] = planeParm[1];  // 法向量 Y 分量
Vec_N[2] = planeParm[2];  // 法向量 Z 分量

// 基向量(机器人基座 Z 轴方向)
cv::Vec3f Vec_Base = cv::Vec3f(0, 0, 1);

// 叉乘求旋转轴
cv::Vec3f Vec_new = CrossProduct_3Pt(Vec_N, Vec_Base);

// Rodrigues 公式:旋转轴 → 旋转矩阵
Mat1f M = Mat1f::zeros(3, 3);
Rodrigues(Vec_new, M);

// 从旋转矩阵中提取欧拉角(O, A, T)
float Angle_O, Angle_A, Angle_T;

// Pitch(俯仰角 A):绕 Y 轴旋转
Angle_A = atan2(sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]), M[2][2]);

// 特殊处理:A ≈ 0° 或 A ≈ 180° 时的奇异性
if (abs(Angle_A - 0.0) < 1E-2) {
    Angle_O = 0;
    Angle_T = atan2(-M[0][1], M[0][0]);
} else if (abs(Angle_A - PI) < 1E-2) {
    Angle_O = 0;
    Angle_T = atan2(M[0][1], -M[0][0]);
} else {
    Angle_O = atan2(M[1][2] / sin(Angle_A), M[0][2] / sin(Angle_A));
    Angle_T = atan2(M[2][1] / sin(Angle_A), -M[2][0] / sin(Angle_A));
}

// 弧度 → 角度
Angle_O = Angle_O * 180.0 / PI;
Angle_A = 180 - (Angle_A * 180.0 / PI);  // 注意:A 取补角
Angle_T = Angle_T * 180.0 / PI;

🎯 一句话概括: 抓哪里 = 点云中心点,以什么角度抓 = 平面法向量 → Rodrigues → 欧拉角

5.2.4 刚体变换:从相机坐标系到机器人坐标系

void RigidTransPtCloud(std::vector<cv::Vec4f> &srcV, Matrix4f trsM)
{
    for (unsigned int i = 0; i < srcV.size(); i++)
    {
        // 对每一个点执行 4×4 变换矩阵乘法
        float nX = trsM(0,0)*srcV[i][0] + trsM(0,1)*srcV[i][1] 
                 + trsM(0,2)*srcV[i][2] + trsM(0,3);
        float nY = trsM(1,0)*srcV[i][0] + trsM(1,1)*srcV[i][1] 
                 + trsM(1,2)*srcV[i][2] + trsM(1,3);
        float nZ = trsM(2,0)*srcV[i][0] + trsM(2,1)*srcV[i][1] 
                 + trsM(2,2)*srcV[i][2] + trsM(2,3);
        srcV[i][0] = nX; srcV[i][1] = nY; srcV[i][2] = nZ;
    }
}

5.3 手眼标定:4点 SVD 法 🎯

手眼标定的本质: 求解相机坐标系 → 机器人基座坐标系的变换矩阵

团队采用了一种快速4点标定法,无需强度信息:

// 用 4 对已知对应点,通过 SVD 分解求解 RT 矩阵
int ComputeRT_3D(std::vector<Vec3d>& M, std::vector<Vec3d>& D, Mat1d & R, Mat1d & T)
{
    // M = 机器人工件坐标系下的 4 个点坐标
    // D = 相机点云坐标系下对应的 4 个点坐标
    // 通过 SVD 分解求解最优旋转矩阵 R 和平移向量 T
    // ...
}

// 构建 4×4 齐次变换矩阵
Mat1d RT = Mat1d::eye(4, 4);
R.copyTo(RT(Rect(0, 0, 3, 3)));  // 左上 3×3 填入 R
RT(0, 3) = T[0][0];              // 第4列前3行填入 T
RT(1, 3) = T[1][0];
RT(2, 3) = T[2][0];
// RT = [R | T]
//      [0 | 1]

SVD 求解 RT 的数学原理:

给定两组对应点 {M_i} 和 {D_i},i = 1..4

1. 计算质心:
   μ_M = (1/4)Σ M_i     μ_D = (1/4)Σ D_i

2. 去中心化:
   M'_i = M_i - μ_M      D'_i = D_i - μ_D

3. 构造协方差矩阵:
   H = Σ D'_i · M'_i^T

4. SVD 分解:
   H = U · Σ · V^T

5. 最优旋转矩阵:
   R = V · U^T

6. 平移向量:
   T = μ_M - R · μ_D

7. 齐次变换矩阵:
   RT = | R   T |
        | 0   1 |

📐 标定精度: 受视觉系统重建误差影响,手眼标定匹配误差均值为 1.5mm

5.4 UDP 通信:Qt 封装 📡

// Qt UDP 通信封装
QUdpSocket xx;
xx.bind(QHostAddress("192.168.0.15"), 60000);  // 绑定本地端口

// 将抓取指令打包发送
cv::Vec6f buf(centerPt[0], centerPt[1], centerPt[2], Angle_O, Angle_A, Angle_T);
char BUF[100];
sprintf(BUF, "%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,4,0", 
        buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);

// 发送给机器人控制器
xx.writeDatagram(BUF, sizeof(BUF), QHostAddress("192.168.0.2"), 60003);

通信协议设计:

字段 格式 示例 说明
X float 123.4 抓取点 X 坐标(mm)
Y float 56.7 抓取点 Y 坐标(mm)
Z float 89.0 抓取点 Z 坐标(mm)
O float 0.0 Roll 角度(度)
A float 135.0 Pitch 角度(度)
T float 45.0 Yaw 角度(度)
工具号 int 4 气动夹具编号
速度 int 0 运动速度档位

六、研发踩坑全记录 🧩

每个成功的项目背后,都有一部"血泪史"——这支团队也踩了不少坑,记录下来供后来者参考 👇

6.1 已解决的问题 ✅

🐛 问题 🔍 根因 ✅ 解决方案
点云精度差 Astra Pro 在 620mm 处平面标准差达 1.43mm,点云分层 多次采集取平均 + 滤波后求中心点/法线来"抹平"误差
4PCS+ICP 配准失败 点云精度差导致匹配结果不鲁棒 放弃配准方案,改用平面拟合 + 中心点直接求解
开发板编译死机 Zora P1 内存较小,PCL 库加载时内存溢出 换用 PC 进行编译和运算
flann 库冲突 OpenCV 和 PCL 各自携带 flann,版本不兼容 手动指定链接顺序,解决编译冲突

6.2 已知局限 ⚠️

⚠️ 局限 📝 说明 🚀 改进方向
深度精度有限 标准差 1.43mm,Z 方向抓取误差 2mm 换用条纹结构光相机
仅支持平面工件 当前方案依赖平面拟合 引入模板匹配,支持复杂几何体
无路径规划 直接发送抓取指令,无避障 增加运动规划模块
开发板算力不足 Zora P1 无法流畅运行完整算法 升级到 Jetson Orin 级别开发板

6.3 点云精度分析

团队对 Astra Pro 的深度精度做了量化测试,结果如下:

📊 指标 📐 数值 📝 说明
工作距离 620mm 优化后的最佳工作距离
平面标准差 1.43mm 主要误差来源
正负最大距离 9mm 最坏情况下的偏差
正负平均距离 1.22mm 平均偏差
手眼标定误差 1.5mm 4点 SVD 法
X/Y 抓取误差 0.5mm 控制系统补偿后
Z 抓取误差 2mm 受深度精度限制
角度误差 0.8° 控制系统补偿后
19f1c582e94b1.png

七、技术栈总览 🛠️

🗂️ 类别 🔧 技术选型 📋 版本/说明
操作系统 Ubuntu 16.04 / 18.04
编程语言 C++ C++11 标准
深度相机 SDK OpenNI / Astra SDK 奥比中光官方
点云处理 PCL(Point Cloud Library) 1.8
图像处理 OpenCV 3.2
线性代数 Eigen 矩阵运算、SVD分解
GUI 框架 Qt 5.x,集成界面 + 网络通信
网络通信 QUdpSocket UDP 协议
开发板 Zora P1 奥比中光定制 ARM 开发板
机器人 川崎 6轴机械臂 以太网通信
末端执行器 气动夹具 气泵驱动

八、技术创新亮点 💡

8.1 四大核心创新

🏷️ 创新点 📝 说明 🆚 传统方案对比
🎯 4点快速手眼标定 无需强度信息的 SVD 标定法,操作简单 传统方法需专用标定板,步骤繁琐
📐 平面法向量抓取 任意姿态下沿平面法线方向抓取 传统方案只能从固定方向接近
🧠 区域生长智能分割 利用法向量一致性自动分离接触物体 传统聚类对接触物体效果差
⚡ 轻量化端到端流程 采集→分割→拟合→抓取,无中间配准 4PCS+ICP 配准链路长、不鲁棒

8.2 方案对比总结

🆚 对比维度 📸 传统 2D 视觉 🔧 4PCS+ICP 配准方案 🏆 本方案(平面拟合)
摆放要求 必须整齐 任意 ✅ 任意
精度 高(2D平面) 低(点云精度差) ✅ 中等(补偿后可用)
鲁棒性 高 ❌ 对噪声极敏感 ✅ 取平均后稳定
计算量 低 高(配准迭代) ✅ 低(拟合解析解)
实现难度 低 高 ✅ 中等

九、总结与展望 🚀

9.1 核心贡献

  • 🎯 端到端无序抓取方案:从 RGB-D 采集到机器人执行,形成完整闭环
  • 📐 平面拟合 + 法向量求解:巧妙绕过点云配准的坑,用几何方法直接求解抓取姿态
  • 🔗 Qt 集成开发:统一界面管理相机、算法、通信,工程化程度高
  • 📊 精度量化分析:对系统各环节误差做了详细测量,为后续优化提供数据支撑

9.2 未来方向

🚀 方向 🎯 目标 💡 技术路径
📷 升级深度传感器 换用条纹结构光相机,将深度精度提升至 <0.5mm 条纹投影 + 相位解算
🧩 模板匹配抓取 支持复杂曲面零件(非平面工件) 预扫描工件库 + 模板匹配
🗺️ 抓取后路径规划 避障 + 最优路径 RRT / A* 算法
🤖 第三视角避障 利用 Astra Pro 做环境感知 实时深度图 + 障碍物检测
📱 开发板升级 在边缘端完整运行算法 Jetson Orin Nano 8GB

🌟 写在最后: 这支团队用朴实无华的硬件(Astra Pro + Zora P1 + 川崎机器人),走出了一条"用几何方法解决工程问题"的务实路线。他们没有堆砌花哨的深度学习模型,而是在理解数据特性的基础上,选择了最适合当前硬件条件和精度约束的方案——平面拟合 + 法向量抓取。这种"把手头的牌打好"的工程思维,比任何炫技都更有价值。如果你也在做类似的工业视觉项目,这份实战经验绝对值得参考!🏆


–

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注