
📋 项目概述
> "让机器像人一样精准识别、定位并采摘草莓" ——这不仅仅是一个竞赛项目,更是计算机视觉与机器人技术在智慧农业领域的一次生动实践。
本项目核心目标是构建一个基于深度相机与机械臂的自动化草莓采摘系统,实现从"看见"到"抓取"的完整闭环。
核心硬件选型:
| 组件 | 型号 |
|---|---|
| 深度相机 | Orbbec Astra / Gemini 系列 |
| 机械臂 | Arm7Bot 六轴机械臂 |
| 计算平台 | PC (Windows 10) / Jetson Nano |
🔗 源码与参考
– GitHub 仓库: https://github.com/3DCVdeveloper/RobotV_Strawberry-picking
– 竞赛名称: 第二届3D视觉创新应用竞赛
– 参赛团队: 邱泽宇 / 南方科技大学
🏗️ 系统架构:三大模块协同作战
整个系统将复杂的采摘任务拆解为三个核心模块,各司其职又紧密配合:

模块间的"握手协议"
识别模块和定位模块在完成一次检测后主动阻塞,等待抓取模块完成动作后发送唤醒信号,然后继续下一轮识别。这种生产者-消费者模式确保了系统运行的节奏感和稳定性。
🔬 核心技术深度解读
1️⃣ 识别模块:基于HSV色彩空间的草莓检测

这是整个项目的视觉之眼。不同于简单的颜色阈值分割,项目采用了一套多步骤的图像处理流水线:
🔴 红色草莓识别流程

关键代码逻辑解读:
# HSV空间中红色的"两段式"分布特性
# 红色在HSV色轮上跨越0°和180°,因此需要两个阈值范围
mask1 = cv2.inRange(hsv, [0, 100, 80], [10, 256, 256]) # 低段红色
mask2 = cv2.inRange(hsv, [170, 100, 80], [180, 256, 256]) # 高段红色
mask = mask1 + mask2 # 合并
> 💡 为什么要分两段? 因为在HSV色彩空间中,红色的色相H值分布在0°附近,跨越了0和180两个边界。不分区处理会导致红色目标被"切断"。
形态学操作的作用:
| 操作 | 目的 | 效果 |
|---|---|---|
| 高斯模糊 (7×7) | 抑制图像噪声 | 减少误检 |
| 闭运算 (MORPH_CLOSE) | 填充前景区域内部空洞 | 让草莓轮廓更完整 |
| 开运算 (MORPH_OPEN) | 去除孤立的噪声点 | 过滤背景干扰 |
椭圆拟合的意义:
cv::RotatedRect ellipse = cv::fitEllipse(biggest_contour[0]);
// 椭圆中心 = 草莓的2D图像坐标
X = ellipse.center.x;
Y = ellipse.center.y;
椭圆拟合不仅给出了草莓的中心位置,还提供了朝向和尺寸信息,为后续抓取姿态规划提供了重要参考。
🟢 绿色草莓识别(扩展功能)
项目还预留了绿色草莓的识别分支,使用HSV范围 [35, 43, 46] ~ [77, 256, 256] 来捕获未成熟的绿色草莓,展示了系统的可扩展性。
2️⃣ 定位模块:从2D像素到3D世界坐标的魔法
这是项目中最具3D视觉技术含量的部分。
深度相机的工作原理

核心API调用:
// AstraSDK 提供的坐标映射接口
coordinateMapper.convert_depth_to_world(
float(X), float(Y), float(z),
mouseWorldX_, // 输出:世界坐标X
mouseWorldY_, // 输出:世界坐标Y
mouseWorldZ_ // 输出:世界坐标Z
);
> 🔑 深度值的意义: 深度相机每个像素对应一个Z值(单位:毫米),表示该点到相机的直线距离。convert_depth_to_world() 内部完成了像素坐标系 → 相机坐标系 → 世界坐标系的变换,涉及相机内参矩阵和畸变校正。
坐标对齐的必要性
由于彩色相机和深度传感器存在物理位置差异(视差),两者的图像帧需要严格对齐才能正确配对。AstraSDK 通过 enable_registration() 接口完成这一步:
depthStream.enable_registration(true); // 开启深度-彩色图像对齐
3️⃣ 抓取模块:逆运动学控制机械臂

坐标变换链路
从相机到机械臂末端,坐标经历了两次关键变换:
世界坐标 (mouseWorldX, mouseWorldY, mouseWorldZ)
│
│ 平移补偿(相机与机械臂基座的相对位置标定)
▼
机械臂基坐标系 (X', Y', Z')
│
│ 逆运动学求解 (IK6)
▼
六关节角度 (θ1, θ2, θ3, θ4, θ5, θ6)
Python端控制代码:
# 坐标变换(含手眼标定偏移量)
X = int(z) - 300 + 35 - 10 - 50 + 10 # 多次标定后的经验补偿
Y = -int(x) + 165 - 45 + 30 - 20 - 20 + 10
Z = int(y) + 120 + 10
# 逆运动学求解 + 末端姿态控制
arm.setIK6([X, Y, Z], [0, 0, -1]) # 移动到目标上方
time.sleep(2)
arm.setIK6([X, Y, Z], [1, 1, 0]) # 调整末端姿态
time.sleep(3)
arm.setAngle(6, 18) # 闭合夹爪(抓取)
time.sleep(1)
arm.setIK6([-170, 1, 100], [0,0,-1])# 移动到放置位置
arm.setAngle(6, 90) # 张开夹爪(释放)
> ⚠️ 手眼标定的重要性: 代码中大量的 +35、-45 等常数是相机-机械臂手眼标定的结果。这一步是将视觉坐标映射到机械臂坐标系的关键,直接决定了抓取精度。
抓取动作序列
移动到草莓上方 → 下降接近目标 → 闭合夹爪抓取 → 抬起移动至收集盒 → 释放草莓 → 返回待机位
🧪 测试与性能
识别准确率测试
| 测试项 | 结果 |
|---|---|
| 测试样本数 | 50 张图片 |
| 识别成功 | 43 张 |
| 识别失败 | 7 张 |
| 准确率 | 86% |
失败原因分析:
- 🍃 叶片遮挡草莓果实
- 🔴 多个果实重叠在一起
- 🎨 背景颜色干扰(红色系物体)
深度定位精度测试
通过在相机前方不同距离放置物体,验证 AstraSDK 深度计算的可靠性:
| 距离(mm) | 测量误差(mm) |
|---|---|
| 300 | ±15 |
| 500 | ±20 |
| 800 | ±30 |
数据拟合显示误差在可接受范围内,且随距离增大线性增长,符合深度相机的精度特性。
🚧 开发中的"坑"与解决方案
| 问题 | 解决方案 |
|---|---|
| 彩色流与深度流同步 | 使用 AstraSDK 的 enable_registration() 对齐两路数据流 |
| 模块间同步阻塞 | 通过文件信号量(data.txt)和超时等待实现模块间握手 |
| 机械臂末端晃动 | 先移动到预抓取位再微调姿态,分两步下降 |
| 开发板编译卡死 | Jetson Nano 性能有限,将 make -j8 降为 make -j1 |
| 字体文件缺失 | 将 .otf 字体文件拷贝到可执行文件同目录 |
🚀 未来改进方向
1. 引入深度学习(YOLO/FCN)替代传统CV方法 ➡️ 解决遮挡、重叠场景下的识别难题
2. 3D点云重建 + 最优抓取点分析 ➡️ 利用深度信息构建草莓三维模型 ➡️ 计算最佳抓取角度和力度
3. 机械臂轨迹优化 ➡️ 避免触碰茎秆导致草莓移位 ➡️ 引入力反馈控制实现柔性抓取
> "智慧农业的未来,始于每一次精准的识别与抓取。"