2.11 PID控制算法(三)----PID结果与实际值的关联

2023-11-14

1、讲解

1、AD采样,经过PID计算的值,怎么和PWM对应起来?
2、电机编码采样,经过PID计算的值,怎么与速度对应起来?

这个简单,PID控制原理就是输出一个控制量,然后检测反馈,由反馈得到的数据计算当前实际输出是多少,由这个实际输出和目标输出得到差值,最后由这个差值计算一个新的输出控制量。
举例(数据都是乱拟的,只为好计算):假设你的PWM是用来控制电机速度的,0%占空比对应的电机速度是0r,100%占空比对应的电机速度是100r。你目标电机速度是50r,那么调控步骤如下:

  1. 输出50%占空比的PWM
  2. AD采样并计算当前电机速度,假设计算得到的当前实际电机速度是40r,比目标速度50r差10r,这个10r送到PID计算得到一个增量结果,假设结果是5r
  3. 由5r计算对应的PWM占空比,即5%
  4. 更新PWM输出占空比,就是:50%+5%=55%,返回到第1步
    我个人理解,它们之间实际上就是一个比例关系。

2、举例1

我们来分析一个例子:步进电机PID速度闭环控制,它原理:预先设置好需要达到的速度,然后每隔一段时间读取编码器的值反馈当前速度,经过PID计算慢慢到达设定的速度。

#define FEEDBACK_CONST                        (SPR/ENCODER_SPR)   //编码器和步进电机驱动器的比值

typedef struct 
{
  __IO float SetPoint;    // 目标值  单位:mm/s
  __IO int LastError;     // 前一次误差    
  __IO int PrevError;     // 前两次误差
  __IO long SumError;     // 累计误差
  __IO double Proportion; // Kp系数
  __IO double Integral;   // Ki系数
  __IO double Derivative; // Kd系数
}PID_Typedef;

__IO PID_Typedef vPID;
 Vel_Target = (vPID.SetPoint*P_PERIOD);//每单位采样周期内的脉冲数(频率)
 
 
/**
  * 函数功能:增量式PID速度环计算
  * 输入参数:NextPoint     由编码器得到的速度值 
  *           TargetVal    目标值
  * 返 回 值:经过PID运算得到的增量值
  * 说    明:增量式 PID 速度环控制设计,计算得到的结果仍然是速度值
  */
float IncPIDCalc(__IO float NextPoint,__IO float TargetVal)    //临时变量,期望值 
{
  __IO float iError = 0,iIncpid = 0;                    //当前误差
  iError = TargetVal - NextPoint;                  // 增量计算
//  if((iError<0.5f)&&(iError>-0.5f))
//    iError = 0;                                    // |e| < 0.5,不做调整
  
  iIncpid=(vPID.Proportion * iError)               // E[k]项
              -(vPID.Integral * vPID.LastError)    // E[k-1]项
              +(vPID.Derivative * vPID.PrevError); // E[k-2]项
  
  vPID.PrevError=vPID.LastError;                   // 存储误差,用于下次计算
  vPID.LastError = iError;
  return(iIncpid);                                 // 返回增量值
}

/**
  * 函数功能: 系统滴答定时器中断回调函数
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明: 每发生一次滴答定时器中断进入该回调函数一次
  */
void HAL_SYSTICK_Callback(void)
{
  __IO static uint16_t time_count = 0; // 时间计数,每1ms增加一(与滴答定时器频率有关)
  __IO static int32_t Last_CaptureNumber=0;       // 上一次捕获值
  // 每1ms自动增一
  time_count++; 
  if(Start_Flag == ENABLE)
  {
    if(time_count >= SAMPLING_PERIOD)// 20ms控制周期
    {
      time_count = 0;
      //获得编码器的脉冲值
      CaptureNumber = OverflowCount*65536 + __HAL_TIM_GET_COUNTER(&htimx_Encoder);
      //M法 测速度
      MSF = CaptureNumber - Last_CaptureNumber;
      Last_CaptureNumber = CaptureNumber;
      MSF = abs(MSF);
      
      Exp_Val += IncPIDCalc((float)MSF,Vel_Target);
	  //编码器输出期望值
      Exp_Val = abs(Exp_Val);
      /* 经过PID计算得到的结果是编码器的输出期望值的增量,
         需要转换为步进电机的控制量(频率值),这里乘上一个系数6400/2400
      */
      //乘上一个系数,6400/2400,将PID计算结果转换为步进电机的频率(速度)
      STEPMOTOR_Motion_Ctrl(MotorDir,Exp_Val*FEEDBACK_CONST);
    }
  }
}

/**
  * 函数功能: 步进电机运动控制
  * 输入参数: Dir:步进电机运动方向 0:反转 1正转
  *           Frequency:步进电机频率,0:停止
  * 返 回 值: void
  * 说    明: 无
  */
void STEPMOTOR_Motion_Ctrl(uint8_t Dir , float Frequency)
{
  uint16_t Step_Delay = 0;  //步进延时

  if(Frequency == 0)
    STEPMOTOR_OUTPUT_DISABLE();
  else
  {
    if(Dir==MOTOR_DIR_CCW)
    {
      STEPMOTOR_DIR_REVERSAL();
    }
    else STEPMOTOR_DIR_FORWARD();//方向控制
    /*
      步进电机速度由定时器输出脉冲频率(f)决定,
        f = c/F;c是计数器的计数值,F是定时器频率
      推导过程:(T是定时器输出脉冲周期)
        T=c*t => T=c*F => f = 1/T = F/c;
    
    */
    Step_Delay = (uint16_t)(FREQ_UINT/Frequency);
    
    Toggle_Pulse = Step_Delay>>1;//算出来的结果是周期,这里除以2,半周期翻转一次
  }
}

我们来分析一下它PID是怎么PID输出结果与速度量的关系:
从上面我可以知道,PID算法
输入参数:
1、MSF :单位采样周期内(20mS)编码器的值。
2、Vel_Target:每单位采样周期内编码器的脉冲数(频率);它由SetPoint(标 值 单位:mm/s),经过一定的计算而来。
输出参数:
1、编码器的输出期望值

步进电机的频率(速度)与PID结果的关系:Exp_Val*FEEDBACK_CONST ;从整个公式我们可发现,它们仅仅一个比例系数而已。

3、举例2

再举一例PWM控制温度

int iDataSigma
void PIDCalc(uint32_t Channel,int16_t set_temp,int16_t actualTemp)//温度放大100倍
{
	int  En,out_temp,controlOut; 

	En= set_temp-actualTemp;  //本次偏差
	if(abs(En) > 500)         //积分分离
	{
		index=0;
	}
	else
	{
		index=1;
		iDataSigma += En*iData; //历史偏差总和
	}
//	out_temp = Kp*En+index*Ki*iDataSigma; //P+I
	out_temp = Kp*En+index*Ki*iDataSigma+Kd(En-En_1);//P+I+D
	En_1 = En;
			 
	controlOut=_TIM3_ARR/500*out_temp;
	
	if (controlOut <= 0)
		bsp_SetPWM_TEMP_CCRx(Channel,0); //停止加热
	else
		bsp_SetPWM_TEMP_CCRx(Channel,abs(controlOut));//加热	
}

//占空比
 void bsp_SetPWM_TEMP_CCRx(uint32_t Channel,uint16_t duty)
{
	if(duty <= _TIM3_ARR)
	{
		__HAL_TIM_SET_COMPARE(&htim3, Channel, duty);		
	}
}

//STM32 PWM_1模式 初始化设置PWM周期
bsp_SetPWM_TEMP_ARR(_TIM3_ARR);		                 //周期 T=1000uS  _TIM3_ARR 

4、举例3

举例三:PWM控温

//定时器装载1000,相当于1mS
void PID_Init1(void)
{
    spid1.Uplimit = 999;
    spid1.Downlimit = 0;
    spid1.Kp = 20;
    spid1.Ki = 0.1;
    spid1.Kd = 0;
    spid1.e_0 = 0;
    spid1.e_1 = 0;
    spid1.e_2 = 0;
    spid1.ei = 0;
    spid1.ed = 0;
}
void PID_Init2(void)
{
    spid2.Uplimit = 999;
    spid2.Downlimit = 0;
    spid2.Kp = 20;
    spid2.Ki = 0.1;
    spid2.Kd = 0;
    spid2.e_0 = 0;
    spid2.e_1 = 0;
    spid2.e_2 = 0;
    spid2.ei = 0;
    spid2.ed = 0;
}
//位置式
u32 pid_calc(sPID *pid,float target ,float feedback)  
{     
    pid->target = target;
    pid->feedback = feedback;
    pid->e_0 = target - feedback;
    #if 0 
    if(pid->Ki*pid->ei + pid->Kp*pid->e_0 <= pid->Uplimit)//限制累积值
        pid->ei += pid->e_0;  
    else if(pid->e_0 < 0)
       pid->ei += pid->e_0;
    else;
    #endif
    pid->ei += pid->e_0;
    if(pid->Ki*pid->ei > 500)//限制累积值
    {
        pid->ei = 500/pid->Ki;
    }
    if(pid->ei < (-100))
    {
        pid->ei = (-100);
    }
#if 0
    pid->ed = pid->e_0 - 2*pid->e_1 + pid->e_2;  
 #else 
    pid->ed = pid->e_1 - pid->e_0;  //个人以为这个才是对的 
 #endif   
    pid->Out = pid->Kp*pid->e_0 + pid->Ki*pid->ei + pid->Kd*pid->ed;  

    if(pid->Out > pid->Uplimit)
    {
        pid->Out = pid->Uplimit;
    }
    else if(pid->Out < pid->Downlimit)
    {
        pid->Out = pid->Downlimit;
    }
    else
    {}
    
    pid->e_2 = pid->e_1;  
    pid->e_1 = pid->e_0;  
    
    return (u32)pid->Out;     
}

 pid_calc(&spid1,(float)TempCtrler[PURE_TEMP_LYSIS].target,(float)TempForCal[PURE_TEMP_LYSIS]);
 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,spid1.Out);

5、调试PID参数

调试PID参数链接
在这里插入图片描述

3.1 PID参数的整定原则

U(t)=P*[e(t)+ 1/Ti∫0te(t)dt+Tdde(t)/dt]
a.在输出不振荡时,增大比例增益P。(即增开Kp)
b.在输出不振荡时,减小积分时间常数Ti。(即增大Ki)
c.在输出不振荡时,增大微分时间常数Td。(即减小Kd)

P环很好理解,我们将误差乘以P值加在执行机构上面,当误差越小时P环所得值也就越小,给到执行机构的值也就越小,执行机构反应也就越慢,很符合这种闭环反馈的思想。但是当有一种情况,误差很小的时候P环得出的值给到执行机构上面不足以驱动执行机构工作,这时系统距离期望值仍有一段距离,该距离便被称为静差。

I环的作用是对过去状态的累加,本质上是对误差的积分,当系统存在静差时,I环会持续累加静差值,直到累加值大到足以驱动执行机构工作。这是I环的优点,可以有效地处理静差。但是I环本质上是对过去状态的处理,所以加上I环以后整个系统会变得有些不可控制,这里可以采用积分分离式的思想,只有当误差小于一定范围才开始进行进行误差的累加。如果是对稳定性要求比较高的系统,比如平衡小车直立环,就尽量不要用I环,单PD控制器控制即可。

D环,这个环比较的神奇,它可以预测将来,本质上是对误差的微分。也可以理解成对系统的阻尼,打个比方,在一个理想的环境下有个单摆一直在摆动,它摆动的波形是个正弦波形。如果不加阻尼那么它便可以一直摆动,但是现实中总会有各种各样的阻尼作用迫使单摆运动停下来。D环起的就是这个作用。D环一般运用在角度环比较多,因为你不可以进入弯道才想到转弯,而是在进入弯道之前就要有这个转弯的意识。做智能车的小伙伴们注意了!!

下面式复制别人图片,讲的挺好的,链接如下:
PID参数整定

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2.11 PID控制算法(三)----PID结果与实际值的关联 的相关文章

  • 在地址“0xXXXXXX”处中断,没有可用的调试信息,或在程序代码之外

    配置 使用 Nucleo L476RG 使用 GNU ARM Eclipse 我从 STM32CubeMX 生成了一个极简代码 我已经在我的板载 ST Link 中刷新了 J link 驱动程序 一直在尝试为我的代码运行调试器 但我的程序计
  • 以字符串形式接收数字(uart)

    我正在尝试通过 uart 接收一个包装为字符串的数字 我发送数字 1000 所以我得到 4 个字节 空字符 但是 当我使用 atoi 将数组转换为数字并将整数与 1000 进行比较时 我并不总是得到正确的数字 这是我用于接收号码的中断处理函
  • CMSIS 库是否应该包含在版本控制中? [复制]

    这个问题在这里已经有答案了 通常 我曾经在版本控制中包含芯片供应商 ST 提供的设备特定标头和源以及 CMSIS Core 标头 数量不多 也没有更新的习惯 我使用STM32微控制器 但我不使用立方体框架 or the 标准外设库 最近 我
  • 当数据大小较小时,内存到内存 DMA 传输是否需要权衡?

    我正在学习 STM32 F4 微控制器 我正在尝试找出使用 DMA 的限制 根据我的理解和研究 我知道如果数据量较小 即设备使用DMA生成或消耗少量数据 则开销会增加 因为DMA传输需要DMA控制器执行操作 从而不必要地增加系统成本 我做了
  • 139-基于stm32单片机老人居家监护报警系统Proteus仿真+源程序

    资料编号 139 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 MQ4传感器 电位器模拟 MQ2传感器 电位器模拟 蜂鸣器 电机 制作一个基于stm32单片机老人居家监护报警系统Proteus仿真 2 通过MQ2传
  • 137-基于stm32单片机智能保温杯控制装置Proteus仿真+源程序

    资料编号 137 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DS18B20传感器 电机 制作一个基于stm32单片机智能保温杯控制装置Proteus仿真 2 通过DS18b20传感器检测当前保温杯水的温度 并且
  • 135-基于stm32单片机超声波非接触式感应水龙头控制系统Proteus仿真+源程序

    资料编号 135 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 电机 超声波传感器 制作一个基于stm32单片机超声波非接触式感应水龙头控制系统Proteus仿真 2 通过DHT11传感器检测当前
  • Push_back() 导致程序在进入 main() 之前停止

    我正在为我的 STM32F3 Discovery 板使用 C 进行开发 并使用 std deque 作为队列 在尝试调试我的代码 直接在带有 ST link 的设备上或在模拟器中 后 代码最终在 main 中输入我的代码之前在断点处停止 然
  • STM32超声波——HC_SR04

    文章目录 一 超声波图片 二 时序图 三 超声波流程 四 单位换算 五 取余计算 六 换算距离 七 超声波代码 一 超声波图片 测量距离 2cm 400cm 二 时序图 1 以下时序图要先提供一个至少10us的脉冲触发信号 告诉单片机我准备
  • 毕业设计 江科大STM32的智能温室控制蓝牙声光报警APP系统设计

    基于STM32的智能温室控制蓝牙声光报警APP系统设计 1 项目简介 1 1 系统构成 1 2 系统功能 2 部分电路设计 2 1 stm32f103c8t6单片机最小系统电路设计 2 2 LCD1602液晶显示电路设计 2 2 风
  • STM32F103概要

    The STM32F103x4 STM32F103x6 STM32F103xC STM32F103xD and STM32F103xE are a drop in replacement for STM32F103x8 B medium d
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • STM32F207 I2C 测试失败

    我正在使用 STM32F207 微控制器在 STM3220G EVAL 板上学习嵌入式开发 我尝试通过连接同一芯片上的两个 I2C2 和 I2C3 模块并发送 接收字符来测试 I2C 接口 这是我当前编写的代码 使用 mdk arm 5 i
  • Cortex-M3与M4权威指南

    处理器类型 所有的ARM Cortex M 处理器是32位的精简指令集处理器 它们有 32位寄存器 32位内部数据路径 32位总线接口 除了32位数据 Cortex M处理器也可以有效地处理器8位和16位数据以及支持许多涉及64位数据的操作
  • 核心耦合内存在 STM32F4xx 上可执行吗?

    尝试从 STM32F429s CCM 运行代码 但每当我命中 CCM 中的第一条指令时 我总是会遇到硬故障 并且 IBUSERR 标志被设置 该指令有效且一致 STM32F4xx 是否可能不允许从 CCM 执行 数据访问效果良好 alios
  • 通过JTAG恢复STM32 MCU磨掉的标记

    我有一块可能带有 STM32 MCU 的板 我想为该板制作定制固件 因为库存板有很多问题 不幸的是 电路板制造商很友善地磨掉了所有标记 有没有办法通过 jtag 获取设备 系列 ID 并将其交叉引用到型号 我能找到的一切都是关于获取芯片的唯
  • 嵌入式 C++11 代码 — 我需要 volatile 吗?

    采用 Cortex M3 MCU STM32F1 的嵌入式设备 它具有嵌入式闪存 64K MCU固件可以在运行时重新编程闪存扇区 这是由闪存控制器 FMC 寄存器完成的 所以它不像a b那么简单 FMC 获取缓冲区指针并将数据刻录到某个闪存
  • PWM DMA 到整个 GPIO

    我有一个 STM32F4 我想对一个已与掩码进行 或 运算的 GPIO 端口进行 PWM 处理 所以 也许我们想要 PWM0b00100010一段时间为 200khz 但随后 10khz 后 我们现在想要 PWM0b00010001 然后
  • 在 Contiki 程序中使用 malloc

    考虑以下 Contiki 程序 include
  • 移动数组中的元素

    我需要一点帮助 我想将数组中的元素向上移动一个元素 以便新位置 1 包含位置 1 中的旧值 new 2 包含 old 1 依此类推 旧的最后一个值被丢弃 第一个位置的新值是我每秒给出的新值 我使用大小为 10 的数组 uint32 t TE

随机推荐

  • 网络吞吐量详解

    吞吐量 简单的讲 对于P2P系统而言 当主机A到主机B传送一个文件 任何时间瞬间的瞬时吞吐量都是主机B接收到该文件的速率 以bps计算 如果文件由F比特组成 主机B接收到所有F比特用去T秒 则文件传送的平均吞吐量是F T bps 举个例子服
  • List>排序

    package com test import java util ArrayList import java util Collections import java util Comparator import java util Ha
  • Android 6.0 miracast 学习

    Miracast是Wi Fi Alliance对支持Wi Fi Display功能的设备的认证名称 Miracast认证的设备将在最大程度内保持对Wi Fi Display功能的支持和兼容 所以从这一个方面可以说Miracast等价于WiF
  • css实现文字渐变

    效果如图 text class text align left font size 36px font weight bold line height 36px background image linear gradient 19f7ff
  • 大数据毕设项目 深度学习+opencv+python实现车道线检测 - 自动驾驶

    文章目录 0 前言 1 课题背景 2 实现效果 3 卷积神经网络 3 1卷积层 3 2 池化层 3 3 激活函数 3 4 全连接层 3 5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV5 6 数据集处理 7 模型
  • 什么是全真互联网?腾讯版Web3元宇宙?

    2020年12月底 马化腾提出全真互联网的概念 即互联网的下一波升级 称为全真互联网 小马哥对新技术的趋势很有前瞻性 这跟今年大火特火的Web3 0和元宇宙可以说是异曲同工 只是不同的描述而已 但马化腾口中的全真互联网和扎克伯格口中的元宇宙
  • Vue实现大文件分片上传、断点续传

    前言 实现大文件分片上传的断点续传以及上传进度条是一个在前端开发中常见且具有挑战性的问题 本篇博客将介绍如何使用Vue框架来实现这个功能 并给出代码示例 概述 大文件分片上传指的是将一个大文件切割成多个小文件 或称为分片 然后依次上传这些小
  • matlab 读取labview,用matlab读取labview存储的二进制

    用matlab读取labview存储的二进制 在labview中 将N个double型数组 内部有9个数字 N个double型数组 内部有4个数字 N个double型数字 N个表示时间的字符串捆绑成簇后 Write To Binary Fi
  • C/C++语言实现的一个缓存队列

    C C 语言实现的一个缓存队列 完整代码下载地址 https gitee com yzhengBTT QueueBuffer 使用方法 对于C语言 队列的创建分两种 1 静态创建 队列大小 define QUEUE SIZE 10 队列数据
  • 一起学Vue3源码,实现最简Vue3【06】 - 实现 readonly 功能

    实现 readonly 功能 什么是readonly 顾名思义 就是只能读 不能修改 TDD编码思维 测试 gt 实现 gt 重构代码 gt 优化 readonly spec ts describe readonly gt it happy
  • vim设置tab为4个空格

    版本为Ubuntu14 04 3 仅当前文本使用 vim默认tab为8个空格 不知道是不是因为linux内核代码的规范中 tab为8个空格 可以使用set ts 4 将tab设置为4个空格 执行完指令 tab缩进变为4个空格 同时再使用ta
  • Struts的优点/缺点

    lt 一 gt 优点 1 struts简单 易懂 容易被人采用 功能强大
  • STM32程序软件复位

    set FAULTMASK 1 STM32程序软件复位 NVIC SystemReset
  • python使用t-sne算法降维,方便可视化

    常用的降维算法有LDA PCA 但通常为了方便可视化 我们使用t sne降维算法 PCA的算法可以参考 异常检测2 PCA异常检测 t san的算法可以参考 t SNE算法 示例代码 import pandas as pd import m
  • 超详细的html+css基础知识树状图~HTML标签

    前言 学习任何新知识 最重要的永远都是搭建属于自己的知识框架 随后学习的细碎知识点往框架里面填入 最后形成一棵属于自己的知识大树 本系列的博客专注更新总结好的思维导图 希望可以帮助大家快速理清知识结构 具体知识树状图 一 HTML标签 1
  • java jinfo_JDK工具-Jinfo命令

    Jinfo是JDK自带Java配置信息工具 位于java的bin目录下 jinfo的作用是实时地查看和调整虚拟机的各项参数 虽然使用Jps命令的 v参数可以查看虚拟机启动时显示指定的参数列表 但是如果想要知道没有被明确指出的系统默认值 就需
  • linux编译安装含义,linux源码包编译安装详解

    linux下安装软件包有两种方法 源文件编译安装 source 和 rpm 安装 1 源文件包安装的通用方法 一般安装源代码的程序你得要看它的README 一般在它的目录下都有的 01 配置 构建应用的第一步就是执行configure脚本
  • OpenCV-Python实战(2)——图像与视频文件的处理

    OpenCV Python实战 2 图像与视频文件的处理 0 前言 1 图像与视频文件处理基础 2 图像的读取与写入 2 1 在 OpenCV 中读取图像 2 2 使用 OpenCV 写入图像 2 3 计算机视觉项目处理流程示例 3 读取相
  • jQuery最佳实践:如何用好jQuery

    一 用对选择器 在jQuery中 你可以用多种选择器 选择同一个网页元素 每种选择器的性能是不一样的 你应该了解它们的性能差异 1 最快的选择器 id选择器和元素标签选择器 举例来说 下面的语句性能最佳 id form 遇到这些选择器的时候
  • 2.11 PID控制算法(三)----PID结果与实际值的关联

    文章目录 1 讲解 2 举例1 3 举例2 4 举例3 5 调试PID参数 1 讲解 1 AD采样 经过PID计算的值 怎么和PWM对应起来 2 电机编码采样 经过PID计算的值 怎么与速度对应起来 这个简单 PID控制原理就是输出一个控制