强化学习与控制论:从LQR到PPO的倒立摆实战解析
发布时间:2026/8/30 15:00:56 作者:尧图编辑部 阅读量:1,286

在接触强化学习Reinforcement Learning, RL之前不少读者是做传统控制出身或者正在机器人、自动驾驶、工业自动化领域使用 PID、MPC、LQR 这类经典方法。另一部分读者则从深度学习切入第一次接触“智能体与环境交互”的概念对控制理论里那些状态空间、可观性、稳定性分析感到陌生。两种视角在同一个问题上经常“鸡同鸭讲”控制工程师觉得 RL 像黑箱调参RL 研究者觉得控制论数学太重、约束太多。其实这两个学科研究的是同一件事在未知或部分已知的环境中通过动作影响系统状态从而优化一个长期目标。控制论把这件事叫做“最优控制”强化学习把它叫做“序列决策”。本文想系统梳理两者的连接点并从工程落地角度给出对照实验、代码实现、常见坑点与最佳实践。无论你从哪个方向进入读完都能建立一条“从经典控制到强化学习”的完整认知链。1. 为什么要把强化学习和控制放在一起看1.1 控制论视角的“闭环思想”控制论的核心是闭环反馈。系统输出被传感器测量控制器根据测量值与期望值的偏差计算控制量再作用到执行器上。整个过程可以用“感知—决策—执行”三个词概括。经典控制方法通常需要先建立被控对象的数学模型。比如倒立摆系统我们会写出它的微分方程在工作点附近做线性化然后设计 LQR 或 PID 控制器。模型越准确控制器效果越好一旦模型偏差过大控制效果就会明显下降。这带来一个天然瓶颈很多真实系统难以精确建模。机械臂的摩擦力、无人机的空气动力学、电网的负荷波动都存在大量不确定性和强非线性。传统控制方法处理这些场景时往往需要复杂的系统辨识和鲁棒控制设计周期长、成本高。1.2 强化学习视角的“数据驱动决策”强化学习的思路完全不同。它不要求你提前写出精确的动力学方程而是通过智能体与环境的大量交互用奖励信号引导策略改进。智能体在某个状态 $s$ 下选择动作 $a$环境返回下一个状态 $s$ 和奖励 $r$。智能体的目标是最大化累计奖励。这个过程本质上也是一个闭环策略根据状态输出动作环境对动作做出响应策略再根据新的状态继续决策。与控制论相比强化学习更像一个“数据驱动的控制器设计方法”。它不需要显式建模但需要大量试错而且对安全性和稳定性缺乏天然保障。这也是为什么业界常说要“用控制的严谨性改造 RL用 RL 的灵活性增强控制”。1.3 两个领域的核心关系用一个表格快速对比维度经典控制最优控制强化学习系统模型显式微分/差分方程隐式环境转移或无模型采样目标最小化代价函数最大化累计奖励决策变量控制律 $u Kx$ 等策略 $\pi(a \mid s)$求解工具动态规划、Riccati 方程、凸优化值迭代、策略梯度、Q-learning对模型依赖高低对数据依赖低高安全保证相对成熟仍在发展这个表格是全文的骨架。后面所有内容都会围绕这些差异和联系展开。2. 历史同源从最优控制到强化学习的血缘关系2.1 Bellman 是共同祖先很多人不知道强化学习最核心的 Bellman 方程最早正是从动态规划中诞生的。Richard Bellman 在 20 世纪 50 年代研究多阶段决策过程时提出了“最优性原理”一个最优策略的子策略在其对应的子状态上也是最优的。这个思想同时滋养了两个学科。控制理论把它发展为动态规划求解最优控制问题衍生出 HJBHamilton-Jacobi-Bellman方程计算机科学和人工智能则把它引入离散马尔可夫决策过程MDP后来成为强化学习的理论基石。2.2 从制导问题到 Q-Learning20 世纪 50-60 年代美国空军资助了大量关于导弹制导、飞行控制的最优控制研究。当时的计算能力无法支撑大规模在线动态规划于是控制学者转向求解连续时间系统的 Riccati 方程这直接催生了 LQR 和 Kalman 滤波。到了 80 年代Sutton、Barto 等人把时序差分TD学习引入人工智能领域强化学习才逐渐成为独立方向。再后来DQN、PPO、SAC 等深度强化学习算法的出现让 RL 在高维状态空间取得了突破。一句话总结控制论率先把“最优性原理”变成可计算的工程工具强化学习则把同一个原理推广到模型未知、状态高维、决策序列化的场景。3. 理论连接从 Bellman 方程到 LQR 的过渡3.1 MDP 与状态空间的数学定义强化学习里最常见的是离散时间 MDP用五元组 $(S, A, P, R, \gamma)$ 描述$S$状态集合$A$动作集合$P(s \mid s, a)$状态转移概率$R(s, a, s)$奖励函数$\gamma$折扣因子$0 \le \gamma 1$控制理论里的离散时间状态空间模型是$$ x_{k1} A_d x_k B_d u_k $$两者形式非常接近。如果把状态 $x_k$ 对应到 $s$控制量 $u_k$ 对应到动作 $a$转移概率 $P(s \mid s, a)$ 退化为确定性映射 $f(x,u)$那么 MDP 就退化成了确定性控制系统模型。3.2 从值函数到 HJB 方程在连续时间、连续状态的最优控制问题中值函数 $V(x(t))$ 满足 HJB 方程$$ 0 \min_u \left[ g(x,u) \nabla_x V(x)^T f(x,u) \right] $$其中 $g(x,u)$ 是瞬时代价函数$f(x,u)$ 是系统动力学。这个方程描述的正是“当前代价 未来值函数变化率 0”的最优条件。在离散时间强化学习中状态-动作值函数 $Q(s,a)$ 满足 Bellman 最优方程$$ Q^(s,a) \mathbb{E} \left[ r \gamma \max_{a} Q^(s, a) \right] $$这两个方程是同一个最优性原理在不同数学语言下的表达。HJB 是微分形式Bellman 方程是差分形式。3.3 LQR强化学习里的“线性特例”线性二次型调节器LQR是最优控制中最经典的算法。系统是线性的代价是状态和控制量的二次型$$ J \sum_{k0}^{\infty} \left( x_k^T Q x_k u_k^T R u_k \right) $$LQR 的解是一个线性状态反馈控制律 $u_k -K x_k$其中 $K$ 通过求解离散代数 Riccati 方程得到。有趣的是如果我们在一个确定性线性系统中使用“线性策略 二次奖励”并采用类似 Q-learning 的值迭代方式求解最终收敛到的结果就是 LQR。这也是为什么很多 RL 入门教程喜欢拿 LQR 做基准——它既是控制理论的经典算法又是 RL 理论可以精确验证的特例。4. 环境准备与工具链4.1 Python 环境搭建本文代码以 Python 3.9 为基础建议使用虚拟环境隔离依赖。python -m venv rl_control_env source rl_control_env/bin/activate4.2 需要安装的库控制部分使用python-control强化学习部分使用gymnasium和stable-baselines3。绘图使用matplotlib数值计算使用numpy。pip install control matplotlib numpy pip install gymnasium stable-baselines3这里提醒一点stable-baselines3在你写代码时可能已经升级到了不兼容的新版本安装时最好查看官方文档确认 API。下面代码以 SB3 2.x 的常用 API 为例核心思路不变。4.3 仿真环境选择倒立摆是最适合做“控制 vs RL”对照实验的经典环境。它状态维度适中物理意义明确既能用 LQR 精确求解也能用 RL 训练策略。gymnasium自带的CartPole-v1是简化版倒立摆状态只有 4 维动作是离散的适合跑 DQN 和 PPO。更真实的连续控制版本可以用InvertedPendulum-v4动作是连续力矩适合跑 SAC 和 PPO。5. 实战第一部分用 LQR 控制倒立摆5.1 线性化模型单级倒立摆的连续时间非线性动力学方程是$$ (M m) \ddot{x} m l \ddot{\theta} \cos\theta - m l \dot{\theta}^2 \sin\theta F $$$$ m l \ddot{x} \cos\theta m l^2 \ddot{\theta} - m g l \sin\theta 0 $$在竖直向上的平衡点 $\theta \pi$ 附近线性化并选取状态向量$$ x [p, \dot{p}, \theta, \dot{\theta}]^T $$可以得到标准的线性状态空间方程$$ \dot{x} A x B u $$其中 $u$ 是小车驱动力。5.2 代码实现 LQR 控制器下面使用python-control直接设计 LQR。# 文件路径lqr_cartpole.py import control as ct import numpy as np import matplotlib.pyplot as plt # 倒立摆物理参数 M 1.0 # 小车质量 kg m 0.1 # 摆杆质量 kg l 0.5 # 摆杆长度的一半 m g 9.8 # 重力加速度 # 线性化后的状态空间矩阵在平衡点附近 # 状态: [位置, 速度, 摆角, 摆角速度] A np.array([ [0, 1, 0, 0], [0, 0, -m*g/M, 0], [0, 0, 0, 1], [0, 0, (Mm)*g/(M*l), 0] ]) B np.array([ [0], [1/M], [0], [-1/(M*l)] ]) C np.eye(4) D np.zeros((4, 1)) sys ct.ss(A, B, C, D) # LQR 权重矩阵 Q np.diag([10.0, 1.0, 100.0, 1.0]) # 摆角误差权重最大 R np.array([[1.0]]) K, S, E ct.lqr(sys, Q, R) print(LQR 增益矩阵 K:) print(K)这里Q矩阵对角线上的值表示我们对各个状态的重视程度。因为任务是“稳住摆杆”所以摆角 $\theta$ 对应的权重最大。R表示对控制力大小的惩罚R越小控制器越“敢用力”。5.3 仿真并绘制响应曲线为了验证控制效果我们可以用ct.forced_response仿真闭环系统。# 文件路径lqr_cartpole.py续 # 初始状态摆杆偏离 10 度 theta0 np.deg2rad(10) x0 np.array([0.0, 0.0, theta0, 0.0]) T np.linspace(0, 5, 500) # 闭环系统 sys_cl ct.ss(A - B K, B, C, D) # 零输入响应 t_out, y_out ct.initial_response(sys_cl, T, x0) plt.figure(figsize(10, 6)) plt.subplot(2, 1, 1) plt.plot(t_out, y_out[2] * 180 / np.pi, labeltheta (deg)) plt.axhline(y0, colorr, linestyle--, labeltarget) plt.ylabel(Pendulum angle (deg)) plt.legend() plt.grid(True) plt.subplot(2, 1, 2) plt.plot(t_out, y_out[0], labelposition (m)) plt.ylabel(Cart position (m)) plt.xlabel(Time (s)) plt.legend() plt.grid(True) plt.tight_layout() plt.savefig(lqr_response.png, dpi150) plt.show()运行后可以看到摆角从 10 度快速收敛到 0小车位置也回到原点。LQR 的优点是响应快、有理论保证缺点是必须依赖模型而且只能在平衡点附近线性化范围内有效。6. 实战第二部分用强化学习控制倒立摆6.1 强化学习环境封装我们还是使用倒立摆作为任务但这次不直接设计控制律而是让智能体通过试错学习。如果使用gymnasium自带的离散版本环境定义非常简单# 文件路径rl_cartpole.py import gymnasium as gym import numpy as np from stable_baselines3 import PPO from stable_baselines3.common.env_util import make_vec_env from stable_baselines3.common.vec_env import VecNormalize # 创建向量化环境 env make_vec_env(CartPole-v1, n_envs4) # 使用归一化帮助策略收敛 env VecNormalize(env, norm_obsTrue, norm_rewardTrue) model PPO( MlpPolicy, env, learning_rate3e-4, n_steps2048, batch_size64, n_epochs10, gamma0.99, gae_lambda0.95, clip_range0.2, verbose1, seed42 ) # 开始训练 model.learn(total_timesteps200_000) model.save(ppo_cartpole) # 保存归一化参数 env.save(vec_normalize.pkl)这里有几个关键点需要解释make_vec_env会创建并行环境加快采样速度。VecNormalize会对观测和奖励做归一化这在 RL 训练中几乎必不可少。PPO 的n_steps是每次策略更新前收集的步数n_epochs是每批数据重复更新的次数。这两个参数影响训练稳定性和速度。gamma是折扣因子体现智能体对远期奖励的重视程度。6.2 加载模型并评估训练完成后我们加载模型并运行一个完整 episode观察智能体的表现。# 文件路径eval_cartpole.py import gymnasium as gym from stable_baselines3 import PPO from stable_baselines3.common.vec_env import DummyVecEnv, VecNormalize # 创建环境时保持结构一致 env DummyVecEnv([lambda: gym.make(CartPole-v1)]) env VecNormalize.load(vec_normalize.pkl, env) env.training False env.norm_reward False model PPO.load(ppo_cartpole) obs env.reset() total_reward 0 step_count 0 done False while not done: action, _ model.predict(obs, deterministicTrue) obs, reward, dones, info env.step(action) total_reward reward[0] step_count 1 if dones[0]: done True print(fEpisode length: {step_count}) print(fTotal reward: {total_reward:.2f})CartPole-v1中智能体每维持一步获得 1 分如果不倒最大步数为 500。训练好的 PPO 通常能稳定跑到 500 步。6.3 连续控制版本InvertedPendulum要和控制论做更公平的对比建议使用连续动作版本。gymnasium的InvertedPendulum-v4是 MuJoCo 环境需要安装pip install gymnasium[mujoco]训练脚本几乎不变只需要把环境名换掉并把策略换成 SAC 或 PPO# 文件路径rl_pendulum_continuous.py import gymnasium as gym from stable_baselines3 import SAC from stable_baselines3.common.env_util import make_vec_env env make_vec_env(InvertedPendulum-v4, n_envs1) model SAC( MlpPolicy, env, learning_rate3e-4, buffer_size300_000, batch_size256, tau0.005, gamma0.98, verbose1, seed42 ) model.learn(total_timesteps300_000) model.save(sac_inverted_pendulum)连续动作空间中SAC 通常比 PPO 更稳定因为它基于最大熵强化学习对奖励尺度不敏感。不过训练时间会明显增加建议在有 GPU 的机器上运行。7. RL 与控制融合的新视角7.1 模型预测控制与 RL 的结合模型预测控制MPC已经在工业控制中广泛应用。它的核心思想是在每一个控制周期基于当前状态求解一个有限时域优化问题只执行第一个控制量然后下一周期重新求解。MPC 的优势是能显式处理约束缺点是需要在线优化计算量大且模型不准时效果会下降。近年来的研究尝试用 RL 学一个“短时域 MPC 的近似解”或者用 RL 来校正 MPC 的模型误差。这种结合不是“二选一”而是“互相补位”。7.2 安全约束与约束 RL真实工程环境不允许智能体随意探索比如无人机撞墙、机械臂超出关节限位、电网频率越限。因此安全强化学习成为热点。控制论已经有一套成熟的约束处理方法比如障碍函数、控制不变集、MPC 中的硬约束。把这些方法引入 RL 的策略优化过程可以显著降低训练风险。如果你要在真实设备上跑 RL务必在仿真中验证安全机制再考虑迁移到物理系统。7.3 多智能体与机器人的控制趋势在机器人领域ROS 2 Control 已经成为统一的硬件控制框架它的底层仍然依赖经典控制理论。而在多智能体场景中RL 开始处理更复杂的协作与博弈问题。例如最新的多智能体强化学习方法会使用贝叶斯动作解码器Bayesian Action Decoder来推断队友或对手的潜在意图在部分可观测环境中表现出色。这类方法的落地往往需要把“经典底层控制”和“高层 RL 决策”结合起来底层用 PID、MPC 保证系统稳定顶层用 RL 做路径规划和任务分配。8. 常见问题与排查思路下面是学习中最高频的问题按现象整理成表问题现象常见原因解决思路PPO 训练不收敛reward 一直在最低值奖励信号设计不合理或观测未归一化检查 reward 是否过于稀疏加入VecNormalize适当调整学习率训练过程中 reward 突然下降策略更新步长过大或环境随机性过强减小clip_range降低学习率增加n_steps和n_epochsSAC 训练时出现 NaN loss学习率过高或奖励尺度过大减小学习率对 reward 做 clip检查网络输入是否有 NaN模型在仿真中表现好真机上完全失效sim-to-real gap真实系统存在延迟和噪声使用 domain randomization添加随机扰动提高控制器鲁棒性控制回路频率不满足要求control loop miss its desired rate算法推理时间过长或底层驱动响应不及时优先减小策略网络规模尝试模型量化检查实时系统调度配置训练时 docker 服务启动失败报job for docker.service failed because the control process exited with errorDocker 服务因环境冲突或磁盘问题崩溃查看journalctl -u docker日志清理磁盘空间重启服务后确认状态安装 ROS2 相关包时 dpkg-deb 报错下载的 .deb 文件不完整或仓库源不稳定删除 /tmp 下的缓存包换用国内镜像源重新执行安装命令8.1 控制回路频率问题的详细排查控制系统对实时性要求极高。如果 RL 策略的推理时间超过了控制周期的要求整个系统会变得不稳定。你可以先用time命令测一次模型推理耗时import time import gymnasium as gym from stable_baselines3 import PPO model PPO.load(ppo_cartpole) env gym.make(CartPole-v1, render_modergb_array) obs, _ env.reset() start time.perf_counter() action, _ model.predict(obs, deterministicTrue) end time.perf_counter() print(f单次推理耗时: {(end - start) * 1000:.2f} ms)如果耗时超过控制周期就需要考虑裁剪网络层数、使用 TensorRT/ONNX 导出模型、或者把 RL 决策放到更高层底层仍由 PID 执行。8.2 LaTeX 文档中的 undefined control sequence写论文时如果遇到undefined control sequence报错通常是命令拼写错误或缺少宏包。比如输入\R之前必须先定义\newcommand{\R}{\mathbb{R}}否则编译就会报错。排查方法先定位文档中第一个报错行号再看看是不是漏了\usepackage{amsmath}或\usepackage{amssymb}。9. 最佳实践与工程建议9.1 先从简单任务开始不管最终目标多复杂先在一个简单、低维、可快速训练的环境上跑通全流程再逐步增加难度。直接上高维连续控制任务很容易陷入“训练很久但不知道为什么失败”的困境。9.2 仿真先行真机后置所有 RL 实验都应在仿真环境完成充分验证。真机测试时必须设置安全保护机制比如力矩限制、速度限制、急停开关。授权、权限与操作规范也要提前梳理清楚尤其是多人协作时要明确谁有权限修改控制器参数。9.3 把“控制知识”编码进奖励函数在 RL 的奖励函数中引入控制论思想往往能大幅提升训练效率。例如用二次型误差作为负奖励类似 LQR 的代价函数。约束违反时给出大的惩罚类似 MPC 的软约束。在动作项中加入惩罚避免剧烈抖振类似于控制量权重的效果。9.4 记录实验日志保证可复现强化学习实验对随机种子和超参数极其敏感。建议每次训练都记录随机种子网络结构超参数环境版本训练时间步数奖励曲线使用TensorBoard或wandb可以自动记录训练曲线。推荐在代码中固定随机种子import numpy as np import random import torch def set_seed(seed): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) set_seed(42)9.5 善用经典控制方法做基准不管你的 RL 算法多花哨都应该先跑一个传统基线。比如线性系统用 LQR 或 PID 做基线。非线性系统用 MPC 或基于 Lyapunov 的方法做基线。对照实验可以帮助判断 RL “学到的策略”是否真的比经典方法更优还是只是因为调参过度。9.6 注意环境依赖与系统配置在 Linux 上安装控制相关依赖时经常会遇到包管理器问题。比如前面提到的 dpkg-deb 错误常见原因是下载文件不完整。建议所有安装步骤都写在 Dockerfile 里这样不会污染宿主机环境也方便复现。Docker 服务如果遇到control process exited with error优先查看日志和磁盘空间很多时候是/var/lib/docker所在分区满了。10. 总结与学习路线到这里我们已经完整梳理了强化学习与控制论的关系并用 LQR 和 PPO/SAC 两个方向攻克了同一个倒立摆问题。你至少应该掌握了控制论和强化学习在数学上的同源性Bellman 方程、HJB 方程、LQR 都是最优性原理的不同表达。如何用python-control快速求解 LQR 控制器。如何在gymnasium中搭建 RL 训练环境并用stable-baselines3训练 PPO 和 SAC。为什么 RL 不是控制的替代品而是互补工具。训练不稳定、模型失效、控制回路频率不足等高频问题的排查思路。下一步可以这样继续深入读懂 DQN、PPO、SAC 的原始论文理解每个算法的理论动机。在 Gymnasium 中复现经典控制环境尝试把 LQR 的结果作为 RL 的初始化策略。学习安全强化学习和约束策略优化这对真实工程落地至关重要。阅读 ROS 2 Control 源码理解经典控制框架如何与高层 RL 决策集成。尝试多智能体场景结合贝叶斯动作解码器等最新方法探索协作控制问题。控制论和强化学习的融合远未结束。作为工程师与其争论哪个学派更优不如在实践中找到两者的黄金结合点用控制保证安全底线用 RL 扩展决策边界。如果这篇文章对你理解 RL 与控制的关系有帮助可以收藏备用也欢迎在评论区交流你的训练和控制经验。动手跑一遍示例代码比看十遍理论都更有收获。