Balance_car_PPO:基于 Isaac Lab 与 RSL-RL 的平衡车强化学习项目

可用于训练双轮平衡车原地平衡策略,并导出轻量 Actor 供 STM32 部署验证。项目基于 Isaac Lab 与 RSL-RL 实现 PPO,使用 IMU 和轮编码器观测,输出左右轮力矩,支持训练、播放与导出。【此简介由AI生成】

Branch1Tags0
FilesLast commitLast update
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago

Balance Car Isaac Lab

这是一个基于 Isaac Lab 和 RSL-RL 的双轮平衡车强化学习项目。当前任务只 考虑平地上的原地平衡,控制器根据 IMU 和轮子编码器信息输出左右轮控制量, 目标是保持车体直立、位置接近复位点,并抑制不必要的轮速和车体旋转。

当前范围

项目 当前配置
仿真任务 Isaac-Balance-Car-Flat-v0
播放任务 Isaac-Balance-Car-Flat-Play-v0
观测 10 维:IMU 重力方向 3、IMU 角速度 3、左右轮角速度 2、上一时刻动作 2
动作 2 维左右轮归一化力矩
策略频率 50 Hz(仿真步长 5 ms,decimation=4)
PPO Actor 10-32-32-2,ReLU
PPO Critic 10-128-128-1,仅训练使用
地面 平面、静态/动态摩擦系数 1.0、恢复系数 0

当前没有速度命令,默认目标朝向为 yaw=0。因此策略会优先学习原地平衡, 而不是主动前进或转弯。

目录结构

Balance_car/
├── assets/
│   ├── meshes/                 # 本地/外部提供的 STL 网格
│   ├── urdf/                   # 本地/外部提供的原始 URDF 和导出数据
│   └── usd/                    # URDF 转换生成的 Isaac Sim USD(本地缓存)
├── scripts/
│   ├── list_envs.py            # 列出已注册任务
│   ├── zero_agent.py           # 零动作仿真检查
│   ├── convert_urdf.py         # URDF/STL 转 USD
│   └── rsl_rl/                 # PPO 训练、播放和命令行参数
├── source/balance_car/         # Python 包、环境、观测和奖励
├── logs/                       # 训练输出,已加入 .gitignore
├── pyproject.toml              # Python 构建后端配置
└── setup.py                    # 当前项目的可编辑安装入口

环境要求

  • Ubuntu 22.04(当前开发环境)
  • Isaac Lab 及其 Isaac Sim 依赖
  • Isaac Lab 使用的 Conda 环境,例如 isaaclab
  • Python >= 3.10
  • RSL-RL >= 3.0.1
  • 训练需要支持 CUDA 的 NVIDIA GPU;播放和小规模检查也可使用较小显存

下面的命令假设 Isaac Lab 和本项目位于同一台机器。先按实际路径设置变量:

source /path/to/miniconda3/etc/profile.d/conda.sh
conda activate isaaclab

export ISAACLAB_ROOT=/path/to/IsaacLab
export BALANCE_CAR_ROOT=/path/to/Balance_car

准备仿真资源

当前 .gitignore 将整个 assets/ 作为外部资源目录处理。这样模型、网格和 URDF 不会因为后续迭代把仓库历史变大。百度网盘资产包只需要提供 URDF 和 其引用的 STL;运行前先将它们复制到 assets/:

网盘链接: https://pan.baidu.com/s/1UlWjlSKxjfZAj7u3jTaRdA?pwd=gw87

assets/urdf/car.SLDASM3.urdf
assets/meshes/base_link.STL
assets/meshes/left_Link.STL
assets/meshes/right_Link.STL

转换脚本会将生成的 USD 和 configuration/ 子层写入 assets/usd/。地面由 Isaac Lab 的 GroundPlaneCfg 创建;其默认配置使用 ISAAC_NUCLEUS_DIR/Environments/Grid/default_environment.usd。 检查资源:

cd "$BALANCE_CAR_ROOT"
test -f assets/urdf/car.SLDASM3.urdf
test -f assets/meshes/base_link.STL
test -f assets/meshes/left_Link.STL
test -f assets/meshes/right_Link.STL

从 URDF/STL 生成 USD

URDF 中的 <mesh filename="..."> 路径是相对于 URDF 文件解析的。当前项目的 目录关系必须保持为:

assets/urdf/car.SLDASM3.urdf
assets/meshes/base_link.STL
assets/meshes/left_Link.STL
assets/meshes/right_Link.STL

不要把 STL 单独导入后再手动拼装;转换器会根据 URDF 自动读取网格、惯量、关节 和碰撞描述。当前仓库提供了可重复执行的转换脚本:

cd "$BALANCE_CAR_ROOT"
TERM=xterm "$ISAACLAB_ROOT/isaaclab.sh" -p scripts/convert_urdf.py \
    --urdf assets/urdf/car.SLDASM3.urdf \
    --output assets/usd \
    --usd-name balance_car.usd \
    --force \
    --headless

脚本使用 Isaac Lab 的 UrdfConverter,会在输出目录中生成:

assets/usd/balance_car.usd
assets/usd/configuration/*.usd
assets/usd/config.yaml

--force 会覆盖同名 USD;不指定时,转换器会根据 URDF 和配置缓存判断是否 需要重新生成。修改 STL 后建议显式使用 --force,因为仅修改网格文件不一定 会触发旧版本缓存失效。

Isaac Sim 图形界面导入

也可以在 Isaac Sim 中通过 URDF 导入器完成转换:

  1. 打开 Isaac Sim 的 URDF Importer,选择 assets/urdf/car.SLDASM3.urdf。
  2. 确认距离单位为米(distance scale 为 1.0),保留关节和惯量信息。
  3. 关闭不需要的自碰撞;轮子驱动由 Isaac Lab 的 actuator 配置提供,不要在 导入器中额外设置位置/速度驱动。
  4. 导入后将生成的顶层 USD 和其 configuration/ 子层一起保存到 assets/usd/,顶层文件名保持为 balance_car.usd。
  5. 在 Isaac Sim 中重新打开 balance_car.usd,检查轮子轴向、质量、碰撞体和 关节名称 left_wheel、right_wheel,再运行零动作检查。

图形界面和脚本转换的关键是保留完整的 USD 子层目录;只复制顶层 balance_car.usd 会导致引用丢失,任务无法启动。

安装项目

cd "$BALANCE_CAR_ROOT"
python -m pip install -e . --no-deps

--no-deps 表示不重新安装 Isaac Lab 和 Isaac Sim 的依赖,它们由当前 Conda 环境提供。当前项目仍由 setup.py 提供包名、版本和 source/ 包发现 配置;如果计划删除它,需要先把这些字段迁移到 pyproject.toml。

检查任务注册

cd "$BALANCE_CAR_ROOT"
TERM=xterm "$ISAACLAB_ROOT/isaaclab.sh" -p scripts/list_envs.py \
    --keyword Balance-Car

正常情况下应看到:

Isaac-Balance-Car-Flat-v0
Isaac-Balance-Car-Flat-Play-v0

零动作仿真检查

该命令只用于确认模型、传感器、奖励和终止条件能够正常初始化。零动作不应 被当作平衡控制器:在有倾角时车辆最终会倒下。

cd "$BALANCE_CAR_ROOT"
"$ISAACLAB_ROOT/isaaclab.sh" -p scripts/zero_agent.py \
    --task Isaac-Balance-Car-Flat-Play-v0 \
    --num_envs 1 \
    --headless

PPO 训练

建议从项目目录启动,这样训练日志会写入 Balance_car/logs/:

cd "$BALANCE_CAR_ROOT"
"$ISAACLAB_ROOT/isaaclab.sh" -p scripts/rsl_rl/train.py \
    --task Isaac-Balance-Car-Flat-v0 \
    --num_envs 2048 \
    --max_iterations 1000 \
    --run_name f411_32x32 \
    --headless

显存不足时将 --num_envs 降到 256 或 512。快速检查训练脚本时可以使用:

"$ISAACLAB_ROOT/isaaclab.sh" -p scripts/rsl_rl/train.py \
    --task Isaac-Balance-Car-Flat-v0 \
    --num_envs 64 --max_iterations 5 --headless

训练输出通常位于:

logs/rsl_rl/balance_car_flat/<run_name>/

恢复训练示例:

"$ISAACLAB_ROOT/isaaclab.sh" -p scripts/rsl_rl/train.py \
    --task Isaac-Balance-Car-Flat-v0 \
    --resume \
    --load_run 2026-09-02_11-13-51 \
    --checkpoint model_999.pt \
    --headless

恢复训练时 Actor 结构必须与 checkpoint 一致。当前 32-32/ReLU 网络不能 加载此前的 128-128/ELU checkpoint。

播放和导出策略

播放脚本会加载 checkpoint,并在同一运行目录下自动导出:

exported/policy.pt
exported/policy.onnx

播放命令:

cd "$BALANCE_CAR_ROOT"
"$ISAACLAB_ROOT/isaaclab.sh" -p scripts/rsl_rl/play.py \
    --task Isaac-Balance-Car-Flat-Play-v0 \
    --checkpoint logs/rsl_rl/balance_car_flat/<run_name>/model_999.pt \
    --num_envs 1

需要无界面运行时添加 --headless;需要尽可能按真实速度运行时可添加 --real-time。policy.pt 和 policy.onnx 只包含 Actor,不包含 PPO Critic。

观测和动作接口

STM32 上的推理输入必须保持以下顺序和缩放:

[gravity_x, gravity_y, gravity_z,
 0.2 * gyro_x, 0.2 * gyro_y, 0.2 * gyro_z,
 0.1 * left_wheel_rad_s, 0.1 * right_wheel_rad_s,
 last_left_action, last_right_action]

其中重力方向是 IMU 坐标系中的投影重力方向,不是直接输入角度;角速度使用 机体坐标系、单位为 rad/s;轮速使用 rad/s。last_action 是上一时刻的归一化 网络动作。

Actor 输出应在固件中限制到 [-1, 1],再转换为实际电机控制量。当前仿真动作 缩放为 0.30 N*m,这是临时力矩上限;TB6612 的 PWM 与实际轮端力矩之间需要 根据电机、减速比、电池电压和实测电流重新标定,不能直接把 PWM 数值当作力矩。

STM32F411 部署规模

当前 Actor 为 10-32-32-2:

  • 1,474 个参数
  • FP32 权重约 5.9 KB
  • 每次推理约 1,408 次乘加
  • ReLU 可直接实现为 max(0, x)

F411 上只部署 Actor;Critic、PPO 优化器和训练日志不需要移植。第一版建议 使用 FP32 验证闭环,再根据实测误差考虑定点或 INT8 量化。 STM32 固件不需要 URDF、STL 或 USD;这些文件只用于仿真、训练和模型检查。

当前限制和后续工作

  • 当前只训练平地原地平衡,不包含速度命令。
  • 默认目标朝向为 0;转弯时应改为动态 yaw 或 yaw-rate 命令,而不是继续固定惩罚 yaw。
  • IMU 和编码器在仿真中暂时无噪声、无量化、无延迟,尚未包含完整电机电气模型。
  • reset 初始倾角范围较小;正式 sim-to-real 训练应增加初始角速度、外部推力、传感器噪声和延迟随机化。
  • 位置保持奖励是仿真塑形项,真实车辆没有绝对 XY 位置传感器,部署主要依靠 IMU 和编码器估计状态。

常见问题

找不到 balance_car.usd

检查 assets/ 中的 URDF 和 STL 是否已从外部资产包复制回来。若 USD 不存在, 先运行“从 URDF/STL 生成 USD”中的转换命令;assets/ 被 .gitignore 忽略, 干净克隆不会自动包含模型资源。

checkpoint 无法加载

确认 checkpoint 对应的 Actor 输入维度为 10、隐藏层为 [32, 32]、激活函数为 ReLU。网络结构变化后必须重新训练。

任务未注册

确认已经激活正确的 isaaclab 环境,并执行过:

python -m pip install -e "$BALANCE_CAR_ROOT" --no-deps

Introduction

可用于训练双轮平衡车原地平衡策略,并导出轻量 Actor 供 STM32 部署验证。项目基于 Isaac Lab 与 RSL-RL 实现 PPO,使用 IMU 和轮编码器观测,输出左右轮力矩,支持训练、播放与导出。【此简介由AI生成】

Customize your domain