备赛电赛学习软件篇(二):PID(2)持续更新中.....

注:本篇笔记承接备赛电赛学习软件篇(二):PID(1),且本笔记主要是代码部分

一、PID的基本实现

1、位置型PID

结构体部分 

/*定义结构体和公用体*/
typedef struct
{
  float setpoint;       //设定值
  float proportiongain;     //比例系数
  float integralgain;      //积分系数
  float derivativegain;    //微分系数
  float lasterror;     //前一拍偏差
  float result; //输出值
  float integral;//积分值
}PID;

接下来实现PID控制器:

void PIDRegulation(PID *vPID, float processValue)
{
  float thisError;
  thisError=vPID->setpoint-processValue;
  vPID->integral+=thisError;
  vPID->result=vPID->proportiongain*thisError+vPID->integralgain*vPID->integral+vPID->derivativegain*(thisError-vPID->lasterror);
  vPID->lasterror=thisError;
}

2、增量型PID

 结构体部分 

/*定义结构体和公用体*/
typedef struct
{
  float setpoint;       //设定值
  float proportiongain;     //比例系数
  float integralgain;      //积分系数
  float derivativegain;    //微分系数
  float lasterror;     //前一拍偏差
  float preerror;     //前两拍偏差
  float deadband;     //死区
  float result; //输出值
}PID;

接下来实现PID控制器:

void PIDRegulation(PID *vPID, float processValue)
{
  float thisError;
  float increment;
  float pError,dError,iError;
 
  thisError=vPID->setpoint-processValue; //得到偏差值
  pError=thisError-vPID->lasterror;
  iError=thisError;
  dError=thisError-2*(vPID->lasterror)+vPID->preerror;
  increment=vPID->proportiongain*pError+vPID->integralgain*iError+vPID->derivativegain*dError;   //增量计算
 
  vPID->preerror=vPID->lasterror;  //存放偏差用于下次运算
  vPID->lasterror=thisError;
  vPID->result+=increment;
}

二、积分分离

1、位置型PID

结构体部分:

/*定义结构体和公用体*/
typedef struct
{
  floatsetpoint;       //设定值
  floatproportiongain;     //比例系数
  floatintegralgain;      //积分系数
  floatderivativegain;    //微分系数
  floatlasterror;     //前一拍偏差
  floatresult; //输出值
  floatintegral;//积分值
  float epsilon; //偏差检测阈值
}PID;

接下来实现PID控制器:

void PIDRegulation(PID *vPID, float processValue)
{
  floatthisError;
 thisError=vPID->setpoint-processValue;
 vPID->integral+=thisError;
  uint16_tbeta= BetaGeneration(error,vPID->epsilon);
 
  if(beta==0)
{
 vPID->result=vPID->proportiongain*thisError+vPID->derivativegain*(thisError-vPID->lasterror);
}
else
{
vPID->result=vPID->proportiongain*thisError+vPID->integralgain*vPID->integral+vPID->derivativegain*(thisError-vPID->lasterror);
}
 
 vPID->lasterror=thisError;
 
}
static uint16_t BetaGeneration(float error,float epsilon)
{
  uint16_t beta=0;
 
  if(abs(error)<= epsilon)
{
  beta=1;
}
 
return beta;
 
}

2、增量式PID

结构体

/*定义结构体和公用体*/
typedef struct
{
  floatsetpoint;       //设定值
  floatproportiongain;     //比例系数
  floatintegralgain;      //积分系数
  floatderivativegain;    //微分系数
  floatlasterror;     //前一拍偏差
  floatpreerror;     //前两拍偏差
  floatdeadband;     //死区
  floatresult; //输出值
  float epsilon; //偏差检测阈值
}PID;

接下来实现PID控制器:

void PIDRegulation(PID *vPID, float processValue)
{
  floatthisError;
  floatincrement;
  floatpError,dError,iError;
 
 thisError=vPID->setpoint-processValue; //得到偏差值
 pError=thisError-vPID->lasterror;
 iError=thisError;
 dError=thisError-2*(vPID->lasterror)+vPID->preerror;
  uint16_tbeta= BetaGeneration(error,vPID->epsilon);
 
  if(beta==0)
{
increment=vPID->proportiongain*pError+vPID->derivativegain*dError;   //增量计算
}
else
{
increment=vPID->proportiongain*pError+vPID->integralgain*iError+vPID->derivativegain*dError;   //增量计算
}
 vPID->preerror=vPID->lasterror; //存放偏差用于下次运算
 vPID->lasterror=thisError;
 vPID->result+=increment;
}
static uint16_t BetaGeneration(float error,float epsilon)
{
  uint16_t beta=0;
 
  if(abs(error)<= epsilon)
{
  beta=1;
}
 
return beta;
 
}

三、抗积分饱和

1、思想

所谓积分饱和就是指系统存在一个方向的偏差,PID控制器的输出由于积分作用的不断累加而扩大,从而导致控制器输出不断增大超出正常范围进入饱和区。当系统出现反响的偏差时,需要首先从饱和区退出,而不能对反向的偏差进行快速的响应。

为了解决积分饱和的问题,人们引入了抗积分饱和的PID算法。所谓抗积分饱和算法,其思路是在计算U(k)的时候,先判断上一时刻的控制量U(k-1)是否已经超出了限制范围。若U(k-1)>Umax,则只累加负偏差;若U(k-1)<Umin,则只累加正偏差。从而避免控制量长时间停留在饱和区。
 

2、流程图

 3、代码部分

3.1位置型

结构体

/*定义结构体和公用体*/
typedef struct
{
  floatsetpoint;       //设定值
  floatproportiongain;     //比例系数
  floatintegralgain;      //积分系数
  floatderivativegain;    //微分系数
  floatlasterror;     //前一拍偏差
  floatresult; //输出值
  floatintegral;//积分值
  floatmaximum;//最大值
  floatminimum;//最小值
}PID;

PID控制器

void PIDRegulation(PID *vPID, float processValue)
{
  floatthisError;
 thisError=vPID->setpoint-processValue;
 if(vPID->result>vPID->maximum)
  {
   if(thisError<=0)
    {
     vPID->integral+=thisError;
    }
  }
  elseif(vPID->result<vPID->minimum)
  {
   if(thisError>=0)
    {
     vPID->integral+=thisError;
    }
  }
  else
  {
   vPID->integral+=thisError;
  }
 
 vPID->result=vPID->proportiongain*thisError+vPID->integralgain*vPID->integral+vPID->derivativegain*(thisError-vPID->lasterror);
 vPID->lasterror=thisError;
}

3.2增量式

结构体

/*定义结构体和公用体*/
typedef struct
{
  floatsetpoint;       //设定值
  floatproportiongain;     //比例系数
  floatintegralgain;      //积分系数
  floatderivativegain;    //微分系数
  floatlasterror;     //前一拍偏差
  floatpreerror;     //前两拍偏差
  floatdeadband;     //死区
  floatresult; //输出值
  floatmaximum;//最大值
  floatminimum;//最小值
}PID;

PID控制器

void PIDRegulation(PID *vPID, float processValue)
{
  floatthisError;
  floatincrement;
  floatpError,dError,iError;
 
 thisError=vPID->setpoint-processValue; //得到偏差值
 pError=thisError-vPID->lasterror;
  iError=0;
 dError=thisError-2*(vPID->lasterror)+vPID->preerror;
 
 if(vPID->result>vPID->maximum)
  {
   if(thisError<=0)
    {
     iError=thisError;
    }
  }
  elseif(vPID->result<vPID->minimum)
  {
   if(thisError>=0)
    {
     iError=thisError;
    }
  }
  else
  {
   iError=thisError;
  }
 
 increment=vPID->proportiongain*pError+vPID->integralgain*iError+vPID->derivativegain*dError;   //增量计算
 
 vPID->preerror=vPID->lasterror; //存放偏差用于下次运算
 vPID->lasterror=thisError;
 vPID->result+=increment;
}

### PWM在控制程序中的设计与实现 PWM(Pulse Width Modulation),即脉冲宽度调制技术,在子竞项目中被广泛应用于机驱动、LED亮度调节以及精密压源的设计等领域。以下是关于如何基于PWM设计和实现控制程序流程图的相关内容。 #### 1. PWM基本原理及其应用 PWM是一种通过对逆变路开关器件的通断进行控制的技术,从而使得输出端获得一系列幅值相等的脉冲信号[^1]。这些脉冲信号可以通过调整其周期和占空比来精确地控制目标设的行为。例如,在控制系统中,改变PWM的占空比可以直接影响机转速;而在模拟信号生成领域,则可通过DAC转换将PWM信号转化为连续变化的压信号[^2]。 #### 2.控制器上的PWM功能实现 以STM32系列微控制器为例,其实现过程通常涉及以下几个方面: - **时钟系统的配置**:确保微控制器能够稳定运行在其预期的工作频率下。 - **外设初始化**:这一步骤包括设置GPIO引脚的功能模式、配置定时器参数以及启用相应的DAC通道等功能模块。 具体到代码层面,下面是一个简单的初始化示例: ```c // 配置TIM2作为PWM发生器 void TIM2_PWM_Init(void){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = 99; // 自动重装载寄存器周期值ARR TIM_TimeBaseStructure.TIM_Prescaler = 71; // 预分频系数psc=71 TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High ; TIM_OCInitStructure.TIM_Pulse = 49; // CCR初始值 TIM_OC1Init(TIM2,&TIM_OCInitStructure); TIM_Cmd(TIM2,ENABLE); } ``` 此函数完成了对定时器TIM2的基础设定,并启用了第一个比较输出单元用于生成PWM波形[^2]。 #### 3. 控制逻辑描述——流程图绘制建议 针对含有PWM组件的整体系统而言,构建清晰合理的软件架构至关重要。一般情况下,整个项目的执行顺序可概括如下几个阶段: - 初始化硬件资源; - 设置默认工作状态下的各项参数; - 进入循环监听外部事件并作出响应; - 动态更新PWM相关属性直至满足特定条件为止。 对于上述各环节的具体表现形式,推荐采用标准框图表示法予以展现。比如,“开始→初始化→等待触发→计算新PWM值→施加更改→结束”这样的结构就非常适合用来表达此类实时反馈型应用程序的核心思路。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘子ゆ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值