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 的安装稍微麻烦一点。你需要:
- 注册 NVIDIA 开发者账号(免费)。
- 下载 Isaac Gym Preview Release(目前最新是 Preview 4)。
- 解压后运行
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 知识体系总览
下面这张图帮你理清本章的核心脉络:
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 训练的基石,花时间把这一步做扎实,后面会省很多麻烦。我在项目里吃过亏——仿真里跑得好好的,换到真实机器人就抖成筛子,最后发现是仿真里忘了加关节阻尼。所以,别嫌我啰嗦,多检查物理参数。