Heim Der Blog Blog Details

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors

February 10 2025
Ampheo

Anfrage

Globaler Lieferant elektronischer Komponenten AMPHEO PTY LTD: Umfangreiches Inventar für One-Stop-Shopping. Einfache Anfragen, schnelle, individuelle Lösungen und Angebote.

SCHNELLE ANFRAGE
ZUR RFQ-LISTE HINZUFÜGEN
Der interne Aufbau und das Funktionsprinzip von Gleichstrommotoren werden eigentlich schon in Physikbüchern für die Oberstufe gelehrt. Hier besprechen wir hauptsächlich, wie man einen Gleichstrommotor mit einem Mikrocontroller und einem Motortreibermodul antreibt.
1. Grundlegende Motorsteuerung
 
Der interne Aufbau und das Funktionsprinzip von Gleichstrommotoren werden eigentlich schon in Physikbüchern für die Oberstufe gelehrt. Hier besprechen wir hauptsächlich, wie man einen Gleichstrommotor mit einem Mikrocontroller und einem Motortreibermodul antreibt.
 
1. 1. Gerätevorbereitung und Verdrahtung
 
Das in diesem Artikel verwendete Mikrocontrollermodell ist stm32f103rct6, und stm32f103c8t6 kann auch verwendet werden.
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 1

Wählen Sie für den Motorantrieb den

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 2

 
Gleichstrommotor TB6612. Wählen Sie diesen Encodermotor mit Hallsensor, 12 V, Untersetzungsverhältnis 1/30, Drehzahl 330 U/min.

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 3

 
Um die Beobachtung und Bedienung zu erleichtern, wird ein 0,96-Zoll-OLED verwendet

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 4

 
Verdrahtung
 
Pinbelegung des Moduls MCU-Pins
OLED_SCL PB8
OLED_SDA PB9
Taste K1 PC9
Taste K2 PC8
TB6612_AIN1 PB12
TB6612_AIN2 PB13
Encoder A Phase PB6
Encoderphase B PB7
 
1.2. Codeanzeige
Die Ansteuerung von TB6612 ist sehr einfach. Es verwendet zwei normale GPIO-Ausgänge mit hohem und niedrigem Pegel, um die Vorwärts- und Rückwärtsdrehung des Motors zu steuern, und verwendet dann einen Multiplex-Timer-IO, um ein PWM zur Steuerung der Motordrehzahl zu generieren.
Der motor.c-Teil des Codes lautet wie folgt:
 
#include "motor.h"
/**
  * @brief  电机方向控制引脚设置
  * @param  None
  * @retval None  
  */
static void motor_gpio_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13; //端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //50M
  GPIO_Init(GPIOB, &GPIO_InitStructure);       //根据设定参数初始化GPIOB 
}
 
/**
  * @brief  定时器初始化
  * @param  arr:自动重装值,设为一个时钟频率的最大值
  * @param  psc: 预分频值
  * @retval None  
  */
void Motor_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;
    motor_gpio_Init();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);// 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIO外设时钟使能
   //设置该引脚为复用输出功能,输出TIM1 CH1 CH4的PWM脉冲波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //TIM_CH1 //TIM_CH4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
 
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值  
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
 
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0;                            //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //输出极性:TIM输出比较极性高
TIM_OC4Init(TIM1, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
 
    TIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE 主输出使能
 
TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH4预装载使能  
 
TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器
 
TIM_Cmd(TIM1, ENABLE);  //使能TIM1
 
Verwenden Sie einfach eine Funktion. Die Eingabe ist eine vorzeichenbehaftete Ganzzahlvariable, die positiven und negativen Vorzeichen stellen die ausgewählte Richtung dar und der absolute Wert stellt den Arbeitszyklus dar.
 
/**
  * @brief  电机输出控制
  * @param  motor_pwm: 占空比 0-7200
  * @retval None  
  */
void Set_Pwm(int motor_pwm)
{
  if(motor_pwm>0)
  {
  BIN1=1;
      BIN2=0; //前进 
  }
 
 else if(motor_pwm<0)
{
BIN1=0;
BIN2=1; //后退
}
else  //停止
{
BIN1=0;
BIN2=0; 
}
PWMB=myabs(motor_pwm);
TIM_SetCompare4(TIM1, PWMB);
}
 
 
1.3. Effektanzeige
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 5

Die erste Zeile des OLED-Displays zeigt den Betriebszustand (EIN oder AUS) an, die zweite Zeile zeigt den PWM-Wert des Motors an, wobei + für Vorwärtsdrehung steht, - für Rückwärtsdrehung und durch Drücken von K1 die Drehrichtung des Motors umgeschaltet wird. Drücken Sie K2, um den Motor zu starten/stoppen.
gitee-PID-Motorsteuerungsquellcode basierend auf stm32
 
2. Motordrehzahlanzeige
 
Als Encoder kommt ein Hall-Sensor mit zwei im 90-Grad-Winkel zueinander angeordneten Hall-Elementen zum Einsatz. Die Lesemethoden der Encoder-Motordrehzahl lassen sich aus der Mikrocontroller-Lesemethode in die Timer-Eingangserfassungsmethode und die externe Interruptmethode, aus dem Encoderprinzip in Doppelfrequenz und Vierfachfrequenz und aus der Geschwindigkeitsberechnungsmethode in die Geschwindigkeitsmessung mit der M-Methode und die Geschwindigkeitsmessung mit der T-Methode unterteilen.
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 6

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 7

 
Werfen wir einen kurzen Blick auf die Geschwindigkeitsmessung mit der M-Methode und der T-Methode.
 
Geschwindigkeitsmessung nach der M-Methode : Innerhalb eines festen Zeitzyklus wird die Anzahl der Encoderimpulse in diesem Zeitraum gezählt und daraus der Geschwindigkeitswert berechnet.
 
Die Berechnungsformel der Drehzahl n lautet:
 
 N=M 0/ ( C∗T 0 ) 
 
C: Gesamtzahl der Encoderimpulse pro Umdrehung
T0: Zählperiode, Einheit: Sekunde (s)
M0: Anzahl der innerhalb der Zählperiode gezählten Encoderimpulse
 
Angenommen, es ist bekannt, dass der Encoder 100 Impulse für eine Umdrehung benötigt und dass innerhalb von 100 ms 20 Impulse gemessen werden. Berechnet nach der Formel n = 20/(100*0,1)=2 (Kreise/Sekunde)
 
Geschwindigkeitsmessung mit der T-Methode : Bei dieser Methode wird ein Hochfrequenzimpuls mit bekannter Frequenz erzeugt und gezählt.
Die Berechnungsformel der Drehzahl n lautet:
 
 N=F 0/ ( C∗M 1 ) 
 
C: Gesamtimpulszahl einer Encoder-Einzelumdrehung
F0: Frequenz des Hochfrequenzimpulses
M1: Anzahl der Umdrehungen eines Impulses
 
Bei der T-Methode wird anhand eines bekannten Impulses die Zeit zwischen zwei Encoderimpulsen gemessen, um so die Geschwindigkeit zu berechnen.
 
Angenommen, der Encoder benötigt 100 Impulse für eine Umdrehung (C=100), dann führt ein Impuls eine Umdrehung von 1/100 aus, was 20 ms bzw. 50 Hz dauert, und die Drehgeschwindigkeit beträgt 0,5 Umdrehungen/Sekunde.
 
Zur Lösung des Problems der Geschwindigkeitsberechnung werden die M-Methode und die T-Methode der Geschwindigkeitsmessung verwendet. Im Folgenden werden die Methode zur Erfassung der Timereingabe und die Methode zur externen Unterbrechung erläutert.
 
2.1. Methode zur Erfassung von Timer-Eingaben
2.1.1. Interne Struktur der Timer-Eingabeerfassung
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 8

 
Zuerst werden zwei orthogonale Signale vom GPIO in den Filter eingegeben, dann werden Flankenerkennung und Polaritätsauswahl durchgeführt und mit der Encoderschnittstelle im Timer verbunden.
 
Bei der Geschwindigkeitsmessung mithilfe der Methode zur Erfassung der Timereingabe wird tatsächlich die Encoder-Schnittstellenfunktion des STM32-Timers verwendet:
Die Encoder-Schnittstelle kann das Signal des inkrementellen (orthogonalen) Encoders empfangen und den CNT automatisch so steuern, dass er entsprechend den durch die Encoderrotation erzeugten orthogonalen Signalimpulsen zunimmt oder abnimmt, wodurch die Position, Drehrichtung und Drehgeschwindigkeit des Encoders angezeigt werden.
 
  • Jeder erweiterte Timer und allgemeine Timer verfügt über eine Encoder-Schnittstelle
  • Die beiden Eingangspins übernehmen Kanal 1 und Kanal 2 der Eingangserfassung.
Nachfolgend ist die Beziehung zwischen der Zählrichtung und dem Kodierungssignal dargestellt:
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 9

 
2.1.2. Codeanzeige
 
Nachfolgend sind einige Codes von encoder.c aufgeführt:
 
/**
  * @brief  编码器初始化,使用定时器输入捕获法
  * @param  None
  * @retval None 
  */
void Encoder_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 
    GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
 
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
 
    TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
 
TIM_ICInit(TIM4, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
 
TIM_ICInit(TIM4, &TIM_ICInitStructure);
/*TI1和TI2都计数,上升沿计数*/
TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
 
TIM_Cmd(TIM4, ENABLE);
}
/**
  * @brief  获取定时器的计数值
  * @param  None
  * @retval None 
  */
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp = TIM_GetCounter(TIM4);
TIM_SetCounter(TIM4, 0);
return Temp;
}
 
 
Zusätzlich wird über einen Timer die Erfassungsgeschwindigkeit eingestellt:
 
 /**
  * @brief  定时器中断,每100ms更新一次速度
  * @param  None
  * @retval None 
  */
  
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
Speed = Encoder_Get();
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 10

 
2.2. Externe Interrupt-Methode
2.2.1. Einführung in die externe Interrupt-Methode
 
Verwenden Sie das Sprungsignal des Mikrocontroller-Pins, um den Interrupt auszulösen, und beurteilen Sie dann den Pegel der beiden Encoder-Pins im Interrupt, um den Zählwert zu erhöhen oder zu verringern. Wir legen fest, dass der Vorwärtszählwert ++ und der Rückwärtszählwert - ist.
 
Bei Verwendung der 4-fachen Frequenzzählung lösen die steigende und die fallende Flanke der Phase A sowie die steigende und die fallende Flanke der Phase B Interrupts aus.
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 11

 
Kante der Phase A Ebene Phase B Entsprechender Bereich Zählwert
Steigende Flanke M 2 Encoder_EXTI++
Fallende Flanke H 4 Encoder_EXTI++

 

B Phasenflanke Eine Phasenebene Entsprechender Bereich Zählwert
Steigende Flanke H 3 Encoder_EXTI++
Fallende Flanke M 1 Encoder_EXTI++
 
Wenn der Motor umkehrt, unterscheiden sich die Phasen der A- und B-Phasensignale um 90 Grad von denen bei der Vorwärtsdrehung. Mit anderen Worten: Bei der Vorwärtsdrehung löst Phase A zuerst die steigende Flanke aus, während bei der Rückwärtsdrehung Phase B zuerst die steigende Flanke auslöst.
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 12

 
Kante der Phase A Ebene Phase B Entsprechender Bereich Zählwert
Steigende Flanke H 3 Encoder_EXTI–
Fallende Flanke M 1 Encoder_EXTI–
 
B Phasenflanke Eine Phasenebene Entsprechender Bereich Zählwert
Steigende Flanke M 2 Encoder_EXTI–
Fallende Flanke H 4 Encoder_EXTI–

 

2.2.2. Codeanzeige
 
Ein Teil des Codes lautet wie folgt:
 
/**
  * @brief  编码器初始化,使用外部中断法
  * @param  None
  * @retval None 
  */
void Encoder_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
 
GPIO_Init(GPIOB,&GPIO_InitStruct);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//设置IO口与中断线的映射关系
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource6);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource7);
//4.初始化线上中断
EXTI_InitStruct.EXTI_Line =  EXTI_Line6 | EXTI_Line7;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//跳变沿触发
EXTI_Init(&EXTI_InitStruct);
//5.配置中断分组
NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);
 
}
/**
  * @brief  中断服务函数,采用4倍频测速
  * @param  None
  * @retval None 
  */
int Encoder_EXTI=0;
void EXTI9_5_IRQHandler(void)
{
 
if(EXTI_GetITStatus(EXTI_Line6) != RESET)//右轮A相 PB6
{
EXTI_ClearITPendingBit(EXTI_Line6);  //清除LINE上的中断标志位
if(PBin(6)==0)   //这里判断检测到的是否是下降沿
{
if(PBin(7)==0)   Encoder_EXTI++;//B相的电平如果是低,电机就是正转加1
else             Encoder_EXTI--;//否则就是反转减1
}
else                  //上升沿
if(PBin(7)==1)  Encoder_EXTI++; //B相电平如果为高,电机就是正转加1
else             Encoder_EXTI--;//否则就是反转减1
}
}
 
if(EXTI_GetITStatus(EXTI_Line7) != RESET)//右轮B相 PB7
{
EXTI_ClearITPendingBit(EXTI_Line7);  //清除LINE上的中断标志位
if(PBin(7)==0)   //这里判断检测到的是否是下降沿
{
if(PBin(6)==1)   Encoder_EXTI++;//A相的电平如果是高,电机就是正转加1
else             Encoder_EXTI--;//否则就是反转减1
}
else                  //上升沿
if(PBin(6)==0)  Encoder_EXTI++; //A相电平如果为低,电机就是正转加1
else             Encoder_EXTI--;//否则就是反转减1
}
}
 
}
/**
  * @brief  获取中断的计数值
  * @param  None
  * @retval None 
  */
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp = Encoder_EXTI;
Encoder_EXTI =0;
return Temp;
}
 /**
  * @brief  定时器中断,每100ms更新一次速度
  * @param  None
  * @retval None 
  */
  void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
Speed = Encoder_Get();
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
 
 
2.2.3. Effektanzeige
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 13

 
Berechnung der tatsächlichen Drehzahl des Motorrades:
 
1. Zunächst einmal lautet das Wesentliche der Formel zur Geschwindigkeitsberechnung:
 
In=s / t
 
t: bekannter Zählzyklus des Encoders (100 ms), s: die Strecke, die das Rad in diesem Zählzyklus zurücklegt.
 
2. Als nächstes müssen wir s berechnen.
 
Wir wissen, dass der Encoder die Anzahl der Impulse pro Zeiteinheit erfasst und dass die Codescheibe des Encoders am Ende der Motorwelle installiert ist. Sie misst die Geschwindigkeit der Motorausgangswelle. Die Motorwelle muss außerdem durch ein Untersetzungsgetriebe geführt werden, bevor sie mit dem Rad verbunden werden kann.
 
Daraus lässt sich zunächst die Strecke berechnen, die ein Impulsrad pro Zeiteinheit zurücklegt.
 
 
m=2∗P Ich∗R / ( 4∗N∗ich )
 
2 * PI *R ist der Umfang des Rades, R ist der Radius des Rades (34 mm) bei 4-facher Zählung, n ist die Anzahl der Impulse pro Umdrehung der Encoderscheibe (11) und i ist das Untersetzungsverhältnis des Motors (30).
 
3. Die von einem Impulsrad zurückgelegte Strecke kann direkt von Hand berechnet werden. Wir multiplizieren sie also mit der Anzahl der vom Encoder gemessenen Impulse, um die vom Rad in diesem Zählzyklus zurückgelegte Strecke zu ermitteln.
daher,
 
S=M∗m
 
m ist die Anzahl der vom Encoder gemessenen Impulse.
Der obige Berechnungsprozess wird im C-Code wie folgt ausgedrückt:
 
/**
  * @brief  编码器读数转换为轮子速度(mm/s)
  * @param encoder:编码器计数
  * @retval : Velocity 轮子速度
  */
int Get_Velocity_Form_Encoder(int encoder)
{
float Distance,Velocity;
Distance= 2*3.14159*34/(4*11*30);//单位是mm
Velocity= encoder*Distance/0.1; //单位是mm/s。0.1就是编码器计数周期100ms,0.1s
 
return Velocity;
}
 
3. PID-Position
 
Berechnungsformel
 
Bei der Motorsteuerung geben wir einen PWM-Arbeitszykluswert an den Motor aus.
Die Grundformel der PID-Position:
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 14

 
Das Steuerungsflussdiagramm sieht wie folgt aus:
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 15

 
In der obigen Abbildung können wir den Zielwert normalerweise durch Programmierung über Tasten oder Schalter ändern, und die Messposition besteht darin, die Encoderdaten über stm32 zu erfassen. Die Differenz zwischen Zielposition und gemessener Position ist die aktuelle Regelabweichung. Die Ausgabe wird zur Berechnung an den PID-Regler gesendet und anschließend wird der Motor über einen Leistungsverstärker angetrieben, um die Drehung des Motors zu steuern, die Abweichung zu verringern und schließlich die Zielposition zu erreichen.
 
3.2.C-Sprachimplementierung
 
Der in der Sprache C implementierte Code für die PID-Position lautet wie folgt:
Definieren Sie zunächst eine PID- Parameterstruktur :
 
typedef struct
{
float target_val;   //目标值
float Error;          /*第 k 次偏差 */
float LastError;     /* Error[-1],第 k-1 次偏差 */
float PrevError;    /* Error[-2],第 k-2 次偏差 */
float Kp,Ki,Kd;     //比例、积分、微分系数
float integral;     //积分值
float output_val;   //输出值
}PID;
 
Erstellen Sie dann eine Funktion zum Initialisieren der PID-Parameter:
 
/**
  * @brief  PID参数初始化
  * @note 无
  * @retval 无
  */
void PID_param_init()
{
PosionPID.target_val=3600;
PosionPID.output_val=0.0;
PosionPID.Error=0.0;
PosionPID.LastError=0.0;
PosionPID.integral=0.0;
PosionPID.Kp = 10;
PosionPID.Ki = 0.5;
PosionPID.Kd = 0.8;
 
 
}
 
 
Schreiben Sie abschließend die Implementierungsfunktion der Position PID gemäß der Formel:
 
/**
  * @brief  位置PID算法实现
  * @param  actual_val:实际测量值
  * @note 无
  * @retval 通过PID计算后的输出
  */
float PosionPID_realize(PID *pid, float actual_val)
{
/*计算目标值与实际值的误差*/
pid->Error = pid->target_val - actual_val;
/*积分项*/
pid->integral += pid->Error;
/*PID算法实现*/
pid->output_val = pid->Kp * pid->Error +
                  pid->Ki * pid->integral +
                  pid->Kd *(pid->Error -pid->LastError);
/*误差传递*/
pid-> LastError = pid->Error;
/*返回当前实际值*/
return pid->output_val;
}
 
 
Die Funktionseingabeparameter sind der Geschwindigkeitsmesswert des Encoders und die Struktur der PID-Parameter, und der Rückgabewert ist die PWM zur Motorsteuerung.
 
4. Inkrementelles PID
 
4.1. Berechnungsformel
 
Inkrementelles PID wird auch als Drehzahlregler-PID bezeichnet. Bei der Drehzahlregelung mit geschlossenem Regelkreis werden die Drehzahlinformationen des Motors anhand der Anzahl der pro Zeiteinheit erhaltenen Impulse gemessen (hier wird die M-Methode zur Drehzahlmessung verwendet) und mit dem Zielwert verglichen, um die Regelabweichung zu ermitteln. Die Abweichung wird dann durch Proportion, Integration und Differenzierung gesteuert, um die Abweichung gegen Null tendieren zu lassen.
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 16

 
In unserem geschlossenen Drehzahlregelsystem wird nur die PI-Regelung verwendet, deshalb kann der PID-Regler mit der folgenden Formel vereinfacht werden:
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 17

 
Das Regelblockdiagramm ist dasselbe wie die Positionsformel.
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 18

 
In der obigen Abbildung können wir die Zielgeschwindigkeit im Allgemeinen durch Programmieren von Tasten oder Schaltern ändern. Wie im Abschnitt zum Encoder erwähnt, besteht die Geschwindigkeitsmessung darin, die Encoderdaten zu sammeln und sie regelmäßig über den Mikrocontroller zu löschen . Die Differenz zwischen Sollgeschwindigkeit und gemessener Geschwindigkeit ist die aktuelle Regelabweichung. Die Ausgabe wird zur Berechnung an den PID-Regler gesendet und anschließend wird der Motor über einen Leistungsverstärker angetrieben, um die Drehung des Motors zu steuern, die Abweichung zu verringern und schließlich die Zielgeschwindigkeit zu erreichen.
 
4.2.C-Sprachimplementierung
 
Die Strukturdefinition und die Elementinitialisierung des inkrementellen PID sind dieselben wie die des positionellen PID. Der in der Sprache C implementierte Code lautet wie folgt:
 
/**
  * @brief  速度PID算法实现
  * @param  actual_val:实际值
  * @note 无
  * @retval 通过PID计算后的输出
  */
float addPID_realize(PID *pid, float actual_val)
{
/*计算目标值与实际值的误差*/
pid->Error = pid->target_val - actual_val;
/*PID算法实现,照搬公式*/
pid->output_val += pid->Kp * (pid->Error - pid-> LastError) +
                  pid->Ki * pid->Error +
                  pid->Kd *(pid->Error -2*pid->LastError+pid->PrevError);
/*误差传递*/
pid-> PrevError = pid->LastError;
pid-> LastError = pid->Error;
/*返回当前实际值*/
return pid->output_val;
}
 
 
Die Funktionseingabeparameter sind der Drehzahlmesswert des Encoders und die Struktur der PID-Parameter. Der Rückgabewert ist die PWM der Motorsteuerung. Es ist ersichtlich, dass sich der inkrementelle PID nur auf die letzten drei Messwerte bezieht.
 
5. Kaskaden-PID
 
Kaskaden-PID bedeutet, dass zuerst der Positions-PID eingegeben wird, dann der Geschwindigkeits-PID durchlaufen wird und dieser schließlich ausgegeben wird.
 

Verwenden von stm32 zur Implementierung der PID-Steuerung eines Motors - Blog - Ampheo - 19

 
6. Die Rolle der P-, I- und D-Parameter
 
Die Leistungsindikatoren automatischer Steuerungssysteme umfassen hauptsächlich drei Aspekte: Stabilität, Geschwindigkeit und Genauigkeit.
 
Stabilität : Wenn das Kontrollsystem nach der Einwirkung externer Kräfte die kontrollierten Variablen mit der Zeit wachsen lässt und schließlich mit den gegebenen erwarteten Werten übereinstimmt, wird das System als stabil bezeichnet. Wir nennen dies im Allgemeinen Systemkonvergenz. Weicht die Regelgröße mit der Zeit immer stärker vom vorgegebenen Wert ab, spricht man von einem instabilen System. In diesem Fall spricht man allgemein von einer Systemdivergenz. Nur ein stabiles System kann die Aufgabe der automatischen Steuerung erfüllen, daher ist die Systemstabilität eine notwendige Voraussetzung, um den normalen Betrieb des Steuerungssystems sicherzustellen. Bei einem stabilen Regelsystem sollte die anfängliche Abweichung der Regelgröße vom vorgegebenen Wert mit der Zeit allmählich abnehmen und sich Null annähern.
 
Schnelligkeit : Schnelligkeit bezieht sich darauf, wie lange der dynamische Prozess des Systems dauert. Je kürzer die Prozesszeit, desto schneller ist das System; je länger die Prozesszeit, desto langsamer die Systemreaktion und desto schwieriger die Umsetzung sich schnell ändernder Befehlssignale. Stabilität und Geschwindigkeit spiegeln die Leistungsfähigkeit des Systems im Regelungsprozess wider. Während des Nachführvorgangs des Systems gilt: Je geringer die Abweichung der geregelten Größe vom vorgegebenen Wert und je kürzer die Abweichungszeit, desto höher ist die dynamische Genauigkeit des Systems.
 
Genauigkeit : Bezieht sich auf die Abweichung der kontrollierten Variable (oder Rückmeldung) vom vorgegebenen Wert, nachdem der dynamische Prozess des Systems beendet ist. Diese Abweichung ist der stationäre Fehler. Sie ist ein Indikator zur Messung der stationären Genauigkeit des Systems und spiegelt die Leistung im späteren Stadium des dynamischen Prozesses wider.
 
In praktischen Produktionsprojekten stellen unterschiedliche Steuerungssysteme unterschiedliche Anforderungen an die Reglerwirkung. Beispielsweise erfordern das Auswuchten von Autos und umgekehrten Pendeln eine sehr hohe Systemgeschwindigkeit. Eine zu langsame Reaktion kann dazu führen, dass das System die Kontrolle verliert. Das automatische Öffnungs- und Schließsystem von Türen und Fenstern in Smart Homes erfordert keine hohe Geschwindigkeit, stellt jedoch hohe Anforderungen an Stabilität und Genauigkeit, sodass Überschwingen und statische Fehler des Systems streng kontrolliert werden müssen.
 
Zusammenfassen
 
In diesem Artikel werden hauptsächlich die Positions-PID- und Inkremental-PID-Verfahren vorgestellt, die häufig bei der PID-Regelung von Motoren verwendet werden.
Ampheo