stm32单片机能写复杂控制算法么

stm32单片机能写复杂控制算法么,第1张

1.PID原理

1.1 P I D三个参数简单理解

1.2 P I D

1.3 PI PD PID适用系统

2.串级PID原理

3.PID代码

3.1 单级PID

3.1.1 初始化PID结构体

3.1.2 单级PID计算

3.1.3PID初始化

3.1.4 清空PID

3.2 串级PID

3.2.1 初始化串级PID结构体

3.2.2 串级PID计算

4.PID的使用

4.1 定义PID结构体并初始化

4.2 定义电机速度函数

4.3 在检测霍尔码盘时发送速度给电机

4.4 实验效果

1.PID原理

PID是什么,P,I,D的分别功能

你和PID调参大神之间,就差这篇文章!

1.1 P I D三个参数简单理解

P(比例): 简单来说,P就是凉了加热水,热了加凉水。比目标值小,我就增加一点,比目标值大,我就减小一点。(现在)

P可能出现的问题: 1.P太小,达到目标值需要花费很长的时间,而且会有稳态误差。2.P太大,达州悄锋到目标值时可能会一直震荡。

I(积分): 将一段时间内的误差累积起来加到输出上,可以消除历史误差对当前实际曲线的影响,运中提高系统的稳定性。 (过去)

I可能出现的问题: 1.I太小,可以消除稳态误差,但太慢了,对于某些需要很快响应的系统,显然不能满足要求。2.I太大,累计误差占比过大,就会出现抖动现象,难以收敛。

D(微分): 减小最大超调量。(下图中③就是最大超调量。) 可以有效减小震动的幅度。让曲线收敛更快 (未来)

D可能出现的问题: 1.D太小,作用小,时间长。2.D太大,为了减小超调量,补偿的过多,导致震荡很久。

在这里插入图片描述

1.2 P I D

先调P,逐渐增加P直到系统出现震荡,将当前值乘0.7就是较为合适的值。

再调I,将稳态误差逐渐降低。

后调D,将最大超调量降到最低。

1.3 PI PD PID适用系统

PI:响应速度要求不那么高的系统。

PD:大惯性系统。超调量太大。

PID:都可以。

网上将PID原理太多太多了,我的理解也都是参见上面的内容。认真看肯定有收获。

2.串级PID原理

【串级PID】浅谈串级PID作用及意义——快速理解串级PID结构优势

这里个人理解就是,单机PID就是稳定速度。而需要带位置和角度的就要用串级PID了。常用于平衡车,板球系统等。

而转速闭环称为串级PID的内环,位置 (角度) 闭环称为串级PID的外环。其实也很好理解,位移是速度的积分,只有速度慢慢稳定,位置才能确定。

3.PID代码

3.1 单级PID

3.1.1 初始化PID结构体册晌

typedef struct _PID

{

float kp,ki,kd

float error,lastError//误差、上次误差

float integral,maxIntegral//积分、积分限幅

float output,maxOutput//输出、输出限幅

}PID

1

2

3

4

5

6

7

1

2

3

4

5

6

7

3.1.2 单级PID计算

#define LIMIT(x,min,max) (x)=(((x)<=(min))?(min):(((x)>=(max))?(max):(x)))

//单级pid计算

void PID_SingleCalc(PID *pid,float reference,float feedback)

{

//更新数据

pid->lastError=pid->error

pid->error=reference-feedback

//计算微分

pid->output=(pid->error-pid->lastError)*pid->kd

//计算比例

pid->output+=pid->error*pid->kp

//计算积分

pid->integral+=pid->error*pid->ki

LIMIT(pid->integral,-pid->maxIntegral,pid->maxIntegral)//积分限幅

pid->output+=pid->integral

//输出限幅

LIMIT(pid->output,-pid->maxOutput,pid->maxOutput)

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

3.1.3PID初始化

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

}

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

3.1.4 清空PID

//清空一个pid的历史数据

void PID_Clear(PID *pid)

{

pid->error=0

pid->lastError=0

pid->integral=0

pid->output=0

}

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

3.2 串级PID

3.2.1 初始化串级PID结构体

typedef struct _CascadePID

{

PID inner//内环

PID outer//外环

float output//串级输出,等于inner.output

}CascadePID

1

2

3

4

5

6

1

2

3

4

5

6

3.2.2 串级PID计算

//串级pid计算

void PID_CascadeCalc(CascadePID *pid,float angleRef,float angleFdb,float speedFdb)

{

PID_SingleCalc(&pid->outer,angleRef,angleFdb)//计算外环(角度环)

PID_SingleCalc(&pid->inner,pid->outer.output,speedFdb)//计算内环(速度环)

pid->output=pid->inner.output

}

1

2

3

4

5

6

7

1

2

3

4

5

6

7

4.PID的使用

STM32应用(九)编码器及其测速原理、L298N电机驱动控制编码器电机

在这篇博客的配置下,只需要修改部分代码。以单级PID为例子。

4.1 定义PID结构体并初始化

PID pid

void Motor_Init(void)

{

PID_Init(&pid,10,0,0,1000,1000)

HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL) //开启编码器定时器

__HAL_TIM_ENABLE_IT(&htim1,TIM_IT_UPDATE) //开启编码器定时器更新中断,防溢出处理

HAL_TIM_Base_Start_IT(&htim6) //开启10ms定时器中断

HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1) //开启PWM

__HAL_TIM_SET_COUNTER(&htim1, 10000) //编码器定时器初始值设定为10000

motor.loopNum = 0 //防溢出

}

1

2

3

4

5

6

7

8

9

10

11

12

1

2

3

4

5

6

7

8

9

10

11

12

4.2 定义电机速度函数

void Motor_Send()

{

float output = 0

PID_SingleCalc(&pid, motor.targetSpeed, motor.speed)

output = pid.output

if(output >0) //正转

{

__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, (uint32_t)output)

IN1(1)

IN2(0)

}

else //反转

{

__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, (uint32_t)(-output))

IN1(0)

IN2(1)

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

4.3 在检测霍尔码盘时发送速度给电机

if(htim->Instance==htim6.Instance) //10ms中断

{

int16_t pluse = COUNTERNUM - RELOADVALUE/2

motor.totalAngle = pluse + motor.loopNum * RELOADVALUE/2

motor.speed = (float)(motor.totalAngle - motor.lastAngle)/(4*13*RR)*6000 //进行速度计算,根据前文所说的,4倍频,编码器13位,减速比30,再乘以6000即为每分钟输出轴多少转

motor.lastAngle = motor.totalAngle//更新转过的圈数

Motor_Send()//发送速度

}

根据我的灶咐认识,不可喊弊以,AVR和STM32不兼容。AVR是Atmel公司开发的8位微控制器,而STM32是STMicroelectronics公司开发的32位微控制器。因此,AVR代码不能在隐渗纯STM32上运行。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12556015.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-26
下一篇 2023-05-26

发表评论

登录后才能评论

评论列表(0条)

保存