PID控制車速和自整定總結
PID控制作為傳統的控制方法,介紹很多,程式也有很多,這裡就不多做介紹。本文主要分兩部分,一部分是控制車速快速穩定,一部分是對PID自整定的一些看法。
一、控制車速快速穩定
這裡的車是指智慧小車(差速控制),不是指汽車。控制小車速度由0mm/s到100mm/s,穩定時間需要控制在200ms內。因為死區和摩擦力的原因,車輪的轉速有滯後現象。利用位置式PID不能解決問題,準確的說,用一組PID值想小車快速達到穩定是不可能的。快速性,穩定性,準確性是相互制約的,控制車速肯定希望這三個效能都滿足,因此三個效能只能相互平衡。
以下講講我的方法,我用了分段PID的方法來達到快速穩定的要求。我的分段PID不是指不同的速度對應不同的PID的值,不同於模糊PID的控制方法,我的分段是根據設定值與反饋值得偏差來進行分段控制。
1.快速區
此時的delta_v應大於20mm/s(這裡的數值可以根據專案需要去設定),PID給定值相對較大,主要是Kp比較大,其他兩個值我沒有改變。因為增加Kp還是會導致超調,在這裡我利用了2個策略。
a. 在快速區裡,把(設定值-20)作為新的設定值,然後利用反饋的速度加上瞬時加速度和新設定值比較。
b. 瞬時加速度是利用MPC控制的思想,進行提前量控制,因為車速的滯後性比較強,當前的速度為V_now,前一時刻的速度為V_last,則車速的瞬時加速度為a=V_now-V_last。
2. 緩衝區
此時的10mm/s<delta_v<20mm/s,Kp的值小了一點點。這個區段主要是針對第一階段超調引起的誤差,能較快速的穩定到設定速度,另外可以防止速度產生系統震盪;
3. 穩定區
此時的10mm/s>delta_v,Kp的值繼續減小。車速能夠達到相對穩定的狀態,就一直處在穩定區,如果想較大增速,會再進入快速區。
另外講下原地轉彎,控制角速度w的一些心得。PID控制w的效果不怎麼好,因此,先作出w與PWM的曲線,求出函式。然後根據函式,當輸入w時,進行PWM最大和最小的限幅。原地轉彎的時候比較順暢。
二、PID自整定
目前我瞭解到的自整定的方法有Z-N法和twiddle法。
1. Z-N法
維基百科上有,大家自己去看,經過證實這個方法是有效的。
https://zh.wikipedia.org/wiki/PID%E6%8E%A7%E5%88%B6%E5%99%A8
2. twiddle法(旋鈕法)
這個方法還是直接貼程式碼吧,成本函式的程式碼大家根據自己的系統去寫,我就不貼自己的程式碼了。這裡面上部分是matlab的程式碼,下半部分是Python程式碼。我是偶然看到這位大牛Sebastian Thrun的講PID控制視訊瞭解到的。覺得很有意思,根據別人的程式碼修改了下。不得不說,還是有經驗的人調的更快,但是這個方法可以給大家指明一個大致的方向,關鍵是這個思想我覺得很好。
clear all, clc, close all
%% Twiddle Algorithmus nach Sebastian Thrun
tic
params = [0 0 0]; %Startparameter kp & ki &kd
dparams = [1 1 1]; %Startschrittweite Delta_kp & Delta_ki &Delta_kd
it=1;
%成本函式計算
[cfzz(it),err(it)] = PIDcontrol(params(1),params(2),params(3),100,500);%偏差為10度
% [cfzz(it),err(it)] = PIDcontrol(1,1,1,100,500);
bestcost = cfzz(it);
% 最大化成本函式
while sum(dparams) > 0.01
for i=1:length(params) % 所有引數
params(i)=params(i)+dparams(i);
%成本函式計算
[cfzz(it),err(it)] = PIDcontrol(params(1),params(2),params(3),100,500);
if cfzz(it) < bestcost
bestcost = cfzz(it);
dparams(i)= dparams(i)*1.05;
else
% 相反方向搜尋
params(i)=params(i)- 2*dparams(i);
[cfzz(it),err(it)] = PIDcontrol(params(1),params(2),params(3),100,500);
if cfzz(it) < bestcost %如果目前的成本較高(為好)
bestcost = cfzz(it);
dparams(i) = dparams(i)*1.05; %更大的一步
else
params(i)=params(i)+dparams(i);
dparams(i)=dparams(i)*0.95; % 更小的一步
end
end
it = it+1;
disp(['Twiddle #' num2str(it-1) 'parameter ' num2str(params,'%2.5f \t') ', FunctionCost: ' num2str(cfzz(it-1),'%2.5f \t') ',Err_now: ' num2str(err(it-1),'%2.5f \t')])
paramsstore(it,:) = params; % 為支援在隨後的變數
end %parameter end
end
disp(['Twiddle-Berechnungsdauer ' num2str(toc) 's'])
disp([' X Y Z'])
disp(['Maximum bei ' num2str(params,'%2.5f \t')])
%{
%Write with Python
# Choose an initialization parameter vector
p = [0, 0, 0]
# Define potential changes
dp = [1, 1, 1]
# Calculate the error
best_err = A(p)
threshold = 0.001
while sum(dp) > threshold:
for i in range(len(p)):
p[i] += dp[i]
err = A(p)
if err < best_err: # There was some improvement
best_err = err
dp[i] *= 1.1
else: # There was no improvement
p[i] -= 2*dp[i] # Go into the other direction
err = A(p)
if err < best_err: # There was an improvement
best_err = err
dp[i] *= 1.05
else # There was no improvement
p[i] += dp[i]
# As there was no improvement, the step size in either
# direction, the step size might simply be too big.
dp[i] *= 0.95
%}