倒立擺控制)
簡介面向Quanser QUBE-Servo 2硬件平臺與MATLAB使用者的旋轉(zhuǎn)倒立擺強化學習方案包聚焦DDPG與SAC兩類算法解決真實實驗臺上的平衡控制建模、訓練和部署問題可廣泛應(yīng)用于控制類課程設(shè)計、研究生科研和機器人競賽準備等場景。壓縮包共16個文件整體大小1.74MB包含三套Simulink模型slx分別對應(yīng)仿真、硬件在環(huán)和QLabs虛擬平臺場景還包括策略參數(shù)文件mat、MATLAB腳本m、MLX交互式配置向?qū)б约癙ython輔助腳本、結(jié)果圖和授權(quán)說明等便于按模塊查閱和復用。已有32人學習。包內(nèi)提供從仿真環(huán)境到硬件在環(huán)再到QLabs虛擬平臺的三套完整模型用戶可按需切換預訓練策略文件可直接加載運行省去從頭訓練的時間SAC策略裁剪腳本用于精簡網(wǎng)絡(luò)層以適配嵌入式部署參數(shù)配置腳本和評估工具則支持快速調(diào)參與效果驗證。整套方案注重工程實用性從環(huán)境搭建到策略部署均有清晰路徑適合具備一定控制或強化學習基礎(chǔ)的高校學生、科研人員及競賽團隊快速上手。1. 項目整體思路與方案選型1.1 硬件平臺與問題定義Quanser QUBE-Servo 2 是很多高??刂茖嶒炇依锍R姷男D(zhuǎn)倒立擺平臺。相比傳統(tǒng)的一維直線倒立擺它的結(jié)構(gòu)更緊湊由直流電機驅(qū)動一個水平旋轉(zhuǎn)臂臂末端鉸接一根擺桿電機轉(zhuǎn)動時帶動擺桿在豎直平面內(nèi)運動。控制目標非常直接讓擺桿從自然下垂位置被甩起來并在豎直向上的倒立位置穩(wěn)定住同時讓旋轉(zhuǎn)臂保持在某個參考角度附近。這個系統(tǒng)最大的特點是“看著簡單控制起來不簡單”。電機軸角度、擺桿角度、對應(yīng)的角速度這四個狀態(tài)變量構(gòu)成了一個典型的欠驅(qū)動非線性系統(tǒng)——你只有電機一個輸入?yún)s要同時管住兩個旋轉(zhuǎn)自由度。而且系統(tǒng)還帶有電機摩擦、擺桿阻尼、信號量化誤差等一大堆“不干凈”的因素。用經(jīng)典控制方法做倒立擺LQR、極點配置、PID這些方法都能跑但都有一個共性前提你必須先建立一個相對精確的數(shù)學模型然后再基于模型去設(shè)計控制器。這次實現(xiàn)包換了一條路直接用強化學習來做。核心思路是不給控制器顯式的數(shù)學模型而是把“維持平衡”這件事變成一個試錯學習任務(wù)讓智能體在仿真環(huán)境中不斷嘗試控制策略通過獎勵信號學會“什么樣的電壓輸出能讓擺桿穩(wěn)在豎直位置”。這個思路本身不新但在MATLAB的強化學習工具箱環(huán)境下能不能順利跑通、能不能從仿真遷移到實物才是真正值得寫一講的經(jīng)驗。1.2 為什么選擇強化學習線路做控制的人第一個反應(yīng)通常是倒立擺這種教科書級系統(tǒng)LQR就夠用了為什么還要上強化學習我的看法是兩者解決的不是同一個問題。LQR要求系統(tǒng)模型已知或者能被線性化QUBE-Servo 2在教學場景下沒問題但如果你把擺桿換成柔性結(jié)構(gòu)、給系統(tǒng)加上未知負載、或者讓擺桿參數(shù)發(fā)生漂移LQR的重整定成本會非常高。強化學習的思路是把控制器變成一個“策略網(wǎng)絡(luò)”它的輸入是傳感器觀測輸出是控制指令中間這一大坨非線性映射完全靠數(shù)據(jù)去逼近——不需要精確模型只要仿真環(huán)境足夠接近實物策略就能學到。當然強化學習也有自己的代價訓練時間、超參數(shù)調(diào)優(yōu)、獎勵函數(shù)設(shè)計每一個環(huán)節(jié)都能讓人反復折騰。這個項目選擇MATLAB而不是Python主要原因有三個。第一QUBE-Servo 2官方提供了完整的Simulink模型和QUARC實時控制接口MATLAB里可以直接用帶硬件支持的Simulink模型跑強化學習環(huán)境不需要像Python那樣自己寫底層通信。第二Reinforcement Learning Toolbox提供了現(xiàn)成的DDPG、TD3、SAC、PPO等算法實現(xiàn)不用自己從零寫Actor-Critic網(wǎng)絡(luò)。第三從仿真到實物部署時MATLAB生成的代碼可以直接部署到Speedgoat或兼容實時目標機遷移鏈路很完整。1.3 算法選型的對比與取舍QUBE-Servo 2的控制動作是電機電壓或者電流指令這是一個連續(xù)動作空間問題??蛇x的主流算法有DDPG、TD3、SAC、PPO。我在這套實現(xiàn)包里主要用TD3和SAC做了對比簡單說一下結(jié)論。算法動作噪聲處理樣本效率調(diào)參難度實物部署友好度DDPG簡單高斯噪聲中等較高容易發(fā)散較好TD3目標策略平滑較高中等較好SAC熵正則化探索高中等中等PPO重要性采樣裁剪低較低好但樣本效率差最終選TD3作為默認方案原因很實際QUBE-Servo 2的擺桿在仿真環(huán)境里可以被精確建模樣本效率高的算法能更快收斂而在實物遷移時TD3只有一個確定性策略網(wǎng)絡(luò)部署邏輯更簡單不會像SAC那樣因為隨機策略在實物上產(chǎn)生不必要的抖動。如果你只想快速看效果DDPG也能跑通但收斂穩(wěn)定性確實差一個檔次。2. 環(huán)境搭建與狀態(tài)動作設(shè)計2.1 MATLAB/Simulink環(huán)境配置這個項目依賴的軟件環(huán)境有三塊MATLAB本體建議R2022b及以上舊版本在強化學習工具箱的接口上有差異、Simulink、Reinforcement Learning Toolbox以及QUARCQuanser的實時控制工具包實物實驗需要。如果只做仿真不碰實物QUARC可以不裝但需要用QUBE-Servo 2官方提供的Simscape模型替代。第一件要做的事是獲取QUBE-Servo 2的Simulink模型文件。Quanser官網(wǎng)的學習資源庫里提供了“QUBE-Servo 2 Modeling and Control”系列文件里面有完整的非線性模型和線性化模型。拿到模型后先跑一遍開環(huán)仿真確認擺桿從垂直下垂位置開始的響應(yīng)曲線正常。這一步很多人跳過直接進強化學習結(jié)果訓練半天發(fā)現(xiàn)環(huán)境里角度信號本身就有問題白費時間。用強化學習工具箱的rlSimulinkEnv函數(shù)把Simulink模型包裝成強化學習環(huán)境時需要明確三個接口觀測信號從哪取、動作信號從哪進、終止條件怎么判定。我習慣的做法是把觀測信號通過一個Bus Selector匯總到一個向量端口動作端口直接連到電機的電壓輸入。終止條件的設(shè)置比較關(guān)鍵不能把“擺桿掉落”直接作為終止否則智能體會學到“快速傾倒”這種規(guī)避行為而是要設(shè)計一個平衡區(qū)域出區(qū)域才算失敗。2.2 狀態(tài)空間與觀測變量設(shè)計QUBE-Servo 2 有四個核心狀態(tài)電機軸角度、電機軸角速度、擺桿角度、擺桿角速度。但直接把這四個原始量喂給強化學習智能體效果往往不太理想原因是角度單位弧度和角速度數(shù)值范圍差了一個數(shù)量級網(wǎng)絡(luò)訓練時梯度容易不穩(wěn)定。我在實現(xiàn)包里做了一組觀測變換把觀測向量設(shè)計為obs [theta_motor * scale_angle, theta_pend * scale_angle, omega_motor * scale_angular_velocity, omega_pend * scale_angular_velocity, sin(theta_pend), cos(theta_pend)]加sin和cos分量是強化學習倒立擺任務(wù)里一個非常實用的技巧。擺桿角度在豎直向上附近時角度值本身在0附近擺動但如果擺桿翻轉(zhuǎn)一圈角度會發(fā)生跳躍直接用原始角度會讓網(wǎng)絡(luò)很難理解“角度是循環(huán)的”這一事實。而正弦余弦永遠連續(xù)相當于給了網(wǎng)絡(luò)一個“角度位置在哪”的穩(wěn)定編碼。有一個容易踩的坑電機軸角度是否要加入觀測取決于控制目標。如果只要求擺桿倒立穩(wěn)定電機軸角度可以不進觀測但如果你希望旋轉(zhuǎn)臂同時鎖定在某個固定角度比如0度那這個狀態(tài)必須進觀測否則智能體沒法學到“回中”行為。這個實現(xiàn)包的目標是“擺動起擺穩(wěn)定平衡電機軸回中”所以觀測里包含了電機角度。2.3 動作空間與執(zhí)行器限制動作空間的設(shè)置直接跟物理設(shè)備綁定。QUBE-Servo 2的電機標稱電壓范圍是±6V峰值可能到±10V但長時間跑建議限制在±6V以內(nèi)電機線圈會過熱。在強化學習環(huán)境里動作量需要歸一化處理——網(wǎng)絡(luò)輸出一個范圍在[-1, 1]的信號然后通過一個Saturation模塊映射到實際電壓。這里有一個我做第一版時犯過的錯直接用網(wǎng)絡(luò)輸出作為電壓指令沒有做平滑處理。強化學習策略網(wǎng)絡(luò)產(chǎn)生的動作會有高頻抖動前期探索階段尤其嚴重。這種抖動的電壓信號直接作用在直流電機上會導致電流尖峰還可能讓電機的編碼器讀到被噪聲污染的角速度信號。后來我在動作輸出路徑上加了一階低通濾波時間常數(shù)選在0.02秒左右抖動問題明顯改善。另外要注意如果仿真模型里電機飽和特性沒有建模訓練出來的策略很可能會學到“加大電壓到極限值”的暴力策略在實物上直接觸發(fā)電流保護。所以環(huán)境模型里必須包含飽和模塊最好還加上電流限制邏輯讓強化學習從一開始就知道“動作是有代價的”。2.4 獎勵函數(shù)設(shè)計從稀疏到密集獎勵函數(shù)是強化學習項目里最考驗“手工設(shè)計能力”的地方。網(wǎng)上一搜“強化學習遇到錯誤獎勵”能找到大量討論——獎勵函數(shù)沒寫好智能體訓練不收斂是小事更糟的是模型“自以為是”地學到了完成任務(wù)但行為完全錯誤的對策。倒立擺任務(wù)最樸素的獎勵函數(shù)是位置誤差加權(quán)R -(theta_pend^2 0.1 * omega_pend^2 0.05 * theta_motor^2 0.01 * omega_motor^2)這個設(shè)計思路直接來源于LQR的代價函數(shù)——把狀態(tài)量的二次型加權(quán)和作為負獎勵。這樣做的好處是每個時刻都有反饋獎勵是密集的智能體不會陷入真空探索期。但問題也隨之而來如果四個狀態(tài)量的權(quán)重分配不合理智能體會發(fā)現(xiàn)“犧牲擺桿角度來減小電機角度誤差”很劃算學成一個偏心也不平衡的控制器。我建議的做法是開始訓練時先把電機回中的權(quán)重拉低讓智能體優(yōu)先學會“把擺桿立起來”等擺桿穩(wěn)定后再把回中權(quán)重逐步提高。這種課程式的獎勵調(diào)度curriculum reward shaping實現(xiàn)起來并不復雜——在Simulink里加一個隨時間變化的權(quán)重模塊或者在MATLAB腳本里分段更新獎勵函數(shù)參數(shù)都可以。3. 訓練實現(xiàn)與核心環(huán)節(jié)3.1 Actor-Critic網(wǎng)絡(luò)結(jié)構(gòu)與初始化Reinforcement Learning Toolbox里創(chuàng)建TD3智能體時網(wǎng)絡(luò)結(jié)構(gòu)通過createTD3Agent或rlTD3Agent指定。我最終跑通的網(wǎng)絡(luò)結(jié)構(gòu)如下% 觀測維度64個狀態(tài) sin/cos obsDim 6; actDim 1; % Actor網(wǎng)絡(luò)兩層隱藏層每層256個神經(jīng)元 actorNetwork [ featureInputLayer(obsDim, Normalization, none, Name, obs) fullyConnectedLayer(256, Name, fc1) reluLayer(Name, relu1) fullyConnectedLayer(256, Name, fc2) reluLayer(Name, relu2) fullyConnectedLayer(actDim, Name, action) tanhLayer(Name, tanh) ]; % Critic網(wǎng)絡(luò)輸入包含觀測和動作 criticNetwork [ featureInputLayer(obsDim, Normalization, none, Name, obs) fullyConnectedLayer(256, Name, fc1) reluLayer(Name, relu1) fullyConnectedLayer(256, Name, fc2) reluLayer(Name, relu2) fullyConnectedLayer(1, Name, qvalue) ];Actorn網(wǎng)絡(luò)最后一層接tanh輸出范圍自動限制在[-1, 1]正好和前面說的歸一化動作空間匹配省去了額外裁剪。兩層256個神經(jīng)元的規(guī)模對于這類低維控制問題來說已經(jīng)足夠再大反而容易過擬合仿真環(huán)境里的特殊噪聲。有個小細節(jié)Critic網(wǎng)絡(luò)的標準做法是把動作和觀測拼接后一起輸入網(wǎng)絡(luò)但TensorFlow和MATLAB的實現(xiàn)細節(jié)略有不同。MATLAB的rlQValueFunction支持同時接收觀測和動作輸入所以Critic網(wǎng)絡(luò)里觀測和動作是分開兩個輸入分支的。我一開始按PyTorch的習慣把動作拼到觀測里作為特征輸入結(jié)果訓練速度明顯變慢且不穩(wěn)定——雖然理論上可行但工具箱對分叉輸入的處理做了優(yōu)化順著官方文檔來更穩(wěn)。3.2 訓練超參數(shù)與收斂判斷TD3算法在MATLAB工具箱里的關(guān)鍵超參數(shù)如下這是我調(diào)了很多輪之后穩(wěn)定下來的配置參數(shù)數(shù)值說明采樣時間Ts0.005s200Hz控制頻率QUBE-Servo 2支持折扣因子0.99標準設(shè)置兼顧短期和長期獎勵經(jīng)驗池容量200000足夠容納多次完整訓練回合最小批量256太大訓練慢太小不穩(wěn)定Actor噪聲0.1訓練時動作探索噪聲標準差目標噪聲0.2目標策略平滑噪聲噪聲裁剪范圍[-0.5, 0.5]防止目標動作偏移過大學習率3e-4Actor/Critic統(tǒng)一軟更新系數(shù)τ0.005目標網(wǎng)絡(luò)更新平滑程度訓練循環(huán)我一般設(shè)2000個回合每個回合設(shè)2000步10秒仿真時長。QUBE-Servo 2的實物起擺過程一般不超過3秒所以10秒的回合長度足夠包含完整的“起擺-穩(wěn)定”過程。一個值得注意的細節(jié)是Simulink環(huán)境里的強化學習訓練速度很受采樣時間和仿真步長的影響。如果把仿真步長設(shè)成固定步長0.005秒2000回合需要跑很長時間。我的做法是在訓練階段用一個稍大的控制周期比如0.01秒快速驗證算法邏輯等確認策略能收斂了再把采樣時間改回0.005秒做精細訓練。這樣前期迭代效率高后期精度也夠。如何判斷訓練真正收斂而不是假收斂我總結(jié)了三個信號第一訓練曲線里的平均獎勵值連續(xù)100回合不再上升第二在固定初始狀態(tài)下策略能穩(wěn)定完成“起擺平衡”的完整流程第三把訓練好的策略放到一個“沒訓練過的初始擺角”下測試仍然能恢復平衡——這個泛化性測試比獎勵曲線更可靠。3.3 仿真驗證與評估指標訓練完成后先把Agent導出% 保存訓練好的智能體 save(trainedAgent.mat, agent); % 在仿真環(huán)境中評估 evalOpts rlEvaluationOptions(NumEpisodes, 10, ... MaxSteps, 2000, ... UseParallel, false); results evaluate(agent, env, evalOpts);評估時的觀察重點不是獎勵值本身而是時域響應(yīng)曲線。我會畫三張圖電機角度隨時間變化、擺桿角度隨時間變化、電壓輸出隨時間變化。如果擺桿角度能穩(wěn)定在±5度以內(nèi)電壓噪聲不明顯說明策略質(zhì)量可以接受。不過仿真能過線不意味著實物就沒問題。QUBE-Servo 2的Simulink模型忽略了很多高頻動力學特性比如電刷換向的轉(zhuǎn)矩脈動、編碼器量化誤差、電壓源的內(nèi)阻壓降。仿真里的策略拿到實物上一開始大概率會出現(xiàn)“小幅抖動但能立住”的現(xiàn)象這只是運氣好。真正的考驗是模型不確定性比如擺桿重心不完全在模型標稱位置、摩擦力矩方向隨機變化等。我強烈建議做一輪域隨機化domain randomization——在仿真模型的參數(shù)里加入±10%的隨機擾動比如擺桿慣性矩、阻尼系數(shù)、電機力矩常數(shù)讓策略見到更多樣的環(huán)境。這樣再遷移到實物成功率會顯著提升。4. 常見問題與排查技巧實錄4.1 訓練發(fā)散最常見的“獎勵黑客”問題我在早期版本里遇到過一次特別典型的發(fā)散問題訓練到200多回合時獎勵突然從-50跳到-3000智能體開始“原地瘋狂翻轉(zhuǎn)擺桿”。排查后發(fā)現(xiàn)問題出在終止條件的設(shè)置上。我把終止條件設(shè)置成了“擺桿角度超過60度即終止”但在擺動起擺階段擺桿角度在某個瞬間會超過60度這時回合被強制終止智能體獲得的獎勵不僅低還會把這種“早死”與狀態(tài)關(guān)聯(lián)起來。最終學到的策略變成了快速晃動機電臂讓擺桿獲得一個很大的初速度甩過去。解決方法是把終止條件改成“擺桿角度在平衡位置附近保持超過10秒才終止”其余情況都不終止只是給出負獎勵。這就逼著智能體必須在完整回合內(nèi)學會“起擺-穩(wěn)定”的串聯(lián)動作而不是投機取巧。這個改法看似簡單但直接決定了訓練能不能收斂。4.2 獎勵函數(shù)設(shè)計錯誤局部最優(yōu)陷阱另一個常見的坑是獎勵函數(shù)里的權(quán)重失衡。我試過一版把電機回中權(quán)重設(shè)得特別高的獎勵函數(shù)結(jié)果智能體學成了“寧可讓擺桿倒下也要讓電機歸零”的詭異行為——它在電機回中后立刻放棄穩(wěn)定擺桿導致擺桿反復倒下又立起。根本原因是回中獎勵在每一時刻都成了主導項智能體發(fā)現(xiàn)先回正電機“占便宜”更大。這個問題的排查思路是分別單獨評估獎勵函數(shù)里每一項的數(shù)值量級。用MATLAB的step函數(shù)手動跑幾個回合把每一步的各個獎勵分量都記錄下來算平均值看看哪個分量占據(jù)了總獎勵的90%以上。如果某個分量完全主導說明其他目標的信號被淹沒了需要調(diào)整權(quán)重。我最后用的權(quán)重比例是擺桿角度:電機角度:角速度 10:1:1這樣既保障了擺桿平衡這個最核心的目標又不會讓次要目標喧賓奪主。4.3 仿真到實物的遷移失敗這是這個項目里最讓人頭疼的一環(huán)。即使仿真里跑得再漂亮實物上一旦出現(xiàn)以下現(xiàn)象基本可以斷定是遷移問題擺桿在高頻抖動但電機軸溫度飆升策略在起擺階段過于激進觸發(fā)電流保護擺桿穩(wěn)定后持續(xù)有低頻振蕩無法收斂最有效的手段是在仿真環(huán)境里加“不確定性注入”。具體操作很簡單用rng種子在每次回合開始時隨機初始化擺桿長度、慣量、電機力矩常數(shù)讓策略學到的是一個魯棒控制策略而不是某個精確模型的“記憶”。另一個實操技巧是在實物部署前給動作輸出加一個限制變化率模塊。仿真里的電機模型允許電壓瞬變但實物的電源和電機驅(qū)動有自己的爬坡率限制過快的電壓變化會引入噪聲和機械沖擊。把變化率限制在每步0.5V以內(nèi)可以顯著減少抖動。4.4 MATLAB軟件版本的兼容性最后提一個容易被忽視的問題MATLAB版本。Reinforcement Learning Toolbox在R2021a、R2022b、R2023b之間有一些接口變化比如rlTD3Agent的參數(shù)傳遞方式、rlSimulinkEnv的終止條件函數(shù)格式等。如果你的Simulink模型是用舊版本建的新版本打開后可能會出現(xiàn)“int等類型不匹配”的錯誤。我的建ed建議是項目開始前就確定一個MATLAB版本整個開發(fā)過程不隨意升級。如果確實需要在新版本里打開舊模型先用upgradeadvisor檢查模型兼容性。另外QUARC工具包和MATLAB版本的對應(yīng)關(guān)系非常嚴格裝錯版本會導致Simulink實時模塊無法啟動這類問題通常不是代碼問題純粹是環(huán)境匹配問題查兼容性矩陣比改代碼更快。5. 個人的實操體會這個項目做了幾輪迭代我最大的感受是強化學習控制倒立擺難點不在算法本身而在“環(huán)境建模的忠實度”和“獎勵函數(shù)設(shè)計的意圖對齊”這兩件事上。算法參數(shù)調(diào)來調(diào)去最后發(fā)現(xiàn)影響最大的還是Simulink模型里電機飽和模塊的參數(shù)和獎勵函數(shù)權(quán)重的比例。如果你正準備在自己的設(shè)備上復現(xiàn)這個實現(xiàn)包我的建議是第一次訓練一定要用保守的獎勵函數(shù)先跑通完整鏈路再去優(yōu)化穩(wěn)態(tài)性能。不要一上來就追求“又快又穩(wěn)又省電”那會讓訓練過程充滿挫敗感。還有一個小技巧是訓練過程中保持Simulink的仿真加速模式用set_param把仿真模式設(shè)為accelerator能讓訓練時間縮短到原來的三分之一左右這在反復調(diào)參階段能省下大量時間。最后再分享一個細節(jié)保存模型參數(shù)時除了保存Agent對象記得把訓練曲線數(shù)據(jù)、超參數(shù)配置、獎勵函數(shù)版本都一起存下來。訓練配置分散在多個文件里幾天后你一定會忘記當時跑的版本是“加了低通濾波”還是“改了終止條件”的。這個習慣讓我少走了很多彎路。本文還有配套的精品資源點擊獲取