主推理流程:
1. 加载网络
2. 前向推理
3. 碰撞检测
4. NMS 去重 + 按置信度排序
5. 对抓取预测进行垂直角度筛选
1. 加载网络
# 创建GraspNet模型实例
net = GraspNet(input_feature_dim=0,
num_view=300,
num_angle=12,
num_depth=4,
cylinder_radius=0.05,
hmin=-0.02,
hmax_list=[0.01, 0.02, 0.03, 0.04],
is_training=False)
参数详解:
input_feature_dim=0
:点云输入的特征维度(0表示只有位置坐标)num_view=300
:视点采样数量(从不同角度预测抓取)num_angle=12
:抓取角度采样数量(30度一个间隔:360°/12)num_depth=4
:抓取深度采样数量(沿接近方向的采样点)cylinder_radius=0.05
:点云采样的圆柱半径(5cm)hmin=-0.02
:抓取高度范围下限(-2cm)hmax_list=[0.01, 0.02, 0.03, 0.04]
:抓取高度范围上限(多尺度预测)is_training=False
:设置为评估模式(非训练模式)
2. 前向推理
# 禁用梯度计算(节省内存,加快推理)
with torch.no_grad():
# 前向传播
end_points = net(end_points)
# 解码预测结果
grasp_preds = pred_decode(end_points)
前向传播:
net(end_points)
:执行模型的前向计算- 输入:
end_points
字典包含点云数据(point_clouds
) - 输出:更新后的
end_points
字典,包含:- 抓取得分(graspness scores)
- 抓取宽度预测
- 旋转角度预测
- 抓取高度预测
抓取表示方法
GraspNet 使用以下参数表示一个抓取姿态:
- 位置:抓取中心点的3D坐标 (x, y, z)
- 方向:3×3旋转矩阵(定义夹爪坐标系)
- 宽度:夹爪张开的宽度
- 高度:夹爪的抓取深度
- 得分:抓取质量的置信度(0-1)
网络架构关键组件
-
点云特征提取:
- 使用PointNet++或类似结构提取点云特征
- 学习每个点的局部几何特征
-
抓取性预测:
- 预测每个点作为抓取中心的概率
- 生成抓取候选点
-
抓取参数回归:
- 对于每个候选点,回归抓取参数:
- 旋转角度(绕不同轴的旋转)
- 夹爪宽度
- 抓取高度
- 对于每个候选点,回归抓取参数:
-
多尺度预测:
- 在多个高度范围预测抓取
- 增强对不同大小物体的适应性
3.碰撞检测的实现原理和流程
碰撞检测是机器人抓取系统中的关键步骤,用于确保抓取姿态不会与环境中的物体发生碰撞。在您的代码中,碰撞检测是通过 ModelFreeCollisionDetector
类实现的,以下是其工作原理的详细解释:
碰撞检测的基本思想是:
- 将环境表示为点云:场景中的所有物体被抽象为点云数据
- 创建抓取器模型:为每个候选抓取姿态生成一个简化的几何模型
- 检查几何重叠:检测抓取器模型是否与环境点云发生重叠
- 判断碰撞风险:根据重叠程度评估碰撞风险
在代码中的具体实现
COLLISION_THRESH = 0.01
if COLLISION_THRESH > 0:
voxel_size = 0.01 # 体素大小(10mm)
collision_thresh = 0.01 # 碰撞阈值
# 创建碰撞检测器
mfcdetector = ModelFreeCollisionDetector(np.asarray(cloud.points), voxel_size=voxel_size)
# 检测碰撞
collision_mask = mfcdetector.detect(gg, approach_dist=0.05, collision_thresh=collision_thresh)
# 过滤掉有碰撞的抓取姿态
gg = gg[~collision_mask]
步骤详解
-
体素化点云 (Voxelization):
- 将场景点云划分为大小为
voxel_size
(10mm)的体素网格 - 每个体素代表一个小的立方体空间单元
- 这种方法将连续空间离散化,便于快速检测
- 将场景点云划分为大小为
-
抓取姿态建模:
- 为每个候选抓取姿态生成一个简化的几何模型
- 通常是一个代表夹爪的矩形框或两个平行平面
- 模型包含抓取点及其周围的安全区域
-
接近路径模拟:
- 模拟夹爪接近物体时的路径(
approach_dist=0.05
表示5cm的接近距离) - 沿着接近方向检测路径上的碰撞风险
- 模拟夹爪接近物体时的路径(
-
碰撞检测算法:
- 检查抓取器模型占据的体素是否被场景点云占据
- 使用
collision_thresh
作为阈值判断碰撞程度 - 如果超过阈值(本例为1%),则认为存在碰撞风险
-
结果处理:
- 生成一个布尔掩码
collision_mask
,标记哪些抓取姿态有碰撞风险 - 过滤掉有碰撞风险的抓取姿态
gg = gg[~collision_mask]
- 生成一个布尔掩码
碰撞检测的关键参数
-
体素大小 (voxel_size):
- 决定检测精度和计算效率的权衡
- 较小的值(如5mm)更精确但计算量大
- 较大的值(如20mm)计算快但可能忽略细节
-
接近距离 (approach_dist):
- 模拟夹爪接近物体的安全距离
- 确保夹爪在接近过程中不会碰撞
- 通常设置为抓取点到夹爪基座的距离
-
碰撞阈值 (collision_thresh):
- 决定容忍多少碰撞
- 0表示零容忍,任何碰撞都会被拒绝
- 较高的值允许轻微碰撞(适用于复杂环境)
碰撞检测的优势和局限
优势:
- 无需预先建模:Model-Free 意味着不需要物体的CAD模型
- 计算高效:体素化使检测复杂度从O(n²)降到O(n)
- 实时性能:适合在线抓取规划
- 适应性强:可处理任意形状的物体
局限:
- 点云质量依赖:稀疏点云可能导致误检
- 体素分辨率限制:可能忽略细小结构
- 简化几何模型:抓取器模型可能不够精确
- 静态环境假设:假设场景在检测期间不变
实际应用中的改进方向
-
多分辨率体素:
- 在抓取区域使用更精细的体素
- 在远处使用较粗的体素
-
抓取器精细建模:
- 使用更接近真实夹爪的几何模型
- 包含夹爪内部结构
-
动态碰撞检测:
- 考虑夹爪运动轨迹中的碰撞
- 使用连续碰撞检测(CCD)算法
-
机器学习辅助:
- 使用神经网络预测碰撞风险
- 减少误报率
4.NMS 去重与置信度排序详解
NMS(非极大值抑制)去重
目的与原理
NMS的主要目的是消除重叠的冗余抓取预测,保留最具代表性的抓取姿态:
-
问题背景:
- 同一物体表面可能生成多个相似的抓取预测
- 这些预测在空间位置和姿态上高度重叠
- 直接使用会导致重复执行相似的抓取动作
-
核心思想:
- 对每个抓取预测定义一个"影响力范围"
- 当两个预测过于接近时,只保留得分最高的那个
- 移除其他得分较低但位置相似的预测
关键参数与选择
- 距离阈值 (threshold=0.03):
- 设置为3厘米是经验值
- 基于夹爪物理尺寸的典型值(夹爪宽度通常为8-10cm)
- 小于夹爪宽度的1/3,确保不会抑制有意义的独立抓取
- 可根据场景调整:对于小物体可减小到0.01-0.02m,大物体可增大到0.05m
5.垂直角度筛选的作用和原理
vertical = np.array([0, 0, 1]) # 定义垂直方向向量(Z轴正方向)
angle_threshold = np.deg2rad(30) # 设置30度的阈值
filtered = []
for grasp in gg:
approach_dir = grasp.rotation_matrix[:, 0] # 获取夹爪接近方向
cos_angle = np.dot(approach_dir, vertical) # 计算夹爪方向与垂直方向夹角的余弦值
angle = np.arccos(np.clip(cos_angle, -1.0, 1.0)) # 计算实际角度
if angle < angle_threshold: # 如果夹角小于30度
filtered.append(grasp) # 保留该抓取姿态
垂直角度筛选是抓取姿态选择的一个重要步骤,它的主要目的是确保机械臂能够以接近垂直向下的方向进行抓取。这个筛选过程基于几个关键原因:
1. 机械臂运动学约束
- 机械臂在垂直向下姿态时通常处于最稳定的工作状态
- 避免机械臂关节处于奇异点(singularity points)位置
- 减少关节过度伸展或超出工作范围的风险
2. 抓取稳定性
- 垂直抓取可以充分利用重力作用
- 夹爪闭合时物体不易滑落
- 适用于大多数桌面物体的抓取场景
3. 避免碰撞
- 垂直姿态减少了夹爪与桌面或其他物体的碰撞风险
- 简化运动轨迹规划
- 确保抓取路径无障碍
-
夹爪接近方向 (approach_dir):
- 在抓取姿态中,通常定义旋转矩阵的第一列([:, 0])为夹爪的接近方向
- 这表示夹爪朝向物体的方向
-
垂直方向 (vertical):
- 这里定义为 [0, 0, 1],表示世界坐标系的Z轴正方向(向上)
- 在实际抓取中,我们通常希望夹爪垂直向下,即接近方向为 [0, 0, -1]
-
角度计算:
- 使用点积公式计算两个方向向量之间的夹角
np.arccos()
函数将余弦值转换为角度(弧度)np.clip()
确保余弦值在有效范围内 [-1, 1]