# 线性二次调节器 LQR(Linear Quadratic Regulator,线性二次调节器)是一个典型的连续控制与稳定化任务。本仓库当前提供两个变体: - `dm-lqr-2-1`:两个小球通过绳索相连,只有最后一个小球受控。 - `dm-lqr-6-2`:六个小球串联成链,只有最后两个小球受控。 智能体需要在尽量小的控制代价下,将整条系统拉回中心附近并稳定停下。 ```{video} /_static/videos/dm_lqr_2_1.mp4 :poster: _static/images/poster/dm_lqr_2_1.jpg :nocontrols: :autoplay: :playsinline: :muted: :loop: :width: 100% ``` ```{video} /_static/videos/dm_lqr_6_2.mp4 :poster: _static/images/poster/dm_lqr_6_2.jpg :nocontrols: :autoplay: :playsinline: :muted: :loop: :width: 100% ``` --- ## 任务描述 这两个任务都可以看作一维弹簧-阻尼链的平衡控制问题。每个小球只有一个沿 x 轴的滑动自由度,相邻小球之间通过“绳”形成耦合,系统同时受到: - 球体自身阻尼 - 相邻球体之间的弹簧力和相对速度阻尼 - 指向原点的中心回复力 - 控制输入作用在末端受控自由度上 其中: - `dm-lqr-2-1` 更简单,适合先验证是否能学会稳定驻点。 - `dm-lqr-6-2` 需要把控制作用沿链条传递到更远的非受控球,难度更高。 --- ## 动作空间(Action Space) ### dm-lqr-2-1 | 项目 | 详细信息 | | -------- | ------------------------------- | | **类型** | `Box(-1.0, 1.0, (1,), float32)` | | **维度** | 1 | | 序号 | 动作含义 | 最小值 | 最大值 | 对应 XML 关节 | | ---: | ------------------------ | :----: | :----: | :-----------: | | 0 | 作用在末端球上的控制输入 | -1.0 | 1.0 | `q1` | ### dm-lqr-6-2 | 项目 | 详细信息 | | -------- | ------------------------------- | | **类型** | `Box(-1.0, 1.0, (2,), float32)` | | **维度** | 2 | | 序号 | 动作含义 | 最小值 | 最大值 | 对应 XML 关节 | | ---: | ---------------------- | :----: | :----: | :-----------: | | 0 | 倒数第二个球的控制输入 | -1.0 | 1.0 | `q4` | | 1 | 最后一个球的控制输入 | -1.0 | 1.0 | `q5` | --- ## 观察空间 观察由所有位置 `qpos` 和速度 `qvel` 直接拼接而成。 ### dm-lqr-2-1 | 项目 | 详细信息 | | -------- | ------------------------------- | | **类型** | `Box(-inf, inf, (4,), float32)` | | **维度** | 4 | | 序号 | 观察量 | 含义 | | ---: | ------ | --------------- | | 0 | `q0` | 第 1 个球的位置 | | 1 | `q1` | 第 2 个球的位置 | | 2 | `dq0` | 第 1 个球的速度 | | 3 | `dq1` | 第 2 个球的速度 | ### dm-lqr-6-2 | 项目 | 详细信息 | | -------- | -------------------------------- | | **类型** | `Box(-inf, inf, (12,), float32)` | | **维度** | 12 | 前 6 维为 `q0 ~ q5`,后 6 维为 `dq0 ~ dq5`。 --- ## 奖励函数设计 当前实现的奖励由状态代价、速度代价、控制代价、成功奖励和越界惩罚组成: ```python state_cost = 0.5 * sum(qpos ** 2) velocity_cost = 0.5 * velocity_cost_coef * sum(qvel ** 2) control_cost = 0.5 * control_cost_coef * sum(action ** 2) reward = 1.0 - (state_cost + velocity_cost + control_cost) reward += success_bonus reward -= out_of_bounds_penalty ``` 直观上: - 离中心越远,奖励越低 - 速度越大,奖励越低 - 控制越激进,奖励越低 - 当系统进入“接近原点且速度足够小”的稳定区域时,会得到成功奖励 - 越界时会受到额外惩罚 --- ## 初始状态 每次重置时: - 位置向量从随机方向采样,再归一化到固定范数 - 速度初始化为 0 当前配置中: - `dm-lqr-2-1` 的初始位置范数约为 `0.8` - `dm-lqr-6-2` 的初始位置范数约为 `1.0` --- ## Episode 终止条件 满足以下任一条件时,当前 episode 结束并重置: - 达到成功条件: 位置范数小于成功距离阈值,且速度范数小于成功速度阈值 - 超出边界: 任意位置超过边界范围,或任意速度超过速度边界 - 状态非常接近零点平衡态 - 观察或动作中出现 `NaN` --- ## 使用指南 ### 1. 环境预览 ```bash uv run scripts/view.py --env dm-lqr-2-1 uv run scripts/view.py --env dm-lqr-6-2 ``` ### 2. 开始训练 ```bash uv run scripts/train.py --env dm-lqr-2-1 uv run scripts/train.py --env dm-lqr-6-2 ``` ### 3. 查看训练曲线 ```bash uv run tensorboard --logdir runs/dm-lqr-2-1 uv run tensorboard --logdir runs/dm-lqr-6-2 ``` ### 4. 测试训练结果 ```bash uv run scripts/play.py --env dm-lqr-2-1 uv run scripts/play.py --env dm-lqr-6-2 ``` --- ## 预期训练结果 ### dm-lqr-2-1 1. 受控球能够带动未受控球一起回到中心附近。 2. 两个球的位置和速度最终都收敛到较小范围内。 3. 策略不会长期停在偏离中心的静止点。 ### dm-lqr-6-2 1. 最后两个受控球能够把整条链逐步拉回中心。 2. 链条传播过程中不会出现明显发散或持续振荡。 3. 成功率随训练推进逐步上升,越界率逐步下降。