0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

什么是嵌入式PID算法?嵌入式PID算法分析

嵌入式開(kāi)發(fā)愛(ài)好者 ? 來(lái)源:嵌入式開(kāi)發(fā)愛(ài)好者 ? 2023-11-06 09:24 ? 次閱讀

1.1 概述

比例(Proportion)積分(Integral)微分(Differential)控制器PID控制器或三項(xiàng)控制器)是一種采用反饋的控制回路機(jī)制,廣泛應(yīng)用于工業(yè)控制系統(tǒng)和需要連續(xù)調(diào)制控制的各種其他應(yīng)用。

PID控制器連續(xù)計(jì)算誤差值 e(t) 作為所需設(shè)定點(diǎn)(SP) 和測(cè)量過(guò)程變量(PV)之間的差值,并應(yīng)用基于比例、積分和導(dǎo)數(shù)項(xiàng)(分別表示為P、I和D)的校正,因此得名。

34dc96ce-7bf5-11ee-939d-92fbcf53809c.png

34e62874-7bf5-11ee-939d-92fbcf53809c.png

r(t) 是期望的過(guò)程值或設(shè)定點(diǎn)(SP),y(t) 是測(cè)量的過(guò)程值(PV)。

1.2 歷史發(fā)展

1911年,第一個(gè)PID控制器是由Elmer Sperry開(kāi)發(fā)的。

1922 年,俄裔美國(guó)工程師尼古拉斯·米諾斯基 ( Nicolas Minorsky)才首次利用理論分析制定了我們現(xiàn)在所說(shuō)的 PID 或三項(xiàng)控制的正式控制律。米諾斯基當(dāng)時(shí)正在為美國(guó)海軍研究和設(shè)計(jì)自動(dòng)船舶轉(zhuǎn)向系統(tǒng),他的分析基于對(duì)舵手的觀察。

他指出,舵手不僅根據(jù)當(dāng)前航向誤差,還根據(jù)過(guò)去的誤差以及當(dāng)前的變化率來(lái)駕駛船舶;然后 Minorsky 對(duì)此進(jìn)行了數(shù)學(xué)處理。他的目標(biāo)是穩(wěn)定,而不是一般控制,這大大簡(jiǎn)化了問(wèn)題。

1933年,TIC(泰勒儀器公司)實(shí)現(xiàn)了完全可調(diào)節(jié)的前氣動(dòng)控制器。幾年后,控制工程師通過(guò)將末端返回到一些假值,直到誤差不為零,消除了比例控制器中發(fā)現(xiàn)的穩(wěn)態(tài)誤差。這個(gè)返回包含了誤差,這被稱(chēng)為比例積分控制器。

1940年,第一個(gè)氣動(dòng)PID控制器通過(guò)導(dǎo)數(shù)動(dòng)作開(kāi)發(fā),以減少超調(diào)問(wèn)題。

1942年,Ziegler & Nichols引入了調(diào)諧規(guī)則,由工程師發(fā)現(xiàn)和設(shè)置PID控制器的合適參數(shù)。

20世紀(jì)50年代中期,自動(dòng)PID控制器在工業(yè)上得到了廣泛的應(yīng)用。工業(yè)中大多數(shù)現(xiàn)代 PID 控制都是作為DCS、PLC單片機(jī)程序來(lái)實(shí)現(xiàn)的。

1.3 應(yīng)用

?火箭的姿態(tài)控制

?無(wú)人機(jī)懸??刂频?/p>

?相機(jī)穩(wěn)定器、相機(jī)云臺(tái)

?平衡小車(chē)

?汽車(chē)的定速巡航控制、轉(zhuǎn)向控制

?發(fā)動(dòng)機(jī)轉(zhuǎn)速控制

?3D打印機(jī)上的溫度控制器

?工業(yè)自動(dòng)化領(lǐng)域,大約95%的閉環(huán)操作使用PID控制器。

1.4 與 ON/OFF 型控制器對(duì)比

像PID控制器這樣的閉環(huán)系統(tǒng)包括一個(gè)反饋控制系統(tǒng)。該系統(tǒng)利用一個(gè)固定點(diǎn)對(duì)反饋?zhàn)兞窟M(jìn)行評(píng)估,從而產(chǎn)生誤差信號(hào)。在此基礎(chǔ)上,它改變系統(tǒng)輸出。這個(gè)過(guò)程將繼續(xù),直到誤差達(dá)到零,否則反饋?zhàn)兞康闹稻偷扔谝粋€(gè)固定點(diǎn)。

與ON/OFF型控制器相比,該控制器提供了良好的效果。在開(kāi)/關(guān)型控制器中,只需兩個(gè)條件即可管理系統(tǒng)。大多數(shù)暖通空調(diào)系統(tǒng)、冰箱都采用這種方法。

例如,在冰箱中,它會(huì)冷卻內(nèi)部直到達(dá)到所需溫度,然后關(guān)閉冷卻器,直到達(dá)到高于所需溫度的設(shè)定值。一旦工藝值低于固定點(diǎn),則開(kāi)啟。

類(lèi)似地,一旦該值高于固定值,它將關(guān)閉。這種控制器的輸出不穩(wěn)定,在不動(dòng)點(diǎn)的區(qū)域內(nèi)振蕩頻繁。然而,與ON/OFF型控制器相比,PID 控制器更加穩(wěn)定和準(zhǔn)確。

34f4492c-7bf5-11ee-939d-92fbcf53809c.png

1.6 響應(yīng)類(lèi)型

由PID控制器驅(qū)動(dòng)的系統(tǒng)通常具有三種類(lèi)型的響應(yīng):欠阻尼、過(guò)阻尼和臨界阻尼。

35010a5e-7bf5-11ee-939d-92fbcf53809c.png

3505b04a-7bf5-11ee-939d-92fbcf53809c.gif

?欠阻尼響應(yīng)在穩(wěn)定之前圍繞參考值振蕩。

?過(guò)阻尼響應(yīng)上升緩慢并且不會(huì)超過(guò)參考值。

?臨界阻尼響應(yīng)具有最快的上升時(shí)間,且不會(huì)超過(guò)參考值。

公式

2.1 PID 系統(tǒng)定義與公式

35098cd8-7bf5-11ee-939d-92fbcf53809c.png

r(t) setpoint, reference,是期望的過(guò)程值或設(shè)定值(SP);

y(t) output, process variable,是測(cè)量的過(guò)程值,輸出值(PV);

e(t) error,是偏差;

u(t) control effort,是控制量;

PID控制器的顯著特點(diǎn)是能夠利用比例、積分和微分這三個(gè)控制項(xiàng)對(duì)控制器輸出的影響來(lái)進(jìn)行精確和最優(yōu)的控制。

PID 控制器,不斷計(jì)算誤差值e(t) 作為所需設(shè)定點(diǎn)之間的差異SP=r(t) 和測(cè)量的過(guò)程變量PV=y(t):e(t)=r(t)?y(t) ,并應(yīng)用基于比例、積分和導(dǎo)數(shù)項(xiàng)的修正。

控制器嘗試通過(guò)調(diào)整控制變量來(lái)最小化隨時(shí)間變化的誤差u(t)。manipulated variable (MV)。

351e9b14-7bf5-11ee-939d-92fbcf53809c.png

3531bd0c-7bf5-11ee-939d-92fbcf53809c.png

3540ddfa-7bf5-11ee-939d-92fbcf53809c.png

2.2 PID 數(shù)字公式

由于計(jì)算機(jī)控制是一種采樣控制,它只能根據(jù)采樣時(shí)刻的偏差計(jì)算控制量,而不能像模擬控制那樣連續(xù)輸出控制量,進(jìn)行連續(xù)控制。由于這一特點(diǎn),(式 1-1)中的積分項(xiàng)和微分項(xiàng)不能直接使用,必須進(jìn)行離散化處理。

離散化處理的方法為:以τ作為采樣周期,k作為采樣序號(hào),則離散采樣時(shí)間kτ對(duì)應(yīng)著連續(xù)時(shí)間t,用矩形法數(shù)值積分近似代替積分,用一階后向差分近似代替微分,可作如下近似變換:

354e672c-7bf5-11ee-939d-92fbcf53809c.png

2.3 位置式 PID 算法

將(式 2-1)代入(式 1-1),就可以得到離散的 PID 表達(dá)式為

3555cae4-7bf5-11ee-939d-92fbcf53809c.png

將(式 2-1)代入(式 1-2),就可以得到離散的PID 表達(dá)式為

3559f6a0-7bf5-11ee-939d-92fbcf53809c.png

積分系數(shù)、微分系數(shù)做如下替換:

注意:必須使τ為定值,或者變化小到可以忽略,這樣P、I、D才是固定常數(shù),才可能調(diào)節(jié)

35618780-7bf5-11ee-939d-92fbcf53809c.png357065de-7bf5-11ee-939d-92fbcf53809c.png

2.4 增量式 PID 算法

357d1d74-7bf5-11ee-939d-92fbcf53809c.png

增量式 PID 控制算法可以通過(guò)(式 2-2)推導(dǎo)出。由(式 2-2)可以得到控制器的第 k-1 個(gè)采樣時(shí)刻的輸出值為:

35901f5a-7bf5-11ee-939d-92fbcf53809c.png

由(式 2-3)可以得到控制器的第 k-1 個(gè)采樣時(shí)刻的輸出值為:

359a381e-7bf5-11ee-939d-92fbcf53809c.png

用(式 2-3)減去(式 2-7)相減并整理,就可以得到增量式 PID 控制算法公式:

35a18e34-7bf5-11ee-939d-92fbcf53809c.png

由(式 2-8)可以看出,如果計(jì)算機(jī)控制系統(tǒng)采用恒定的采樣周期τ,一旦確定 A、 B、 C,只要使用前后三次測(cè)量的偏差值,就可以由(式 2-8)求出控制量。

增量式 PID 控制算法與位置式 PID 算法(式 2-3)相比,只需要保持當(dāng)前時(shí)刻以前三個(gè)時(shí)刻的偏差值即可,累計(jì)誤差較小,計(jì)算量小的多,因此在實(shí)際中得到廣泛的應(yīng)用。

而位置式 PID 控制算法也可以通過(guò)增量式控制算法推出遞推計(jì)算公式:

35a5b5c2-7bf5-11ee-939d-92fbcf53809c.png

(式 2-9)就是目前在計(jì)算機(jī)控制中廣泛應(yīng)用的數(shù)字遞推 PID 控制算法。

調(diào)試技巧

35b0c1ce-7bf5-11ee-939d-92fbcf53809c.gif

代碼實(shí)現(xiàn)

python

import numpy as np
import matplotlib.pyplot as plt


class PositionPID(object):
  """位置式PID算法實(shí)現(xiàn)"""


  def __init__(self, target, cur_val, dt, max, min, p, i, d) -> None:
    self.dt = dt # 循環(huán)時(shí)間間隔
    self._max = max # 最大輸出限制,規(guī)避過(guò)沖
    self._min = min # 最小輸出限制
    self.k_p = p # 比例系數(shù)
    self.k_i = i # 積分系數(shù)
    self.k_d = d # 微分系數(shù)


    self.target = target # 目標(biāo)值
    self.cur_val = cur_val # 算法當(dāng)前PID位置值,第一次為設(shè)定的初始位置
    self._pre_error = 0 # t-1 時(shí)刻誤差值
    self._integral = 0 # 誤差積分值




  def calculate(self):
    """
    計(jì)算t時(shí)刻PID輸出值cur_val
    """
    error = self.target - self.cur_val # 計(jì)算當(dāng)前誤差
    # 比例項(xiàng)
    p_out = self.k_p * error 
    # 積分項(xiàng)
    self._integral += (error * self.dt)
    i_out = self.k_i * self._integral
    # 微分項(xiàng)
    derivative = (error - self._pre_error) / self.dt
    d_out = self.k_d * derivative


    # t 時(shí)刻pid輸出
    output = p_out + i_out + d_out


    # 限制輸出值
    if output > self._max:
      output = self._max
    elif output < self._min:
 ? ? ? ? ? ?output = self._min
 ? ? ? ?
 ? ? ? ?self._pre_error = error
 ? ? ? ?self.cur_val = output
 ? ? ? ?return self.cur_val


 ? ?def fit_and_plot(self, count = 200):
 ? ? ? ?"""
 ? ? ? ?使用PID擬合setPoint
 ? ? ? ?"""
 ? ? ? ?counts = np.arange(count)
 ? ? ? ?outputs = []


 ? ? ? ?for i in counts:
 ? ? ? ? ? ?outputs.append(self.calculate())
 ? ? ? ? ? ?print('Count %3d: output: %f' % (i, outputs[-1]))


 ? ? ? ?print('Done')
 ? ? ? ?# print(outputs)
 ? ? ? ?
 ? ? ? ?plt.figure()
 ? ? ? ?plt.axhline(self.target, c='red')
 ? ? ? ?plt.plot(counts, np.array(outputs), 'b.')
 ? ? ? ?plt.ylim(min(outputs) - 0.1 * min(outputs), max(outputs) + 0.1 * max(outputs))
 ? ? ? ?plt.plot(outputs)
 ? ? ? ?plt.show()


pid = PositionPID(10, -5, 0.5, 100, -100, 0.2, 0.1, 0.01)
pid.fit_and_plot(150)

35d00c96-7bf5-11ee-939d-92fbcf53809c.png

c/c++

//首先定義PID結(jié)構(gòu)體用于存放一個(gè)PID的數(shù)據(jù)
typedef struct
{
   float kp,ki,kd;//三個(gè)系數(shù)
  float error,lastError;//誤差、上次誤差
  float integral,maxIntegral;//積分、積分限幅
  float output,maxOutput;//輸出、輸出限幅
}PID;
 
//用于初始化pid參數(shù)的函數(shù)
void PID_Init(PID *pid,float p,float i,float d,float maxI,float maxOut)
{
  pid->kp=p;
  pid->ki=i;
  pid->kd=d;
  pid->maxIntegral=maxI;
  pid->maxOutput=maxOut;
}
 
//進(jìn)行一次pid計(jì)算
//參數(shù)為(pid結(jié)構(gòu)體,目標(biāo)值,反饋值),計(jì)算結(jié)果放在pid結(jié)構(gòu)體的output成員中
void PID_Calc(PID *pid,float reference,float feedback)
{
  //更新數(shù)據(jù)
  pid->lastError=pid->error;//將舊error存起來(lái)
  pid->error=reference-feedback;//計(jì)算新error
  //計(jì)算微分
  float dout=(pid->error-pid->lastError)*pid->kd;
  //計(jì)算比例
  float pout=pid->error*pid->kp;
  //計(jì)算積分
  pid->integral+=pid->error*pid->ki;
  //積分限幅
  if(pid->integral > pid->maxIntegral) pid->integral=pid->maxIntegral;
  else if(pid->integral < -pid->maxIntegral) pid->integral=-pid->maxIntegral;
  //計(jì)算輸出
  pid->output=pout+dout+pid->integral;
  //輸出限幅
  if(pid->output > pid->maxOutput) pid->output=pid->maxOutput;
  else if(pid->output < -pid->maxOutput) pid->output=-pid->maxOutput;
}
 
PID mypid;//創(chuàng)建一個(gè)PID結(jié)構(gòu)體變量
 
int main()
{
  //...這里有些其他初始化代碼
  PID_Init(&mypid,10,1,5,800,1000);//初始化PID參數(shù)
  while(1)//進(jìn)入循環(huán)運(yùn)行
  {
    float feedbackValue=...;//這里獲取到被控對(duì)象的反饋值
    float targetValue=...;//這里獲取到目標(biāo)值
    PID_Calc(&mypid,targetValue,feedbackValue);//進(jìn)行PID計(jì)算,結(jié)果在output成員變量中
    設(shè)定執(zhí)行器輸出大小(mypid.output);
    delay(10);//等待一定時(shí)間再開(kāi)始下一次循環(huán)
  }
}

單環(huán)效果

35df68f8-7bf5-11ee-939d-92fbcf53809c.gif

35fd9314-7bf5-11ee-939d-92fbcf53809c.png

串級(jí)PID的C語(yǔ)言代碼

//此處需要插入上面的單級(jí)PID相關(guān)代碼
 
//串級(jí)PID的結(jié)構(gòu)體,包含兩個(gè)單級(jí)PID
typedef struct
{
  PID inner;//內(nèi)環(huán)
  PID outer;//外環(huán)
  float output;//串級(jí)輸出,等于inner.output
}CascadePID;
 
//串級(jí)PID的計(jì)算函數(shù)
//參數(shù)(PID結(jié)構(gòu)體,外環(huán)目標(biāo)值,外環(huán)反饋值,內(nèi)環(huán)反饋值)
void PID_CascadeCalc(CascadePID *pid,float outerRef,float outerFdb,float innerFdb)
{
  PID_Calc(&pid->outer,outerRef,outerFdb);//計(jì)算外環(huán)
  PID_Calc(&pid->inner,pid->outer.output,innerFdb);//計(jì)算內(nèi)環(huán)
  pid->output=pid->inner.output;//內(nèi)環(huán)輸出就是串級(jí)PID的輸出
}
 
CascadePID mypid;//創(chuàng)建串級(jí)PID結(jié)構(gòu)體變量
 
int main()
{
  //...其他初始化代碼
  PID_Init(&mypid.inner,10,0,0,0,1000);//初始化內(nèi)環(huán)參數(shù)
  PID_Init(&mypid.outer,5,0,5,0,100);//初始化外環(huán)參數(shù)
  while(1)//進(jìn)入循環(huán)運(yùn)行
  {
    float outerTarget=...;//獲取外環(huán)目標(biāo)值
    float outerFeedback=...;//獲取外環(huán)反饋值
    float innerFeedback=...;//獲取內(nèi)環(huán)反饋值
    PID_CascadeCalc(&mypid,outerTarget,outerFeedback,innerFeedback);//進(jìn)行PID計(jì)算
    設(shè)定執(zhí)行機(jī)構(gòu)輸出大小(mypid.output);
    delay(10);//延時(shí)一段時(shí)間
  }
}

雙環(huán)效果

360af194-7bf5-11ee-939d-92fbcf53809c.gif

雙環(huán)控制

串聯(lián)

如果電機(jī)控制既要控制速度又要控制位置,因?yàn)樗俣群臀恢孟嚓P(guān),所以需要串聯(lián)。

3613d250-7bf5-11ee-939d-92fbcf53809c.png

并聯(lián)

姿態(tài)角度與速度間無(wú)相關(guān)性,各自單獨(dú)算一路控制

36183444-7bf5-11ee-939d-92fbcf53809c.png

示例

循跡小車(chē)

可見(jiàn)小車(chē)的循跡效果。

野火中步進(jìn)電機(jī)位置速度雙環(huán)控制

步進(jìn)電機(jī)速度環(huán)控制實(shí)現(xiàn)和 10. 步進(jìn)電機(jī)位置環(huán)控制實(shí)現(xiàn)介紹了單環(huán)控制已經(jīng)能很好地提高電機(jī)的性能了,但是仍有其局限性。

使用速度環(huán)精確控制了電機(jī)的轉(zhuǎn)速,但是停止的位置難以精確控制;

使用位置環(huán)精確控制了電機(jī)轉(zhuǎn)過(guò)的角度,卻不得不人為限制速度來(lái)防止堵轉(zhuǎn)。

位置環(huán)和速度環(huán)雙環(huán)控制,既實(shí)現(xiàn)位置的精確調(diào)節(jié)又實(shí)現(xiàn)速度的自動(dòng)控制。

3627684c-7bf5-11ee-939d-92fbcf53809c.png

該控制下,編碼器不僅起到了反饋位置的作用,也起到了反饋速度的作用。

調(diào)參技巧:在PID參數(shù)整定時(shí),采取先內(nèi)環(huán)再外環(huán)的方法,也就是先單獨(dú)使用速度環(huán)控制,得到滿(mǎn)意的參數(shù)后, 再把位置環(huán)套在外面,整定位置環(huán)參數(shù),最后根據(jù)整體效果對(duì)速度環(huán)參數(shù)進(jìn)行微調(diào)。

bsp_pid.h

/*pid*/
typedef struct
{
 float target_val;   //目標(biāo)值
 float actual_val;   //實(shí)際值
 float err;      //定義當(dāng)前偏差值
 float err_next;    //定義下一個(gè)偏差值
 float err_last;    //定義上一個(gè)偏差值
 float Kp, Ki, Kd;   //定義比例、積分、微分系數(shù)
}_pid;

bsp_stepper_ctrl.h

/*宏定義*/
/*******************************************************/
#define TIM_STEP_FREQ   (SystemCoreClock/TIM_PRESCALER) // 頻率ft值


/*電機(jī)單圈參數(shù)*/
#define STEP_ANGLE             1.8f         //步進(jìn)電機(jī)的步距角 單位:度
#define FSPR       (360.0f/STEP_ANGLE) //步進(jìn)電機(jī)的一圈所需脈沖數(shù)


#define MICRO_STEP    32                     //細(xì)分器細(xì)分?jǐn)?shù)
#define SPR        (FSPR*MICRO_STEP)  //細(xì)分后一圈所需脈沖數(shù)


#define PULSE_RATIO    (float)(SPR/ENCODER_TOTAL_RESOLUTION)//步進(jìn)電機(jī)單圈脈沖數(shù)與編碼器單圈脈沖的比值
#define SAMPLING_PERIOD  50          //PID采樣頻率,單位Hz


#define MOVE_CTRL     0.1f          //啟用速度環(huán)控制量
#define TARGET_DISP    20          //步進(jìn)電機(jī)運(yùn)動(dòng)時(shí)的目標(biāo)圈數(shù),單位:轉(zhuǎn)
#define TARGET_SPEED_MAX 800         // 目標(biāo)速度的最大值


typedef struct {
 unsigned char stepper_dir : 1;        //步進(jìn)電機(jī)方向
 unsigned char stepper_running : 1;      //步進(jìn)電機(jī)運(yùn)行狀態(tài)
 unsigned char MSD_ENA : 1;          //驅(qū)動(dòng)器使能狀態(tài)
}__SYS_STATUS;

bsp_stepper_ctrl.c-增量式PID算法實(shí)現(xiàn)-增量式PID

/**
  * @brief 增量式PID算法實(shí)現(xiàn)
  * @param val:當(dāng)前實(shí)際值
  * @note  無(wú)
  * @retval 通過(guò)PID計(jì)算后的輸出
  */
 float PID_realize(_pid *pid, float temp_val)
{
  /*傳入實(shí)際值*/
  pid->actual_val = temp_val;
  /*計(jì)算目標(biāo)值與實(shí)際值的誤差*/
  pid->err=pid->target_val-pid->actual_val;


  /*PID算法實(shí)現(xiàn)*/
  float increment_val = pid->Kp*(pid->err - pid->err_next) + pid->Ki*pid->err + pid->Kd*(pid->err - 2 * pid->err_next + pid->err_last);
  /*傳遞誤差*/
  pid->err_last = pid->err_next;
  pid->err_next = pid->err;
  /*返回增量值*/
  return increment_val;
 }

bsp_stepper_ctrl.c-步進(jìn)電機(jī)位置速度雙閉環(huán)控制

 /**
  * @brief 步進(jìn)電機(jī)位置速度雙閉環(huán)控制
  * @retval 無(wú)
  * @note  基本定時(shí)器中斷內(nèi)調(diào)用
  */
 void Stepper_Ctrl(void)
{
  /* 編碼器相關(guān)變量 */
  static __IO float last_count = 0;
  __IO float capture_count = 0;
  __IO float capture_per_unit = 0;
  /* 經(jīng)過(guò)pid計(jì)算后的期望值 */
  static __IO float speed_cont_val = 0.0f;
  static __IO float move_cont_val = 0.0f;
  static int cont_val = 0;


  /* 當(dāng)電機(jī)運(yùn)動(dòng)時(shí)才啟動(dòng)pid計(jì)算 */
  if((sys_status.MSD_ENA == 1) && (sys_status.stepper_running == 1))
  {
   /* 計(jì)算編碼器脈沖數(shù) */
   capture_count = (int)__HAL_TIM_GET_COUNTER(&TIM_EncoderHandle) + (encoder_overflow_count * ENCODER_TIM_PERIOD);
   /* 計(jì)算速度環(huán)的傳入值 */
   capture_per_unit = capture_count - last_count;
   last_count = capture_count;


   /* 編碼器脈沖累計(jì)值作為實(shí)際值傳入位置環(huán)pid控制器 */
   move_cont_val += PID_realize_move(&move_pid, (float)capture_count);// 進(jìn)行 PID 計(jì)算
   /* 判斷運(yùn)動(dòng)方向 */
   move_cont_val > 0 ? (MOTOR_DIR(CW)) : (MOTOR_DIR(CCW));
   /* 判斷是否啟用速度環(huán) */
   if (fabsf(move_cont_val) >= MOVE_CTRL)
   {
    /* 傳遞位置環(huán)計(jì)算值,便于計(jì)算*/
    cont_val = move_cont_val;


    /* 目標(biāo)速度上限處理 */
    if (cont_val > TARGET_SPEED_MAX)
    {
     cont_val = TARGET_SPEED_MAX;
    }
    else if (cont_val < -TARGET_SPEED_MAX)
 ? ? ? {
 ? ? ? ? cont_val = -TARGET_SPEED_MAX;
 ? ? ? }


 #if defined(PID_ASSISTANT_EN)
 ? ? ? int32_t temp = cont_val;
 ? ? ? set_computer_value(SEED_TARGET_CMD, CURVES_CH2, &temp, 1); ? ? // 給通道 2 發(fā)送目標(biāo)值
 #endif
 ? ? ? /* 設(shè)定速度的目標(biāo)值 */
 ? ? ? set_pid_target(&speed_pid, cont_val);
 ? ? ? /* 單位時(shí)間內(nèi)的編碼器脈沖數(shù)作為實(shí)際值傳入速度環(huán)pid控制器 */
 ? ? ? speed_cont_val += PID_realize_speed(&speed_pid, (float)capture_per_unit);// 進(jìn)行 PID 計(jì)算
 ? ? ? /* 由于OC_Pulse_num為uint16_t變量,取速度環(huán)輸出值的絕對(duì)值進(jìn)行后續(xù)計(jì)算*/
 ? ? ? cont_val = fabsf(speed_cont_val);
 ? ? ? /* 計(jì)算比較計(jì)數(shù)器的值 */
 ? ? ? OC_Pulse_num = ((uint16_t)(TIM_STEP_FREQ / (cont_val * PULSE_RATIO * SAMPLING_PERIOD))) >> 1;
   }
   else
   {
    /* 計(jì)算比較計(jì)數(shù)器的值 */
    OC_Pulse_num = ((uint16_t)(TIM_STEP_FREQ / ((float)move_cont_val * PULSE_RATIO))) >> 1;
   }
 #if PID_ASSISTANT_EN
   int Temp_ch2 = capture_per_unit;  // 上位機(jī)需要整數(shù)參數(shù),轉(zhuǎn)換一下
   int Temp_ch1 = capture_count;
   set_computer_value(SEED_FACT_CMD, CURVES_CH2, &Temp_ch2, 1); // 給通道 1 發(fā)送實(shí)際值   // 給通道 2 發(fā)送實(shí)際值
   set_computer_value(SEED_FACT_CMD, CURVES_CH1, &Temp_ch1, 1);   // 給通道 1 發(fā)送實(shí)際值


 #else
   printf("實(shí)際值:%d,目標(biāo)值:%.0f
", capture_per_unit, pid.target_val);// 打印實(shí)際值和目標(biāo)值
 #endif
  }
  else
  {
   /*停機(jī)狀態(tài)所有參數(shù)清零*/
   last_count = 0;
   speed_cont_val = 0;
   move_cont_val = 0;
   speed_pid.actual_val = 0;
   speed_pid.err = 0;
   speed_pid.err_last = 0;
   speed_pid.err_next = 0;
   move_pid.actual_val = 0;
   move_pid.err = 0;
   move_pid.err_last = 0;
   move_pid.err_next = 0;
  }
 }

main

 /**
  * @brief 主函數(shù)
  * @param 無(wú)
  * @retval 無(wú)
  */
 int main(void)
{
  /* 初始化系統(tǒng)時(shí)鐘為168MHz */
  SystemClock_Config();
  /*初始化USART 配置模式為 115200 8-N-1,中斷接收*/
  DEBUG_USART_Config();
  printf("歡迎使用野火 電機(jī)開(kāi)發(fā)板 步進(jìn)電機(jī)位置速度雙環(huán)控制 例程
");
  printf("按下按鍵3啟動(dòng)和停止電機(jī)
");
  /* 初始化時(shí)間戳 */
  HAL_InitTick(5);
  /*按鍵中斷初始化*/
  Key_GPIO_Config();
  /*led初始化*/
  LED_GPIO_Config();
  /* 初始化基本定時(shí)器定時(shí),20ms產(chǎn)生一次中斷 */
  TIMx_Configuration();
  /* 編碼器接口初始化 */
  Encoder_Init();
  /*步進(jìn)電機(jī)初始化*/
  stepper_Init();
  /* 上電默認(rèn)停止電機(jī) */
  Set_Stepper_Stop();
  /* PID算法參數(shù)初始化 */
  PID_param_init();
 // MOTOR_DIR(CW);


  /* 目標(biāo)位置轉(zhuǎn)換為編碼器的脈沖數(shù)作為pid目標(biāo)值 */
  move_pid.target_val = TARGET_DISP * ENCODER_TOTAL_RESOLUTION;
  int32_t Temp = TARGET_DISP * ENCODER_TOTAL_RESOLUTION;
 #if PID_ASSISTANT_EN
  set_computer_value(SEED_STOP_CMD, CURVES_CH1, NULL, 0);  // 同步上位機(jī)的啟動(dòng)按鈕狀態(tài)
  set_computer_value(SEED_TARGET_CMD, CURVES_CH1, &Temp, 1);// 給通道 1 發(fā)送目標(biāo)值
 #endif


  while(1)
  {
   /* 掃描KEY1,啟動(dòng)電機(jī) */
   if( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON )
   {
   #if PID_ASSISTANT_EN
    Set_Stepper_Start();
    set_computer_value(SEED_START_CMD, CURVES_CH1, NULL, 0);// 同步上位機(jī)的啟動(dòng)按鈕狀態(tài)
   #else
    Set_Stepper_Start();
   #endif
   }
   /* 掃描KEY2,停止電機(jī) */
   if( Key_Scan(KEY2_GPIO_PORT,KEY2_PIN) == KEY_ON )
   {
   #if PID_ASSISTANT_EN
    Set_Stepper_Stop();
    set_computer_value(SEED_STOP_CMD, CURVES_CH1, NULL, 0);// 同步上位機(jī)的啟動(dòng)按鈕狀態(tài)
   #else
    Set_Stepper_Stop();
   #endif
   }
   /* 掃描KEY3,增大目標(biāo)位置*/
   if( Key_Scan(KEY3_GPIO_PORT,KEY3_PIN) == KEY_ON )
   {
    /* 目標(biāo)位置增加48000,對(duì)應(yīng)電機(jī)位置增加20圈 */
    move_pid.target_val += 48000;


   #if PID_ASSISTANT_EN
    int temp = move_pid.target_val;
    set_computer_value(SEED_TARGET_CMD, CURVES_CH1, &temp, 1);// 給通道 1 發(fā)送目標(biāo)值
   #endif
   }
   /* 掃描KEY4,減小目標(biāo)位置 */
   if( Key_Scan(KEY4_GPIO_PORT,KEY4_PIN) == KEY_ON )
   {
    /* 目標(biāo)位置減小48000,對(duì)應(yīng)電機(jī)位置減少20圈 */
    move_pid.target_val -= 48000;


   #if PID_ASSISTANT_EN
    int temp = move_pid.target_val;
    set_computer_value(SEED_TARGET_CMD, CURVES_CH1, &temp, 1);// 給通道 1 發(fā)送目標(biāo)值
   #endif
   }
  }
 }

補(bǔ)充知識(shí)點(diǎn)

模擬量數(shù)字化

實(shí)際數(shù)字化應(yīng)用中,PID 系統(tǒng)中的積分項(xiàng)和微分項(xiàng)需要進(jìn)行離散化處理。

類(lèi)似的典型應(yīng)用有數(shù)字示波器。對(duì)于數(shù)字示波器來(lái)說(shuō)它無(wú)法直接量化模擬信號(hào),替代的辦法就是持續(xù)周期性采樣,然后將得到的一系列采樣點(diǎn)顯示出來(lái),當(dāng)采樣速率越高,顯示的圖像越真實(shí),這就是數(shù)學(xué)中極限的與微分的思想。

3633c330-7bf5-11ee-939d-92fbcf53809c.png

香農(nóng)(Shannon) 采樣定律

364e885a-7bf5-11ee-939d-92fbcf53809c.png

?定理內(nèi)容

香農(nóng)取樣定理是針對(duì)有限帶寬函數(shù)的,為了不失真地恢復(fù)模擬信號(hào),采樣頻率應(yīng)該不小于模擬信號(hào)頻譜中最高頻率的2倍。








審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5060

    文章

    18980

    瀏覽量

    302242
  • plc
    plc
    +關(guān)注

    關(guān)注

    5007

    文章

    13125

    瀏覽量

    461547
  • DCS
    DCS
    +關(guān)注

    關(guān)注

    20

    文章

    604

    瀏覽量

    49919
  • PID算法
    +關(guān)注

    關(guān)注

    2

    文章

    171

    瀏覽量

    24259
  • PID控制器
    +關(guān)注

    關(guān)注

    2

    文章

    172

    瀏覽量

    18537
  • 工業(yè)控制系統(tǒng)

    關(guān)注

    3

    文章

    110

    瀏覽量

    16575

原文標(biāo)題:嵌入式PID算法理論+實(shí)踐分析

文章出處:【微信號(hào):嵌入式開(kāi)發(fā)愛(ài)好者,微信公眾號(hào):嵌入式開(kāi)發(fā)愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    嵌入式AES算法CBC模式

    嵌入式AES算法CBC模式
    發(fā)表于 08-18 07:28

    【最新課程推薦】PID控制算法

    控制算法;4、掌握常見(jiàn)的溫控參數(shù)設(shè)置;本課程的受眾群體是:有一定單片機(jī)編程基礎(chǔ),尤其是會(huì)用STM23開(kāi)發(fā);有一定的電路基礎(chǔ),能看懂電路圖。>>點(diǎn)擊鏈接進(jìn)入學(xué)習(xí)講師介紹:胥老師技術(shù)總監(jiān)專(zhuān)注于電路設(shè)計(jì),單片機(jī)嵌入式開(kāi)發(fā)教學(xué)
    發(fā)表于 10-12 15:27

    【杭州】誠(chéng)聘嵌入式算法工程師

    參與開(kāi)發(fā)前期的需求分析與設(shè)計(jì);6.自動(dòng)化設(shè)備嵌入式算法軟件的設(shè)計(jì)開(kāi)發(fā)工作。崗位要求:1.具有三年以上嵌入式算法開(kāi)發(fā)工作經(jīng)驗(yàn);2.本科及以上學(xué)
    發(fā)表于 08-02 15:43

    嵌入式小波編碼算法的原理是什么?

    Partitioned Embedded bloCK coder),可逆嵌入小波壓縮算法(CREW:Compression with Reversible Embedded Wavelets)[3] 。本文對(duì)這些算法進(jìn)行了原理
    發(fā)表于 08-15 08:27

    PID算法增量算法

    這里的PID是指控制類(lèi)的比例-積分-微分算法,而不是進(jìn)程ID號(hào)。PID算法,不管是原理上,還是代碼上都比較簡(jiǎn)單。主要運(yùn)用在電機(jī)控制、開(kāi)關(guān)電源、電源管理芯片等領(lǐng)域。一般《自動(dòng)控制原理》上
    發(fā)表于 09-13 06:06

    嵌入式系統(tǒng)中語(yǔ)音算法的基本原理是什么

    嵌入式系統(tǒng)中語(yǔ)音算法的基本原理是什么?嵌入式系統(tǒng)中語(yǔ)音算法有何功能?
    發(fā)表于 12-23 08:49

    嵌入式系統(tǒng)編程教學(xué)分析

    通過(guò)volatile關(guān)鍵字的使用、嵌入式系統(tǒng)工程設(shè)置、嵌入式系統(tǒng)的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)、嵌入式系統(tǒng)算法設(shè)計(jì)四個(gè)方面的介紹,分析
    發(fā)表于 07-01 17:07 ?26次下載

    嵌入式系統(tǒng)中FFT算法分析及設(shè)計(jì)方案

    嵌入式系統(tǒng)中FFT算法分析及設(shè)計(jì)方案 概述: 目前國(guó)內(nèi)有關(guān)數(shù)字信號(hào)處理
    發(fā)表于 03-08 11:47 ?762次閱讀
    <b class='flag-5'>嵌入式</b>系統(tǒng)中FFT<b class='flag-5'>算法</b><b class='flag-5'>分析</b>及設(shè)計(jì)方案

    pid算法_什么是pid算法

    PID控制器是一種最優(yōu)控制。本文講述了增量PID算法原理與數(shù)字PID算法原理與數(shù)字
    發(fā)表于 01-01 11:58 ?1.1w次閱讀
    <b class='flag-5'>pid</b><b class='flag-5'>算法</b>_什么是<b class='flag-5'>pid</b><b class='flag-5'>算法</b>

    嵌入式開(kāi)發(fā)的crc算法知識(shí)精選

    CRC校驗(yàn)(循環(huán)冗余校驗(yàn))是數(shù)據(jù)通訊中最常采用的校驗(yàn)方式。在嵌入式軟件開(kāi)發(fā)中,經(jīng)常要用到CRC 算法對(duì)各種數(shù)據(jù)進(jìn)行校驗(yàn)。因此,掌握基本的CRC算法應(yīng)是嵌入式程序員的基本技能??墒牵?/div>
    的頭像 發(fā)表于 11-08 11:28 ?4402次閱讀
    <b class='flag-5'>嵌入式</b>開(kāi)發(fā)的crc<b class='flag-5'>算法</b>知識(shí)精選

    嵌入式系統(tǒng)中數(shù)字濾波的算法及軟件流程

    嵌入式系統(tǒng)中數(shù)字濾波的算法及軟件流程(嵌入式開(kāi)發(fā)工具軟件是什么)-嵌入式系統(tǒng)中數(shù)字濾波的算法及軟件流程 ? ? ? ? ? ? ??
    發(fā)表于 07-30 12:45 ?15次下載
    <b class='flag-5'>嵌入式</b>系統(tǒng)中數(shù)字濾波的<b class='flag-5'>算法</b>及軟件流程

    基于KCF的目標(biāo)跟蹤算法研究及嵌入式系統(tǒng)實(shí)現(xiàn)

    基于KCF的目標(biāo)跟蹤算法研究及嵌入式系統(tǒng)實(shí)現(xiàn)(嵌入式開(kāi)發(fā)公司如何接項(xiàng)目)-該文檔為基于KCF的目標(biāo)跟蹤算法研究及嵌入式系統(tǒng)實(shí)現(xiàn)總結(jié)文檔,是一
    發(fā)表于 08-04 10:07 ?8次下載
    基于KCF的目標(biāo)跟蹤<b class='flag-5'>算法</b>研究及<b class='flag-5'>嵌入式</b>系統(tǒng)實(shí)現(xiàn)

    嵌入式系統(tǒng)的應(yīng)用控制理論

    嵌入式系統(tǒng)的應(yīng)用控制理論(嵌入式開(kāi)發(fā)板安卓)-工程師寫(xiě)的控制理論書(shū),為了學(xué)習(xí)下PID算法
    發(fā)表于 08-04 13:32 ?4次下載
    <b class='flag-5'>嵌入式</b>系統(tǒng)的應(yīng)用控制理論

    PID算法與直流電機(jī)的PWM技術(shù)控制

    PID控制算法是工業(yè)控制領(lǐng)域使用最廣泛的算法之一,嵌入式系統(tǒng)是工業(yè)領(lǐng)域和生活中最常見(jiàn)的智能系統(tǒng)之一。本文介紹了PID控制
    發(fā)表于 11-26 12:06 ?47次下載
    <b class='flag-5'>PID</b><b class='flag-5'>算法</b>與直流電機(jī)的PWM技術(shù)控制

    深度學(xué)習(xí)算法嵌入式平臺(tái)上的部署

    隨著人工智能技術(shù)的飛速發(fā)展,深度學(xué)習(xí)算法在各個(gè)領(lǐng)域的應(yīng)用日益廣泛。然而,將深度學(xué)習(xí)算法部署到資源受限的嵌入式平臺(tái)上,仍然是一個(gè)具有挑戰(zhàn)性的任務(wù)。本文將從嵌入式平臺(tái)的特點(diǎn)、深度學(xué)習(xí)
    的頭像 發(fā)表于 07-15 10:03 ?1110次閱讀