第一个Embodied AI项目:机械臂抓取
从零开始构建你的第一个具身智能项目——用机械臂抓取物体,涵盖仿真搭建、视觉感知和运动规划。
机械臂 抓取 Isaac Sim 入门项目 Embodied AI
第一个Embodied AI项目:机械臂抓取
机械臂抓取是Embodied AI最经典的入门项目。它涵盖了感知、规划、控制三大核心模块,让你快速理解具身智能的完整流程。
项目目标
构建一个6轴机械臂系统,能够:
- 通过摄像头识别桌面物体
- 计算抓取姿态
- 规划无碰撞轨迹
- 执行抓取动作
在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基础。