1. Anygrasp介绍
AnyGrasp是上海交大 + 非夕 Flexiv 联合实验室(GraspNet 团队)推出的通用 7DoF 视觉抓取算法 & 工程 SDK(2022 论文),面向无序未知物体静态 + 动态抓取,是目前工业落地最主流的 6/7 自由度抓取开源方案,常和 cuRobo 运动规划搭配使用(视觉出抓取位姿→cuRobo 做机械臂避障轨迹)。
无需提前物体建模、物体 CAD、离线标定训练,输入单目 RGB-D 点云,直接输出夹爪可用7 自由度抓取位姿(6D 位姿 + 夹爪开合宽度)
与其他主流方法比较:
使用流程建议(典型 pipeline)
获取 RGB-D 图像 → 生成点云
运行 AnyGrasp → 得到多个候选抓取7DoF 位姿(在相机系下)
手眼标定 → 将抓取位姿转到机器人基坐标系
对抓取位姿进行后处理 → 选择最优抓取位姿
位姿送入 cuRobo 运动规划 → 规划无碰撞路径
执行抓取动作(接近 → 闭合夹爪 → 提起)
使用 [AnyGrasp],它输入一帧 RGBD 数据以及相机内参,输出一组相机坐标系下带分数的候选抓取位姿。AnyGrasp 的 SDK 需要申请 license。
最直接的用法是离线跑一帧数据,核心就是从深度图反投影出点云,喂给模型:
from gsnet import AnyGrasp from graspnetAPI import GraspGroup anygrasp = AnyGrasp(cfgs) anygrasp.load_net() # 从深度图反投影出点云 xmap, ymap = np.meshgrid(np.arange(W), np.arange(H)) points_z = depths / scale points_x = (xmap - cx) / fx * points_z points_y = (ymap - cy) / fy * points_z points = np.stack([points_x, points_y, points_z], axis=-1) mask = (points_z > 0) & (points_z < 1) points = points[mask].astype(np.float32) colors = colors[mask].astype(np.float32) # 检测抓取,返回一个 GraspGroup gg, cloud = anygrasp.get_grasp( points, colors, apply_object_mask=True, collision_detection=True ) gg = gg.nms().sort_by_score() # 非极大值抑制 + 按分数排序 best_grasp = gg[0] # 分数最高的抓取用服务的方式调用
在实际的数据采集流水线里,AnyGrasp 模型加载一次要占不少显存,而且我们往往需要并行跑很多个 Isaac Sim 实例,每个实例都自己加载一份模型既慢又浪费。所以更实用的做法是把AnyGrasp 包成一个 HTTP 服务,模型常驻显存,Isaac 这边作为客户端按需请求。
from flask import Flask, request, jsonify app = Flask(__name__) anygrasp = AnyGrasp(cfgs) anygrasp.load_net() # 模型常驻 @app.route("/process", methods=["POST"]) def process_data(): data = request.get_json() colors = np.array(data["colors"], dtype=np.uint8) depths = np.array(data["depths"], dtype=np.uint16) # ... 反投影 + get_grasp ... gg = gg.nms().sort_by_score() grasp_list = [{ "translation": g.translation.tolist(), "rotation_matrix": g.rotation_matrix.tolist(), "depth": g.depth, "score": g.score, } for g in gg] return jsonify({"grasp_groups": grasp_list}), 200 app.run(host="0.0.0.0", port=5001)从相机系到世界系
AnyGrasp 给出的抓取位姿是在相机坐标系下的,而我们前面规划用的是世界坐标系,所以又得做一次坐标变换。这里需要特别小心的是,AnyGrasp / GraspNet 的相机坐标系约定和 Isaac Sim 的相机坐标系约定是不一样的,中间需要插一个修正矩阵
def get_world_grasp_from_camera_coords( camera_position, camera_quaternion, point_3d, matrix_grasp ): rotation_cam_to_world = R.from_quat(camera_quaternion[[1, 2, 3, 0]]) # 这两个矩阵用来对齐 GraspNet 和 Isaac 的相机坐标系约定 transform_custom_pose = np.array([[0, 0, 1], [0, -1, 0], [1, 0, 0]]) correction_matrix = np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]]) point_in_world = ( rotation_cam_to_world.as_matrix() @ correction_matrix @ transform_custom_pose @ point_3d + camera_position ) rotation_world = ( rotation_cam_to_world * R.from_matrix(correction_matrix @ transform_custom_pose) * R.from_matrix(matrix_grasp) * R.from_matrix(np.linalg.inv(transform_custom_pose)) ).as_quat()[[3, 0, 1, 2]] return point_in_world, rotation_world