2. 仿真环境搭建:PyBullet / Isaac Gym 配置与基础 API 调用

做四足机器人强化学习,第一步不是写策略网络,而是搭一个靠谱的仿真环境。我见过不少同学在真实机器人上跑崩了,回头一查,仿真里就没把地面摩擦系数设对。说白了,仿真环境就是你的“数字试验田”,地没耕好,种子再好也白搭。

这一章,我们重点搞定两个主流仿真器——PyBullet 和 Isaac Gym。我会从安装配置讲到基础 API 调用,最后带你跑通一个四足机器人站立仿真的最小示例。

2.1 为什么需要仿真环境?

你想想看,在真实机器人上调试 RL 算法,一次 crash 可能就烧坏电机、摔断腿。仿真环境给你三个核心价值:

  • 安全试错:策略再烂,大不了仿真里翻个跟头,重启就行。
  • 加速训练:Isaac Gym 可以并行跑几千个环境,一天顶真实世界跑几年。
  • 可控变量:想测雪地行走?改个摩擦系数就行,不用真等到下雪。

核心原则:仿真环境越接近真实,策略迁移成功率越高。但也要平衡仿真速度——太精细的物理引擎会拖慢训练。

2.2 PyBullet vs Isaac Gym:怎么选?

我个人两个都用过,给你一个直观对比:

维度 PyBullet Isaac Gym
安装难度 pip install 一步到位 需要注册 NVIDIA 账号,稍复杂
并行能力 单进程,最多几个环境 GPU 并行,数千环境同时跑
物理精度 中等,适合原型验证 高,支持 GPU 物理计算
渲染质量 OpenGL 基础渲染 支持 RTX 光线追踪
社区生态 开源,教程多 官方文档为主,社区较小
推荐场景 单机调试、算法原型 大规模并行训练

我的建议:刚开始学,先用 PyBullet 跑通流程。等你要做大规模 RL 训练了,再切到 Isaac Gym。别一上来就搞复杂的,容易劝退。

2.3 PyBullet 环境搭建

2.3.1 安装与验证

安装 PyBullet 非常简单,一行命令搞定:

pip install pybullet

验证是否安装成功:

import pybullet as p
import pybullet_data

# 连接物理引擎(GUI 模式)
p.connect(p.GUI)
p.setAdditionalSearchPath(pybullet_data.getDataPath())

# 加载地面和机器人
plane_id = p.loadURDF("plane.urdf")
robot_id = p.loadURDF("r2d2.urdf", [0, 0, 0.5])

# 运行仿真
while True:
    p.stepSimulation()
    time.sleep(1/240.)

运行后你会看到一个窗口,R2D2 机器人站在地面上。嗯,这里要注意:p.stepSimulation() 每调用一次,物理引擎前进一个时间步(默认 1/240 秒)。

2.3.2 四足机器人模型加载

PyBullet 官方没有现成的四足机器人 URDF,我一般用 Unitree Go1 或 A1 的开源模型。你可以从 GitHub 下载:

# 假设你已经下载了 go1.urdf 到当前目录
robot_id = p.loadURDF("go1.urdf", 
                      basePosition=[0, 0, 0.4],
                      useFixedBase=False)

加载后,你可以通过 p.getNumJoints() 查看关节数量,用 p.getJointInfo() 获取每个关节的详细信息。

避坑指南:我曾经加载一个四足机器人 URDF,结果它直接陷到地面以下。原因是 basePosition 的 z 值设得太低。记住:四足机器人站立时,机身高度大约 0.3-0.5 米,具体看腿长。

2.3.3 基础 API 调用

PyBullet 的核心 API 就几个,我列出来你记一下:

  • 获取状态:p.getBasePositionAndOrientation() 获取机身位姿;p.getJointStates() 获取关节角度和速度。
  • 控制关节:p.setJointMotorControl2() 支持位置控制、速度控制、力矩控制。
  • 设置参数:p.changeDynamics() 修改摩擦系数、质量等物理属性。
  • 重置仿真:p.resetBasePositionAndOrientation() 和 p.resetJointState() 用于复位。

一个典型的位置控制示例:

# 控制第 0 号关节转到 0.5 弧度
p.setJointMotorControl2(bodyIndex=robot_id,
                        jointIndex=0,
                        controlMode=p.POSITION_CONTROL,
                        targetPosition=0.5,
                        force=50)

2.4 Isaac Gym 环境搭建

2.4.1 安装与配置

Isaac Gym 的安装稍微麻烦一点。你需要:

  1. 注册 NVIDIA 开发者账号(免费)。
  2. 下载 Isaac Gym Preview Release(目前最新是 Preview 4)。
  3. 解压后运行 python setup.py install。

验证安装:

from isaacgym import gymapi
gym = gymapi.acquire_gym()
print("Isaac Gym version:", gym.get_version())

小技巧:Isaac Gym 依赖 CUDA 和 GPU。如果你在服务器上跑,记得用 nvidia-smi 确认驱动版本。我遇到过 CUDA 版本不匹配导致无法加载物理引擎的情况,折腾了半天。

2.4.2 创建仿真场景

Isaac Gym 的 API 设计更面向大规模并行。创建一个基本场景的流程如下:

from isaacgym import gymapi

# 初始化 gym
gym = gymapi.acquire_gym()

# 创建仿真参数
sim_params = gymapi.SimParams()
sim_params.dt = 1/60.0
sim_params.substeps = 2
sim_params.up_axis = gymapi.UP_AXIS_Z

# 创建仿真实例
sim = gym.create_sim(0, 0, gymapi.SIM_PHYSX, sim_params)

# 创建地面
plane_params = gymapi.PlaneParams()
gym.add_ground(sim, plane_params)

# 创建环境
env = gym.create_env(sim, 
                     gymapi.Vec3(-1, -1, 0),  # 环境下界
                     gymapi.Vec3(1, 1, 2),    # 环境上界
                     1)                       # 每行环境数

2.4.3 加载四足机器人

Isaac Gym 支持加载 URDF 和 MJCF 格式。以 Unitree Go1 为例:

# 加载机器人资产
asset_root = "path/to/go1_urdf"
asset_file = "go1.urdf"

asset_options = gymapi.AssetOptions()
asset_options.fix_base_link = False
asset_options.flip_visual_attachments = True

robot_asset = gym.load_asset(sim, asset_root, asset_file, asset_options)

# 在环境中创建机器人实例
pose = gymapi.Transform()
pose.p = gymapi.Vec3(0, 0, 0.4)
pose.r = gymapi.Quat(0, 0, 0, 1)

robot_handle = gym.create_actor(env, robot_asset, pose, "go1", 0, 1)

2.4.4 并行环境与基础控制

Isaac Gym 的杀手锏是并行。你可以创建多个环境,每个环境里放一个机器人:

num_envs = 1024  # 同时跑 1024 个环境

for i in range(num_envs):
    env = gym.create_env(sim, lower, upper, num_per_row)
    gym.create_actor(env, robot_asset, pose, f"go1_{i}", i, 1)

控制所有机器人关节:

# 获取关节句柄
dof_handle = gym.get_actor_dof_handle(env, robot_handle)
dof_states = gym.get_actor_dof_states(env, robot_handle, gymapi.STATE_ALL)

# 设置目标位置(所有环境同时生效)
targets = np.zeros((num_envs, num_dofs))
targets[:, 0] = 0.5  # 第一个关节转到 0.5 弧度
gym.set_dof_position_target_tensor(sim, gymtorch.from_tensor(targets))

# 步进仿真
gym.simulate(sim)
gym.fetch_results(sim, True)

2.5 知识体系总览

下面这张图帮你理清本章的核心脉络:

仿真环境搭建知识体系 仿真环境搭建知识体系 搭建四足机器人仿真环境 PyBullet Isaac Gym 安装配置 URDF 加载 GPU 并行 Tensor API 状态获取 · 关节控制 · 重置复位 PyBullet 适合原型验证,Isaac Gym 适合大规模并行训练 两者 API 风格不同,但核心概念相通

2.6 最小示例:让四足机器人站起来

最后,我们用一个完整的 PyBullet 示例收尾。这个例子会加载一个四足机器人,设置初始关节角度让它保持站立姿势:

import pybullet as p
import pybullet_data
import time

# 连接 GUI
p.connect(p.GUI)
p.setAdditionalSearchPath(pybullet_data.getDataPath())
p.setGravity(0, 0, -9.81)

# 加载地面
plane = p.loadURDF("plane.urdf")

# 加载四足机器人(假设你有 go1.urdf)
robot = p.loadURDF("go1.urdf", [0, 0, 0.4])

# 获取关节数量
num_joints = p.getNumJoints(robot)
print(f"关节数量: {num_joints}")

# 设置站立姿势(髋关节弯曲 0.3 rad,膝关节弯曲 -0.6 rad)
stand_pose = {
    0: 0.3,   # 左前髋
    1: -0.6,  # 左前膝
    2: -0.3,  # 右前髋
    3: -0.6,  # 右前膝
    4: 0.3,   # 左后髋
    5: -0.6,  # 左后膝
    6: -0.3,  # 右后髋
    7: -0.6   # 右后膝
}

# 应用位置控制
for joint_idx, target_pos in stand_pose.items():
    p.setJointMotorControl2(bodyIndex=robot,
                            jointIndex=joint_idx,
                            controlMode=p.POSITION_CONTROL,
                            targetPosition=target_pos,
                            force=100)

# 运行仿真
for _ in range(500):
    p.stepSimulation()
    time.sleep(1/240.)

print("机器人已站立!")
p.disconnect()

试试看:运行后,你可以用鼠标拖动机器人,感受物理引擎的反馈。如果想看关节角度,用 p.getJointStates() 打印出来。

嗯,到这里,你已经掌握了两个主流仿真环境的基础搭建和 API 调用。记住:环境是 RL 训练的基石,花时间把这一步做扎实,后面会省很多麻烦。我在项目里吃过亏——仿真里跑得好好的,换到真实机器人就抖成筛子,最后发现是仿真里忘了加关节阻尼。所以,别嫌我啰嗦,多检查物理参数。