【嵌入式PID温度控制系统】Part 5:调节增益系数

本文目标是理解比例、积分和微分增益对PID控制系统性能的影响。为方便改变增益值,为GUI添加新功能,有P、I和D增益的文本输入框,增益值通过USB命令发送到EFM8,限制在0 - 255的整数。还可参考相关Scilab脚本及指定链接内容。

GUI升级

我们在本文中的目标是获得对比例、积分和微分增益如何影响PID控制系统性能的可靠概念性理解。如果我们有一种方便的方法来改变增益值,这将会容易得多。因此,我们需要为GUI添加一些新功能:

如您所见,我们现在有P、I和D增益的文本输入框。这些值以与设定值相同的方式发送到EFM8,即通过在每次控制运行开始时发送的USB命令(当您单击“激活PID控制”时“控制运行”开始,并在您单击时结束“停止PID控制“;显示测量温度和设定点线的图表在新控制运行开始时被清除。增益值限制在0到255范围内的整数。让我们快速查看与此新功能相关的Scilab脚本的两个部分。

这里写图片描述

更多内容请参考以下内容:https://www.yiboard.com/thread-893-1-1.html

#include "stm32f10x.h" #include "mpu6050.h" #include "Delay.h" #include "OLED.h" #include <math.h> #define MPU6050_GYRO_ZOUT_H 0x47 #define MPU6050_GYRO_ZOUT_L 0x48 // ???? float lingpiao = 0; // ??????? volatile float yaw = 0; // ??? (0~360?) float target_yaw = 0.0f; // ????? volatile uint32_t system_tick = 0; // ??HAL_GetTick???????? // ???PID??? typedef struct { // PID?? float Kp; float Ki; float Kd; // ???? float last_error; // ????? e(k-1) float prev_error; // ????? e(k-2) // ???? float max_output; // ?????? float min_output; // ?????? // ???? float output; // ?????? } PID_IncTypeDef; PID_IncTypeDef pid; // PID????? /** * @brief PID????? */ void PID_IncInit(PID_IncTypeDef *pid, float kp, float ki, float kd, float min_out, float max_out) { pid->Kp = kp; pid->Ki = ki; pid->Kd = kd; pid->min_output = min_out; pid->max_output = max_out; // ?????? pid->last_error = 0; pid->prev_error = 0; pid->output = 0; } /** * @brief ???PID?? * @param target: ??? * @param feedback: ??? * @retval ?????? */ float PID_IncCalculate(PID_IncTypeDef *pid, float target, float feedback) { float error, p_out, i_out, d_out; float delta_output; // 1. ?????? (??????) error = target - feedback; // ??????[-180, 180]?? if (error > 180.0f) error -= 360.0f; else if (error < -180.0f) error += 360.0f; // 2. ??P?? p_out = pid->Kp * (error - pid->last_error); // 3. ??I?? i_out = pid->Ki * error; // 4. ??D?? d_out = pid->Kd * (error - 2 * pid->last_error + pid->prev_error); // 5. ??????? delta_output = p_out + i_out + d_out; // 6. ?????? pid->prev_error = pid->last_error; pid->last_error = error; // 7. ???? if (delta_output > pid->max_output) delta_output = pid->max_output; else if (delta_output < pid->min_output) delta_output = pid->min_output; // 8. ????? pid->output += delta_output; // ????? if (pid->output > pid->max_output) pid->output = pid->max_output; else if (pid->output < pid->min_output) pid->output = pid->min_output; return pid->output; } void Timer_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_TimeBaseInitStruct.TIM_Period = 5000 - 1; // 5ms?? TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1; // 72MHz/72 = 1MHz TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); NVIC_EnableIRQ(TIM2_IRQn); TIM_Cmd(TIM2, ENABLE); } int16_t MPU6050_GetGyroZ(void) { uint8_t high = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H); uint8_t low = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L); return (int16_t)((high << 8) | low); } void TIM2_IRQHandler(void) { static float gyro_z_prev = 0; if (TIM_GetITStatus(TIM2, TIM_IT_Update)) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); system_tick++; float gyro_z_current = (float)(MPU6050_GetGyroZ() - lingpiao) / 16.4f; float delta_yaw = (gyro_z_prev + gyro_z_current) * 0.0025f * 0.5f; gyro_z_prev = gyro_z_current; yaw += delta_yaw; yaw = fmod(yaw, 360.0f); if (yaw < 0) yaw += 360.0f; float control_output = PID_IncCalculate(&pid, target_yaw, yaw); } } uint32_t Get_Tick(void) { return system_tick * 5; } int main(void) { Delay_init(); Delay_ms(500); MPU6050_Init(); OLED_Init(); Timer_Init(); PID_IncInit(&pid, 1.0f, 0.05f, 0.0f, -100.0f, 100.0f); int32_t sum = 0; for (int i = 0; i < 100; i++) { sum += MPU6050_GetGyroZ(); Delay_ms(10); } lingpiao = sum / 100.0f; OLED_ShowString(1, 1, "Yaw:"); OLED_ShowString(2, 1, "Tar:"); OLED_ShowString(3, 1, "PID:"); target_yaw = 0.0f; while (1) { int integer_part = (int)yaw; int decimal_part = (int)((yaw - integer_part) * 10); OLED_ShowNum(1, 6, integer_part, 3); OLED_ShowChar(1, 9, '.'); OLED_ShowNum(1, 10, decimal_part, 1); OLED_ShowString(1, 12, "deg"); OLED_ShowNum(2, 6, (int)target_yaw, 3); OLED_ShowString(2, 9, "deg"); OLED_ShowNum(3, 6, (int)pid.output, 3); static uint32_t last_change = 0; uint32_t current_tick = Get_Tick(); if (current_tick - last_change > 5000) { last_change = current_tick; target_yaw = (target_yaw == 0.0f) ? 90.0f : 0.0f; } Delay_ms(100); } } 让陀螺仪转动更加精确,并且让舵机转动
最新发布
08-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值