第一个Embodied AI项目:机械臂抓取

从零开始构建你的第一个具身智能项目——用机械臂抓取物体,涵盖仿真搭建、视觉感知和运动规划。

机械臂 抓取 Isaac Sim 入门项目 Embodied AI
第一个Embodied AI项目:机械臂抓取

第一个Embodied AI项目:机械臂抓取

机械臂抓取是Embodied AI最经典的入门项目。它涵盖了感知、规划、控制三大核心模块,让你快速理解具身智能的完整流程。

项目目标

构建一个6轴机械臂系统,能够:

  1. 通过摄像头识别桌面物体
  2. 计算抓取姿态
  3. 规划无碰撞轨迹
  4. 执行抓取动作

在Isaac Sim中搭建场景

from isaacsim import SimulationApp

# 启动仿真
simulation_app = SimulationApp({"headless": False})

import numpy as np
from isaacsim.core import World
from isaacsim.core.utils.prims import add_cube

# 创建世界
world = World()
world.scene.add_default_ground_plane()

# 添加机械臂(使用预置的Franka模型)
from isaacsim.assets import FrankaRobot
franka = FrankaRobot(prim_path="/World/Franka", name="franka")
world.scene.add(franka)

# 添加目标物体
add_cube(
    prim_path="/World/TargetCube",
    size=0.05,
    color=np.array([1.0, 0.0, 0.0]),
    position=np.array([0.5, 0.0, 0.025])
)

# 重置世界
world.reset()

# 运行仿真
while simulation_app.is_running():
    world.step(render=True)

simulation_app.close()

视觉感知模块

import cv2
import numpy as np

class ObjectDetector:
    def __init__(self):
        # 使用预训练的YOLO模型
        self.model = cv2.dnn.readNet("yolov8.weights", "yolov8.cfg")
        self.classes = ["cube", "cylinder", "sphere"]

    def detect(self, image):
        blob = cv2.dnn.blobFromImage(image, 1/255.0, (416, 416))
        self.model.setInput(blob)
        outputs = self.model.forward(self.model.getUnconnectedOutLayersNames())

        # 解析检测结果
        boxes, confidences = self._parse_outputs(outputs)
        indices = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)

        return self._extract_objects(boxes, confidences, indices)

    def _parse_outputs(self, outputs):
        boxes, confidences = [], []
        for output in outputs:
            for detection in output:
                scores = detection[5:]
                class_id = np.argmax(scores)
                confidence = scores[class_id]
                if confidence > 0.5:
                    box = detection[0:4] * np.array([640, 640, 640, 640])
                    boxes.append(box)
                    confidences.append(float(confidence))
        return boxes, confidences

    def _extract_objects(self, boxes, confidences, indices):
        objects = []
        for i in indices:
            obj = {
                "class": self.classes[0],
                "confidence": confidences[i],
                "bbox": boxes[i]
            }
            objects.append(obj)
        return objects

运动规划

import numpy as np
from scipy.optimize import minimize

class MotionPlanner:
    def __init__(self, robot):
        self.robot = robot

    def plan_grasp(self, target_pose):
        """规划从当前位置到目标抓取姿态的轨迹"""
        # 1. 计算逆运动学
        joint_angles = self._inverse_kinematics(target_pose)

        # 2. 生成轨迹点
        trajectory = self._generate_trajectory(joint_angles)

        # 3. 碰撞检测
        if self._check_collision(trajectory):
            return self._find_alternative_path(trajectory)

        return trajectory

    def _inverse_kinematics(self, target_pose):
        """使用数值方法求解逆运动学"""
        def error(q):
            current_pose = self.robot.forward_kinematics(q)
            return np.linalg.norm(current_pose - target_pose)

        q0 = self.robot.current_joint_angles()
        result = minimize(error, q0, method='L-BFGS-B')
        return result.x

    def _generate_trajectory(self, target_joints, steps=100):
        """生成平滑的关节空间轨迹"""
        current = self.robot.current_joint_angles()
        trajectory = np.linspace(current, target_joints, steps)
        return trajectory

控制执行

class GraspController:
    def __init__(self, robot, planner):
        self.robot = robot
        self.planner = planner
        self.gripper_open = 0.04  # 4cm
        self.gripper_close = 0.0  # 闭合

    def execute_grasp(self, target_pose):
        """执行完整的抓取流程"""
        # 1. 张开夹爪
        self.robot.move_gripper(self.gripper_open)

        # 2. 移动到预抓取位置(目标上方10cm)
        pre_grasp = target_pose.copy()
        pre_grasp[2] += 0.1  # Z轴抬高
        trajectory = self.planner.plan_grasp(pre_grasp)
        self.robot.follow_trajectory(trajectory)

        # 3. 下降到抓取位置
        down_trajectory = self._vertical_descent(pre_grasp, target_pose)
        self.robot.follow_trajectory(down_trajectory)

        # 4. 闭合夹爪
        self.robot.move_gripper(self.gripper_close)

        # 5. 抬起
        lift_trajectory = self._vertical_descent(target_pose, pre_grasp)
        self.robot.follow_trajectory(lift_trajectory)

        return True

    def _vertical_descent(self, start, end, steps=50):
        """垂直下降/上升轨迹"""
        trajectory = np.linspace(start, end, steps)
        return trajectory

完整流程

def main():
    # 初始化
    detector = ObjectDetector()
    planner = MotionPlanner(franka)
    controller = GraspController(franka, planner)

    # 主循环
    while simulation_app.is_running():
        # 获取相机图像
        image = camera.get_image()

        # 检测物体
        objects = detector.detect(image)

        if objects:
            target = objects[0]
            target_pose = compute_grasp_pose(target)

            # 执行抓取
            success = controller.execute_grasp(target_pose)
            print(f"抓取{'成功' if success else '失败'}")

        world.step(render=True)

if __name__ == "__main__":
    main()

FAQ

没有机械臂硬件可以做这个项目吗?

完全可以!Isaac Sim提供了完整的仿真环境,包括Franka、UR5等主流机械臂模型。

抓取失败怎么办?

常见原因:相机标定不准、物体位姿估计偏差、运动规划碰撞。建议先在仿真中充分测试。

这个项目需要多久?

按本文步骤,有ROS2基础的话1-2天可以跑通。零基础建议先学习ROS2基础。