可用于训练双轮平衡车原地平衡策略,并导出轻量 Actor 供 STM32 部署验证。项目基于 Isaac Lab 与 RSL-RL 实现 PPO,使用 IMU 和轮编码器观测,输出左右轮力矩,支持训练、播放与导出。【此简介由AI生成】
| Files | Last commit | Last 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 导入器完成转换:
- 打开 Isaac Sim 的 URDF Importer,选择
assets/urdf/car.SLDASM3.urdf。 - 确认距离单位为米(distance scale 为
1.0),保留关节和惯量信息。 - 关闭不需要的自碰撞;轮子驱动由 Isaac Lab 的 actuator 配置提供,不要在 导入器中额外设置位置/速度驱动。
- 导入后将生成的顶层 USD 和其
configuration/子层一起保存到assets/usd/,顶层文件名保持为balance_car.usd。 - 在 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