news 2026/9/9 16:16:51

Matlab强化学习实战:从零训练一级倒立摆全流程指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Matlab强化学习实战:从零训练一级倒立摆全流程指南

简介:一个基于MATLAB的强化学习倒立摆仿真程序包,面向自动化、人工智能方向的初学者与研究人员,用于解决一级倒立摆的平衡控制问题。压缩包内共2个文件,均为.m源代码,整体大小4KB,其中一份负责倒立摆动力学建模,另一份实现强化学习训练与仿真流程,适合在MATLAB中直接运行和二次开发。资源已有1569人学习,代码精简无冗余依赖,便于拆解状态空间、动作空间、奖励函数及策略更新等核心环节。通过学习该程序,读者可掌握用Q学习等强化学习算法处理经典非线性控制问题的完整思路,也可在此基础上修改奖励函数或换用DQN等深度强化学习方法,是快速上手强化学习项目实践的不错示例。 如果你问我强化学习入门最值得复现的第一个项目是什么,我肯定会说:倒立摆。没有别的理由,就因为它能用最短的时间让你跑通强化学习的完整链路——环境、智能体、训练、评估,而且效果极其直观:一根杆子立在小车上,智能体从随机乱晃到慢慢稳住,整个过程肉眼可见,比对着公式空想有意思多了。

这篇记录的是我在Matlab里用强化学习训练一级倒立摆的实操全过程,覆盖方案选型、环境搭建、智能体配置、训练调参和问题排查。适合正在做课程设计或毕业设计的学生,也适合刚接触强化学习、想在仿真环境里快速验证算法效果的工程师。我的做法是直接用Matlab的Reinforcement Learning Toolbox来搭环境和智能体,整个流程尽量贴近真实项目里“从零到能跑、再调优到能用”的节奏,每一个关键地方的原理和坑都会讲到,你照着操作基本不会卡在半路。

1. 整体思路与方案选型

1.1 为什么选Matlab而不是Python

现在一聊强化学习,很多人第一反应就是Python加OpenAI Gym之类框架。这个路线确实主流,但不代表它是所有场景的最优解。对于倒立摆这个具体问题,Matlab的优势相当明显。

首先是环境成本低。OpenAI Gym里倒立摆确实也有,但你得先配Python环境、装gym、处理不同版本的接口差异,运气不好光装环境就能折腾半天。Matlab这边一行命令拿到CartPole环境,不用解决任何依赖问题。其次是可视化方便,训练过程中可以直接看到小车的实时动画,也能通过工具箱自带的绘图函数观察每个episode的奖励曲线,这对理解算法行为、定位训练问题非常有帮助。

再者是算法切换成本低。Matlab的强化学习工具箱把DQN、DDPG、PPO、TD3这些常见算法都封装成了统一的智能体接口,换算法就是改几行配置。做课程设计或者算法对比实验的时候,这个优势会被放大得很明显。如果项目后续要往硬件部署走,Matlab还可以用Simulink生成C代码,同一个控制策略直接落到嵌入式控制器上,前后衔接非常顺。所以我觉得,在倒立摆这类教学和验证场景里,Matlab是比Python更省心的选择。

1.2 算法选型:离散动作用DQN,连续动作用DDPG或TD3

倒立摆控制的难点在于系统本身不稳定,摆杆任何一点小偏角都会因为重力效应被放大,如果不加控制,杆子会在零点几秒内倒下去。传统做法里,LQR和模糊控制是常见方案,网上搜“一级倒立摆模糊控制”也能找到很多资料,但这类方法依赖系统建模精度,控制器设计也要花不少功夫。强化学习的思路是直接从交互数据里学策略,不靠人工设计控制律,这正好适合作为入门项目。

在具体算法选择上,我建议先看动作空间类型。如果小车受力只有“向左”和“向右”两个离散选项,DQN是最合适的入门算法。DQN的原理可以理解成把“做每个动作值多少钱”这件事用神经网络拟合出来,然后每次选择最值钱的动作执行。如果控制量是连续力,比如小车受力范围在-10N到10N之间,那就得用DDPG、TD3这类处理连续动作空间的算法。

我自己第一次做的时候选的是DQN,理由有三条:实现简单、调参相对容易、训练过程稳定。连续动作版本的DDPG在控制效果上通常更细腻,但需要调的地方也多,比如探索噪声大小、Actor和Critic的学习率比例等。入门阶段建议先用DQN把整个流程跑通,再回头换成连续控制算法做对比,对理解算法差异会很有帮助。

1.3 项目整体流程:从环境到评估的闭环

整个项目的推进路径我建议按下面这条线走,每完成一步都有明确的产出,不容易出现“不知道下一步做什么”的情况。

  • 环境准备:安装Matlab R2019a及以上版本,确认强化学习工具箱可用。
  • 环境搭建:用rlPredefinedEnv创建CartPole环境,或自己搭Simulink模型作为环境。
  • 智能体设计:选择DQN,设计神经网络结构和关键超参数。
  • 训练调试:设置训练选项,实时观察奖励曲线,发现问题及时止损并调整。
  • 仿真验证:把训练好的智能体放回环境里,观察控制效果和稳定性。
  • 结果分析:绘制摆杆角度、小车位置等状态变量的变化曲线,量化评估控制性能。

这个流程本质上覆盖了强化学习实验的完整闭环,后面所有小节都是围绕这条线展开的。

2. 倒立摆系统与强化学习关键细节

2.1 倒立摆动力学模型与状态空间

倒立摆的经典模型是一辆可以在水平轨道上移动的小车,小车上方铰接一根摆杆。系统状态通常用四个变量描述:小车位置x、小车速度dx/dt、摆杆角度θ、摆杆角速度dθ/dt。控制量是小车受到的水平作用力F。摆杆角度以竖直向上为0,一旦超过一定范围,比如正负12度,就认为平衡失败,当前回合结束。

这组状态变量非常值得琢磨。它们正好覆盖了“位置”和“变化趋势”两个层面,强化学习智能体依靠这四个数值来决定每一步该施加多大的力。数学模型上,倒立摆是非线性系统,运动方程里含有sinθ、cosθ这些项,控制领域通常会在平衡点附近做线性化处理,然后用状态空间方程表示。Matlab自带的CartPole-Discrete环境已经把这些动力学封装好了,我们实际写代码时不需要手动推导运动方程,但一定要理解状态维度和动作维度,因为它们直接决定了神经网络输入层和输出层的设计。

另外要注意的是量纲差异。四个状态变量中,角度的量级通常在0.01到0.1弧度,位置可能到几米,如果数据范围差异过大,会拖慢训练收敛。很多教程忽略了这一步,但我实际做下来,把状态归一化到相近的量级,训练速度会有肉眼可见的提升。

2.2 奖励函数设计:决定训练成败的手艺活

强化学习里算法只负责最大化累积奖励,但“奖励怎么定义”才是真正体现水平的地方。同一个算法,奖励函数设计不同,最终学出来的策略可能天差地别。倒立摆的奖励设计常见有三种思路,我都试过,感受很深。

第一种是稀疏奖励,摆杆保持直立就每步给一个正奖励,一旦倒下就结束当前回合。这种设计最接近Q-learning的原始设定,实现最简单,但学习速度很慢,前期智能体完全是在随机探索,很难收到正反馈。第二种是密集奖励,用角度和位置误差构造连续奖励,比如角度越小奖励越高、小车越靠近轨道中心奖励越高。收敛速度会明显加快,但需要仔细调各分量的权重。第三种是在奖励里加动作惩罚项,抑制频繁大幅度动作,能让训练出来的策略更平滑,控制过程不抖。

我第一次做的时候只用了角度误差作为奖励,结果训练完之后小车虽然能立住杆子,但会反复左右横冲,动作非常“神经质”。后来加了位置项和控制力惩罚项,策略才明显变得平滑。我的建议是,倒立摆这个场景直接上密集奖励,直接用比较简单的公式:奖励 = -α·θ² - β·x² - γ·F²。α、β、γ分别代表角度、位置、控制力的权重,根据实际效果调整。这个公式的直觉很简单:偏离平衡越远、离中心越远、用力越猛,奖励就越低。

2.3 智能体网络结构与超参数设置

以DQN为例,智能体由两部分组成:一个用于估计Q值的深度神经网络,加上一套经验回放机制。网络输入是四个环境状态,输出是两个动作分别对应的Q值。中间层用两层全连接,每层24个神经元就能跑得很稳,完全没必要一上来就堆大网络,对倒立摆来说大网络反而更难收敛。

超参数方面,我最常用的配置整理成了一张表,新手可以直接照抄,等跑通了再根据自己的情况调整。

参数推荐值设置理由
经验回放池大小10000足够覆盖多样历史经验,又不会让训练初期的无效数据占太大比例
小批量大小64训练稳定性和更新频率的平衡点
目标网络更新频率每4步太频繁会让Q值估计不稳定,太慢则学习速度下降
初始探索率0.9前期尽可能多探索动作空间
探索率衰减每步乘以0.995随着训练进行逐步减少随机动作比重
折扣因子0.99倒立摆是长期平衡任务,需要看重未来收益

这里有一个容易被忽略的细节:经验回放。DQN里的经验回放就像整理错题本,智能体把每一步的状态、动作、奖励、下一状态存起来,训练时从中随机抽一小批来学习。这样做有两个好处,一是打破前后经验之间的相关性,让网络训练更稳定;二是提高数据利用率,一条经验可以反复学习。刚开始接触强化学习的人,经常以为智能体是“边学边忘”的,理解了经验回放机制,就能明白数据复用的重要性了。

3. 实操:从零构建DQN倒立摆程序

3.1 创建环境:一行代码拿到CartPole

Matlab的强化学习工具箱直接提供了CartPole环境,创建代码非常简短:

env = rlPredefinedEnv('CartPole-Discrete');

就这么一行,环境就创建好了。接下来可以查看环境的观测信息和动作信息,确认维度是否符合预期:

obsInfo = getObservationInfo(env); actInfo = getActionInfo(env); disp(obsInfo); disp(actInfo);

观测信息里会看到四个状态变量的维度和范围,动作信息会看到两个离散动作。这个环境默认算一步是0.02秒,也就是说智能体每20毫秒要做一次控制决策。如果后续想模拟更真实或者更复杂的场景,可以基于Simulink自建环境,但入门阶段强烈建议先用现成环境,把精力集中在理解强化学习本身的流程上。

3.2 搭建神经网络与DQN智能体

网络结构用Matlab的深度学习网络设计方式搭建,输入层对应四维状态,输出层是两个动作的Q值。代码可以这样写:

statePath = [ featureInputLayer(4, 'Normalization', 'none', 'Name', 'state') fullyConnectedLayer(24, 'Name', 'fc1') reluLayer('Name', 'relu1') fullyConnectedLayer(24, 'Name', 'fc2') reluLayer('Name', 'relu2') fullyConnectedLayer(2, 'Name', 'output')]; qNetwork = dlnetwork(statePath); agentOptions = rlDQNAgentOptions(... 'ExperienceBufferLength', 10000, ... 'MiniBatchSize', 64, ... 'TargetUpdateFrequency', 4, ... 'ResetExperienceBufferBeforeTraining', false); agent = rlDQNAgent(obsInfo, actInfo, qNetwork, agentOptions);

这段代码里有两个细节值得说明。第一,网络输出层是2个神经元,对应两个离散动作,这一点和动作空间严格对应,不能随意改。第二,rlDQNAgent的输入是观测信息obsInfo和动作信息actInfo,智能体会自动识别状态维度和动作维度,所以前面getObservationInfo那一步不是多余的。如果你用的是R2020a之前的老版本,可能不支持dlnetwork直接传给rlDQNAgent,需要改成rlQValueRepresentation的写法,本质功能是一样的。

3.3 训练配置与过程监控

智能体创建好之后,设置训练选项。这一步很关键,因为训练选项直接影响训练时长和判断收敛的标准。

trainOpts = rlTrainingOptions(... 'MaxEpisodes', 1000, ... 'MaxStepsPerEpisode', 500, ... 'StopTrainingCriteria', 'AverageReward', ... 'StopTrainingValue', 480, ... 'ScoreAveragingWindowLength', 20, ... 'Plots', 'training-progress'); trainingStats = train(agent, env, trainOpts);

解释一下这几个参数的逻辑。MaxEpisodes设置为1000,是给训练留足空间,实际通常用不了那么多轮。MaxStepsPerEpisode设置为500,意思是一个回合最多跑500步就强制结束,这样既能保证智能体有足够的平衡时间,又不会让训练无限拖下去。StopTrainingValue设置为480,是因为每回合上限500步,如果平均奖励接近480,说明绝大多数回合都坚持到了最后,基本可以认定控制策略已经稳定。ScoreAveragingWindowLength设为20,表示看最近20个回合的平均奖励,避免偶发性表现引起误判。

训练过程中,Matlab会弹出一个实时进度窗口,画出两条曲线:一个是每个回合的奖励,一个是滑动平均奖励。我正常训练下来,大概在200到500个回合之间会出现拐点,平均奖励从几十迅速爬升到400以上。如果训练到600个回合奖励还在低位徘徊,通常不是训练步数不够,而是超参数或者奖励设计出了问题,需要停下来排查。

3.4 仿真验证:把学到的策略放到环境中检验

训练结束并不代表工作完成,关键一步是让训练好的智能体重新在环境里跑一遍,看它是不是真的学会了维持平衡。仿真代码也非常简单:

simOpts = rlSimulationOptions('MaxSteps', 500); experience = sim(env, agent, simOpts);

跑完之后,experience里记录了一整个回合的观测、动作、奖励数据。我会把摆杆角度数据画出来,看它是否始终在零度附近波动:

theta = experience.Observation.theta.Data; plot(theta); xlabel('步数'); ylabel('摆杆角度(rad)');

画出来的曲线应该是在0附近小幅震荡的波形,说明智能体在持续修正摆杆姿态。如果曲线发散或者止步于某一步,说明策略还不够稳定。另外也可以试试把MaxSteps调得更大,比如1000步,看智能体能不能长期保持平衡。我之前有一次训练出来的智能体,在500步内表现完美,但拉到1000步就会在某个时刻突然失控,后来发现是训练回合上限恰好限制住了智能体的“耐力”,适当调大MaxStepsPerEpisode再训练一轮才解决。

3.5 可选的扩展:把离散动作换成连续控制

如果基础版本已经跑通,我强烈建议尝试换成连续动作控制,这是对理解强化学习算法非常有帮助的一步。你需要自己搭建一个连续力控制的CartPole环境,动作范围比如[-10, 10]牛顿,算法换成DDPG或TD3。代码框架也很简洁,大致是:

agent = rlTD3Agent(obsInfo, actInfo, ... actor, critic, agentOptions);

其中actor和critic需要分别定义网络结构,actor输出连续动作值,critic输出状态动作对的价值。这个过程中你会真正理解离散动作和连续动作在策略表示上的本质差异,而不是停留在概念层面。

4. 常见问题与调参避坑实录

4.1 训练不收敛:四个排查方向

训练不收敛是倒立摆项目里最常见的问题,我见过不少同学卡在这一步然后放弃了。这里把我用过的排查顺序写出来,按优先级从高到低排。

第一,检查奖励函数。如果奖励特别稀疏,比如只有倒下才给惩罚,那前期探索基本是在碰运气。先改用密集奖励,让每一步都能提供梯度,训练难度会立刻下降一个档次。第二,检查状态归一化。四个状态的量级差异太大会让神经网络很难学,把状态缩放到相近区间,收敛速度会明显提升。第三,检查探索率。如果epsilon衰减太快,智能体还没有充分探索动作空间就过早进入“利用”阶段,很容易陷入局部最优。我一般把epsilon从0.9开始,每步乘0.995,确保前期有足够的随机探索。第四,检查学习率。工具箱默认的1e-3对倒立摆是合理的,但如果你手动改过,可以尝试调低到1e-4,学习率过大是网络震荡发散的常见原因。

如果这四个方向都排查过了还是不行,那就重置环境并固定随机种子重新训练。强化学习本身随机性很大,同样的参数多次训练结果可能不一样,多跑几次有时候自然就收敛了。

4.2 训练收敛但控制效果差:奖励缺陷与网络问题

另一种让人头疼的情况是训练曲线看着很漂亮,平均奖励冲到上限,但实际仿真时控制效果却很差,小车在轨道上剧烈来回冲撞,摆杆角度震荡得厉害。这种情况往往不是算法问题,而是目标没有设计好。

我在第一次做到这个现象时,奖励函数里只设置了角度误差惩罚,智能体发现只要摆杆勉强不倒,位置再偏也无所谓,于是学会了“疯狂摆动加猛冲”的极端策略。解决办法就是我前面提到的,在奖励里加位置项和控制力惩罚项,让策略必须兼顾稳定性、位置居中和平滑性。如果你用的奖励里已经包含了位置项但还是抖动严重,可以适当增大控制力惩罚的权重。另外,网络结构太浅也可能导致学出来的Q值估计不够平滑,可以试着把隐层神经元从24增加到64,但注意不要过度,网络太大会造成训练不稳定。

还有一种情况是目标网络更新太频繁,导致Q值估计持续震荡。把TargetUpdateFrequency调低,比如从1改为4或者8,通常能改善稳定性。这个参数的作用是让目标Q值更新得慢一点,给网络学习留出缓冲,可以类比成“不要每次考试完都立刻改教材,而是积累一段时间再更新”。

4.3 工具箱版本与安装常见坑

最后聊一个容易被忽视的环境问题。强化学习工具箱是R2019a引入的,如果你的Matlab版本太老,会出现找不到rlPredefinedEnv这类函数的情况。我建议直接用R2021b以上版本,一方面函数接口稳定,另一方面dlnetwork的支持也更完善。

如果确认版本没问题但工具箱仍然不可用,可以检查一下安装列表里Reinforcement Learning Toolbox是否勾选。Matlab在安装时默认不会装全部工具箱,需要在MATLAB的“主页-附加功能-管理附加功能”里补装。学校或者公司通常都有正版授权,直接在附加功能里搜索安装就行。另外,不同版本之间rlDQNAgentOptions和rlTrainingOptions的具体字段偶尔会有小改动,如果某段代码在你的版本上报错,优先查对应版本的文档中心,比随便改代码可靠得多。

5. 一点经验与后续扩展方向

把这个项目跑通之后,我自己又沿着三条线做了扩展,每一条都刷新了对强化学习的理解。

第一条是把环境从一级倒立摆换成二级倒立摆,难度立刻上了一个台阶,DQN基本学不动了,得换PPO这类更稳的算法才能处理。第二条是研究奖励塑形对训练速度的影响,对比不同权重的奖励公式在相同训练步数下的表现差距,收获很大。第三条是关注离线强化学习的思路,把之前在线训练产生的经验数据保存下来,然后重新喂给智能体,研究数据复用对样本效率的影响,这也是当前强化学习研究里的热门方向之一。

如果你现在也跑通了倒立摆,我的建议是先别急着换模型、换算法,把奖励函数反复改几遍,每次训练都盯着那条奖励曲线看变化,搞清楚“为什么改了这个权重曲线就变平稳了”。这种体感是任何教程都替代不了的。倒立摆虽然是个入门级环境,但它把强化学习里最核心的“试错-评估-改进”逻辑完整演了一遍,把这条线吃透,后面遇到机器臂控制、运动控制、智能决策这些复杂场景,你都会有个清晰的知识坐标。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 16:16:44

2020款日产Rogue整车碰撞CAE仿真全流程实战解析

2020款Nissan Rogue的CAE模型,我前前后后折腾了差不多两个月,从拆包解压看deck结构,到网格清理、材料核对、连接定义,再到跑正面碰撞和侧碰工况,一路踩了不少坑,也积累了不少心得。这篇文章就把整车碰撞仿真…

作者头像 李华
网站建设 2026/9/9 16:13:34

基于ADMM的多微网电能交互分布式运行策略及Matlab实现

做多微网协调控制的人应该都有同感:单微网能量管理已经够琐碎,一旦扩展到多微网,麻烦直接从“一个优化问题”变成“一堆优化问题加一堆交互约束”。而这个课题里最麻烦的地方在于,每个微网都有自己的运营主体,没有人愿…

作者头像 李华
网站建设 2026/9/9 16:12:11

马尾辫全攻略:位置、脸型与细节决定气质

马尾辫大概是所有发型里最容易被低估的一个。很多人觉得它无非就是拿根皮筋把头发一绑,三秒钟完事。但同样是马尾,有人扎完精神利落显脸小,有人扎完像刚洗完头随手一抓的居家状态,区别不在颜值,而在位置、松紧、纹理这…

作者头像 李华
网站建设 2026/9/9 16:11:02

论文通关攻略|笔墨AI避坑+顶配使用全流程指南

随着高校论文审核标准持续升级,查重检测AIGC智能检测双重审核成为标配,传统粗放式写稿、改稿方式早已无法适配新规。笔墨AI作为轻量化、全免费的学术一站式辅助工具,覆盖论文从选题到答辩的全场景需求,是2026届毕业生高效通关的优…

作者头像 李华
网站建设 2026/9/9 16:10:58

Flutter调用OpenHarmony原生上下文菜单:MethodChannel桥接方案实战

1. 项目概述与立项思路1.1 这个项目到底要解决什么问题熟悉 Flutter 开发的朋友都知道,Flutter 在跨端 UI 一致性上确实做得足够好,一套 Dart 代码编译到 Android、iOS、Web、Windows、macOS、Linux,写起来相当省心。但当目标平台换成 OpenHa…

作者头像 李华