1. 程式人生 > >PID控制車速和自整定總結

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
%}