基于位置式PID算法調節PWM占空比實現電機轉速控制
一、系統架構
1. 硬件組成
| 模塊 | 核心組件 | 功能說明 |
|---|---|---|
| 主控單元 | STM32F407(TIM1+TIM2) | PWM生成與PID運算 |
| 電機驅動 | TB6612(PWMA/PWMB) | PWM輸入控制電機轉速 |
| 反饋裝置 | 霍爾編碼器(500線) | 轉速檢測(2000脈沖/轉) |
| 電源模塊 | 12V/2A DC電源 | 電機供電 |
2. 電路連接
STM32引腳連接 | 功能說明
----------------------------|----------------------------
TIM1_CH1 (PA8) | 電機PWM輸出
TIM2_CH1 (PA0) | 編碼器A相信號輸入
TIM2_CH2 (PA1) | 編碼器B相信號輸入
PB6 (BOOT0) | 電機方向控制
3.3V | 編碼器供電
GND | 公共地
二、PID算法實現
1. 位置式PID公式
\(u(k)=Kpe(k)+Kii=0∑ke(i)+Kd[e(k)?e(k?1)]\)
- 輸入變量:目標轉速(Setpoint)與實際轉速(Feedback)的差值
- 輸出變量:PWM占空比(0-100%)
2. 關鍵參數定義
typedef struct {
float Kp; // 比例系數(建議初始值2.0-5.0)
float Ki; // 積分系數(建議初始值0.1-0.5)
float Kd; // 微分系數(建議初始值0.01-0.1)
float integral;// 積分項累加值
float prev_err;// 上一次誤差
float max_out; // 輸出上限(PWM最大占空比)
} PID_HandleTypeDef;
3. PID初始化函數
void PID_Init(PID_HandleTypeDef *pid, float Kp, float Ki, float Kd) {
pid->Kp = Kp;
pid->Ki = Ki;
pid->Kd = Kd;
pid->integral = 0.0f;
pid->prev_err = 0.0f;
pid->max_out = 100.0f; // PWM占空比上限
}
4. PID計算函數
float PID_Compute(PID_HandleTypeDef *pid, float setpoint, float feedback, float dt) {
float error = setpoint - feedback;
// 比例項
float Pout = pid->Kp * error;
// 積分項
pid->integral += error * dt;
float Iout = pid->Ki * pid->integral;
// 微分項
float derivative = (error - pid->prev_err) / dt;
float Dout = pid->Kd * derivative;
// 計算總輸出
float output = Pout + Iout + Dout;
// 輸出限幅
if(output > pid->max_out) {
pid->integral -= error * dt; // 防止積分飽和
output = pid->max_out;
} else if(output < 0) {
output = 0;
}
pid->prev_err = error;
return output;
}
三、硬件驅動實現
1. PWM配置(STM32 HAL庫)
void MX_TIM1_Init(void) {
TIM_HandleTypeDef htim1;
htim1.Instance = TIM1;
htim1.Init.Prescaler = 84-1; // 84MHz / 84 = 1MHz
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 1000-1; // 1kHz PWM頻率
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&htim1);
// 配置通道1
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0; // 初始占空比0%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}
2. 編碼器測速
volatile uint32_t encoder_count = 0;
volatile float motor_speed = 0.0f;
// 編碼器中斷處理(TIM2)
void TIM2_IRQHandler(void) {
if(TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) {
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_SET) {
encoder_count++;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
}
}
// 計算轉速(每100ms更新一次)
void Calc_Speed() {
static uint32_t last_count = 0;
static float rpm = 0.0f;
motor_speed = (encoder_count - last_count) * 60.0f / 0.1f; // 500線編碼器
last_count = encoder_count;
}
四、主控制循環
int main(void) {
HAL_Init();
SystemClock_Config();
MX_TIM1_Init(); // PWM初始化
MX_TIM2_Init(); // 編碼器初始化
PID_HandleTypeDef motor_pid;
PID_Init(&motor_pid, 2.5f, 0.2f, 0.05f); // 初始參數
while(1) {
Calc_Speed(); // 更新轉速測量值
float duty = PID_Compute(&motor_pid, 1000.0f, motor_speed, 0.001f); // 1kHz采樣
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty); // 更新占空比
HAL_Delay(1);
}
}
參考代碼 位置式PID調節PWM占空比控制電動機轉速 www.youwenfan.com/contentcnk/70961.html
五、參數整定方法
1. Ziegler-Nichols法
| 步驟 | 操作 | 結果記錄 |
|---|---|---|
| 1 | 關閉I/D項(Ki=0, Kd=0) | 基準Kp值 |
| 2 | 逐漸增大Kp至系統持續振蕩 | 記錄Ku和Tu |
| 3 | 計算PID參數: | |
| Kp = 0.6*Ku | ||
| Ki = 1.2*Ku/Tu | ||
| Kd = 0.075KuTu |
2. 實際調試建議
- 初始參數:Kp=2.0, Ki=0.1, Kd=0.01
- 調整順序:先調P→再調I→最后調D
- 典型調試現象: Kp過小:響應慢,穩態誤差大 Kp過大:超調嚴重,振蕩 Ki過大:積分飽和,爬行現象 Kd過大:噪聲敏感,產生振蕩
浙公網安備 33010602011771號