PID算法在流量控制中的应用

news2025/2/21 22:26:28

目录

增量式或位置式

目录

增量式或位置式

PID控制周期

T1 时间

T2 约4ms

PID C代码


     

最近有小伙伴向我提问关于PID的问题:通过比例阀控制水流速度(流量),

  1. 使用增量式还是位置式 PID?
  2. 他的比例法驱动频率是500Hz那么PID的控制周期应该选多少?

增量式或位置式

借用知乎网友的一个回答:

通过带有调节阀的管路向水箱注水,控制输出u为阀门开度,如果控制目标是注水速度(流量),则采用增量控制,达到目标流量后阀门会保持;如果控制目标是水位,则采用位置式,达到目标水位后阀门会基本处于零位(积分作用下会保持一定开度)。

可以看出,当控制输出u,和控制目标是一一对应关系(一定阀门开度对应一定流量)时,采用增量式;当控制输出u,影响的是控制目标的速度(水位变化的速度,即流量)时,采用位置控制。

又比如,通过油门控制车速,也是增量控制,根据期望速度加减油门,速度到了保持住。

我们这里控制水恒流量,应该选用增量式。

PID控制周期

        

 周期 = T1(比例阀变化 -> 物理压力变化量) + T2(压力电压变化量 -> ADC量化时间 )

T1 时间

        这样具体要根据实际情况改变了,可以先按照100ms去调试。

T2 约4ms

可以查阅数据手册

压力传感器:

估算为2ms

MCU

算上软件滤波,ADC量化时间估算为2ms

咱们这里先采用100ms~200ms的PID控制周期去调PID参数。

PID C代码

/*This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
 *
 * \brief Header file for pid.c.
 *
 * - File:               pid.h
 * - Compiler:           IAR EWAAVR 4.11A
 * - Supported devices:  All AVR devices can be used.
 * - AppNote:            AVR221 - Discrete PID controller
 *
 * \author               Atmel Corporation: http://www.atmel.com \n
 *                       Support email: avr@atmel.com
 *
 * $Name$
 * $Revision: 456 $
 * $RCSfile$
 * $Date: 2006-02-16 12:46:13 +0100 (to, 16 feb 2006) $
 *****************************************************************************/

#ifndef PID_H
#define PID_H

#include "stdint.h"

#define SCALING_FACTOR  128

/*! \brief PID Status
 *
 * Setpoints and data used by the PID control algorithm
 */
typedef struct PID_DATA{
  //! Last process value, used to find derivative of process value.
  int16_t lastProcessValue;
  //! Summation of errors, used for integrate calculations
  int32_t sumError;
  //! The Proportional tuning constant, multiplied with SCALING_FACTOR
  int16_t P_Factor;
  //! The Integral tuning constant, multiplied with SCALING_FACTOR
  int16_t I_Factor;
  //! The Derivative tuning constant, multiplied with SCALING_FACTOR
  int16_t D_Factor;
  //! Maximum allowed error, avoid overflow
  int16_t maxError;
  //! Maximum allowed sumerror, avoid overflow
  int32_t maxSumError;
} pidData_t;

/*! \brief Maximum values
 *
 * Needed to avoid sign/overflow problems
 */
// Maximum value of variables
#define MAX_INT         INT16_MAX
#define MAX_LONG        INT32_MAX
#define MAX_I_TERM      (MAX_LONG / 2)

// Boolean values
#define FALSE           0
#define TRUE            1

void pid_Init(int16_t p_factor, int16_t i_factor, int16_t d_factor, struct PID_DATA *pid);
int16_t pid_Controller(int16_t setPoint, int16_t processValue, struct PID_DATA *pid_st);
void pid_Reset_Integrator(pidData_t *pid_st);

#endif
/*This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
 *
 * \brief General PID implementation for AVR.
 *
 * Discrete PID controller implementation. Set up by giving P/I/D terms
 * to Init_PID(), and uses a struct PID_DATA to store internal values.
 *
 * - File:               pid.c
 * - Compiler:           IAR EWAAVR 4.11A
 * - Supported devices:  All AVR devices can be used.
 * - AppNote:            AVR221 - Discrete PID controller
 *
 * \author               Atmel Corporation: http://www.atmel.com \n
 *                       Support email: avr@atmel.com
 *
 * $Name$
 * $Revision: 456 $
 * $RCSfile$
 * $Date: 2006-02-16 12:46:13 +0100 (to, 16 feb 2006) $
 *****************************************************************************/

#include "pid.h"
#include "stdint.h"

/*! \brief Initialisation of PID controller parameters.
 *
 *  Initialise the variables used by the PID algorithm.
 *
 *  \param p_factor  Proportional term.
 *  \param i_factor  Integral term.
 *  \param d_factor  Derivate term.
 *  \param pid  Struct with PID status.
 */
void pid_Init(int16_t p_factor, int16_t i_factor, int16_t d_factor, struct PID_DATA *pid)
// Set up PID controller parameters
{
  // Start values for PID controller
  pid->sumError = 0;
  pid->lastProcessValue = 0;
  // Tuning constants for PID loop
  pid->P_Factor = p_factor;
  pid->I_Factor = i_factor;
  pid->D_Factor = d_factor;
  // Limits to avoid overflow
  pid->maxError = MAX_INT / (pid->P_Factor + 1);
  pid->maxSumError = MAX_I_TERM / (pid->I_Factor + 1);
}


/*! \brief PID control algorithm.
 *
 *  Calculates output from setpoint, process value and PID status.
 *
 *  \param setPoint  Desired value.
 *  \param processValue  Measured value.
 *  \param pid_st  PID status struct.
 */
int16_t pid_Controller(int16_t setPoint, int16_t processValue, struct PID_DATA *pid_st)
{
  int16_t error, p_term, d_term;
  int32_t i_term, ret, temp;

  error = setPoint - processValue;

  // Calculate Pterm and limit error overflow
  if (error > pid_st->maxError){
    p_term = MAX_INT;
  }
  else if (error < -pid_st->maxError){
    p_term = -MAX_INT;
  }
  else{
    p_term = pid_st->P_Factor * error;
  }

  // Calculate Iterm and limit integral runaway
  temp = pid_st->sumError + error;
  if(temp > pid_st->maxSumError){
    i_term = MAX_I_TERM;
    pid_st->sumError = pid_st->maxSumError;
  }
  else if(temp < -pid_st->maxSumError){
    i_term = -MAX_I_TERM;
    pid_st->sumError = -pid_st->maxSumError;
  }
  else{
    pid_st->sumError = temp;
    i_term = pid_st->I_Factor * pid_st->sumError;
  }

  // Calculate Dterm
  d_term = pid_st->D_Factor * (pid_st->lastProcessValue - processValue);

  pid_st->lastProcessValue = processValue;

  ret = (p_term + i_term + d_term) / SCALING_FACTOR;
  if(ret > MAX_INT){
    ret = MAX_INT;
  }
  else if(ret < -MAX_INT){
    ret = -MAX_INT;
  }

  return((int16_t)ret);
}

/*! \brief Resets the integrator.
 *
 *  Calling this function will reset the integrator in the PID regulator.
 */
void pid_Reset_Integrator(pidData_t *pid_st)
{
  pid_st->sumError = 0;
}

/*This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
 *
 * \brief Example of use of general PID implementation for AVR.
 *
 * Example of how to setup and use the general PID implementation in pid.c.
 *
 * - File:               main.c
 * - Compiler:           IAR EWAAVR 4.11A
 * - Supported devices:  All AVR devices can be used.
 * - AppNote:            AVR221 - Discrete PID controller
 *
 * \author               Atmel Corporation: http://www.atmel.com \n
 *                       Support email: avr@atmel.com
 *
 * $Name$
 * $Revision: 456 $
 * $RCSfile$
 * $Date: 2006-02-16 12:46:13 +0100 (to, 16 feb 2006) $
 *****************************************************************************/

#include <inavr.h>
#include <ioavr.h>
#include "stdint.h"
#include "pid.h"

/*! \brief P, I and D parameter values
 *
 * The K_P, K_I and K_D values (P, I and D gains)
 * need to be modified to adapt to the application at hand
 */
//! \xrefitem todo "Todo" "Todo list"
#define K_P     1.00
//! \xrefitem todo "Todo" "Todo list"
#define K_I     0.00
//! \xrefitem todo "Todo" "Todo list"
#define K_D     0.00

/*! \brief Flags for status information
 */
struct GLOBAL_FLAGS {
  //! True when PID control loop should run one time
  uint8_t pidTimer:1;
  uint8_t dummy:7;
} gFlags = {0, 0};

//! Parameters for regulator
struct PID_DATA pidData;

/*! \brief Sampling Time Interval
 *
 * Specify the desired PID sample time interval
 * With a 8-bit counter (255 cylces to overflow), the time interval value is calculated as follows:
 * TIME_INTERVAL = ( desired interval [sec] ) * ( frequency [Hz] ) / 255
 */
//! \xrefitem todo "Todo" "Todo list"
#define TIME_INTERVAL   157

/*! \brief Timer interrupt to control the sampling interval
 */
#pragma vector = TIMER0_OVF_vect
__interrupt void TIMER0_OVF_ISR( void )
{
  static uint16_t i = 0;
  if(i < TIME_INTERVAL)
    i++;
  else{
    gFlags.pidTimer = TRUE;
    i = 0;
  }
}

/*! \brief Init of PID controller demo
 */
void Init(void)
{
  pid_Init(K_P * SCALING_FACTOR, K_I * SCALING_FACTOR , K_D * SCALING_FACTOR , &pidData);

  // Set up timer, enable timer/counte 0 overflow interrupt
  TCCR0A = (1<<CS00);
  TIMSK0 = (1<<TOIE0);
  TCNT0 = 0;
}

/*! \brief Read reference value.
 *
 * This function must return the reference value.
 * May be constant or varying
 */
int16_t Get_Reference(void)
{
  return 8;
}

/*! \brief Read system process value
 *
 * This function must return the measured data
 */
int16_t Get_Measurement(void)
{
  return 4;
}

/*! \brief Set control input to system
 *
 * Set the output from the controller as input
 * to system.
 */
void Set_Input(int16_t inputValue)
{
  ;
}


/*! \brief Demo of PID controller
 */
void main(void)
{
  int16_t referenceValue, measurementValue, inputValue;
  Init();
  __enable_interrupt();

  while(1){

    // Run PID calculations once every PID timer timeout
    if(gFlags.pidTimer)
    {
      referenceValue = Get_Reference();
      measurementValue = Get_Measurement();

      inputValue = pid_Controller(referenceValue, measurementValue, &pidData);

      Set_Input(inputValue);

      gFlags.pidTimer = FALSE;
    }
  }
}

/*! \mainpage
 * \section Intro Introduction
 * This documents data structures, functions, variables, defines, enums, and
 * typedefs in the software for application note AVR221.
 *
 * \section CI Compilation Info
 * This software was written for the IAR Embedded Workbench 4.11A.
 *
 * To make project:
 * <ol>
 * <li> Add the file main.c and pid.c to project.
 * <li> Under processor configuration, select desired Atmel AVR device.
 * <li> Enable bit definitions in I/O include files
 * <li> High optimization on speed is recommended for best performance
 * </ol>
 *
 * \section DI Device Info
 * The included source code is written for all Atmel AVR devices.
 *
 * \section TDL ToDo List
 * \todo Put in own code in:
 * \ref Get_Reference(void), \ref Get_Measurement(void) and \ref Set_Input(int16_t inputValue)
 *
 * \todo Modify the \ref K_P (P), \ref K_I (I) and \ref K_D (D) gain to adapt to your application
 * \todo Specify the sampling interval time \ref TIME_INTERVAL
 */

这是一份AVR的官方增量式代码,也很容易移植到不同的MCU,这份代码我也有实际产品使用过,非常好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/572150.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows http https的搭建

目录 搭建http站点 ​编辑 报错 网站端口更改 可能存在的报错 绑定主机名 端口为80的情况下 绑定的端口不为80的情况下 https站点搭建 CA机构证书可以给其他服务器使用&#xff0c;不过要用导出导入的行书&#xff0c;不能直接使用cer文件 搭建http站点 ①勾选IIS ②一…

windows下nginx+tomcat配置负载均衡的方法

在负载均衡方面&#xff0c;Nginx和Tomcat的实现方式略有不同。Nginx作为反向代理服务器&#xff0c;可以直接处理并分发请求到后端服务器&#xff0c;包括Tomcat。它可以使用不同的负载均衡算法来分发请求&#xff0c;将负载均衡的任务集中在Nginx上。而Tomcat通常通过与Apach…

RL Note 1, Basic Concepts in Reinforcement Learning

Basic Concepts in Reinforcement Learning A grid-world example 在该图中&#xff1a; 格子被分为三类&#xff1a;可访问的格子、禁止访问的格子、目标格子角色被称为 agentagent 的任务就是从 start 开始找到一条“正确”的路径到达 targetagent 无法越过边界&#xff0c…

创建多线程常用的三种方式

三种常用多线程实现方式 1. 继承Thread类 继承Thread线程类并且重写run方法无线程任务返回值 2. 实现Runnable接口 实现Runnable接口并且重写run方法无线程任务返回值 3. 实现Callable接口和通过Futrue接口实现类(FutrueTask) 实现Callable接口(泛型数据类型对应call方法的返回…

(2020,DA)用于数据高效 GAN 训练的可鉴别数据增强(Differentiable Augmentation)

Differentiable augmentation for data-efficient gan training 公众号&#xff1a;EDPJ 目录 0. 摘要 1. 简介 2. 相关工作 3. 方法 3.1 重温数据增强 3.2 GAN 的可鉴别增强 4. 实验 4.1 ImageNet 4.2 FFHQ 和 LSUN-Cat 4.3 CIFAR-10 和 CIFAR-100 4.4 low-sho…

GPU服务器傻瓜式安装Anaconda,pytorch,tensorflow

1.下载Anaconda安装包&#xff0c;官网地址&#xff0c;清华源地址。 在官网下载到本地之后&#xff0c;可以通过文件传输上传安装包到服务器&#xff0c;使用清华源地址可以直接使用wget下载所需版本&#xff0c;例如&#xff1a; wget https://mirrors.tuna.tsinghua.edu.c…

Java之旅(三)

Java 输出&#xff1a;println()、print() 使用 println() 方法在 Java 中输出值或打印文本。 System.out.println("Hello World!"); println() 可以根据需要添加任意数量的方法。请注意&#xff0c;它将为每个方法添加一个新行&#xff1a; System.out.println(&…

静电测试仪:如何简单高效地测量静电电荷?

静电电荷是在两种不同材料之间接触或分离时&#xff0c;由电子或离子转移所产生的电荷。静电电荷的存在&#xff0c;可能导致许多不良的影响&#xff0c;比如产品损坏、设备失灵甚至是人员受伤。因此&#xff0c;测量静电电荷量成为提升产品质量、工作环境的必要步骤之一。而静…

【PCIE体系结构十二】链路训练的相关基础前菜

&#x1f449;个人主页&#xff1a;highman110 &#x1f449;作者简介&#xff1a;一名硬件工程师&#xff0c;持续学习&#xff0c;不断记录&#xff0c;保持思考&#xff0c;输出干货内容 参考书籍&#xff1a;《PCI.EXPRESS系统体系结构标准教材 Mindshare》 目录 物理…

linuxOPS基础_Linux系统的文件目录结构及用途

linux系统文件目录结构 Linux 系统不同于 Windows&#xff0c;没有 C 盘、D 盘、E 盘那么多的盘符&#xff0c;只有一个根目录&#xff08;/&#xff09;&#xff0c;所有的文件&#xff08;资源&#xff09;都存储在以根目录&#xff08;/&#xff09;为树根的树形目录结构中…

如何使用高扩展组件制作APP原型的标签栏?

原型项目中的组件&#xff08;亦称元件、控件&#xff09;&#xff0c;是指通过基础图层拼装而成&#xff0c;可供用户进行交互或用于展示复杂内容的元素。 在原型设计工作中&#xff0c;组件的使用是非常重要的部分&#xff0c;其不仅关乎项目内容的呈现&#xff0c;更会影响…

网络货运平台源码 管理平台端+司机端APP+货主端APP源码

网络货运平台系统源码&#xff0c;网络货运平台源码 管理平台端司机端APP货主端APP 遵循政策要求的八项基本功能&#xff0c;结合货主、实际承运人、监管方等多方业务场景&#xff0c;构建人、车、货、企一体的标准化网络货运平台系统。具有信息发布、线上交易、全程监控、金融…

网络安全工程师能拿高薪的秘密!

网络安全是一门具有很强实践性的学科&#xff0c;但是网络安全传统过程对实践能力培养环节比较薄弱&#xff0c;缺少适应新需求的实践与创新平台。所以&#xff0c;很多网络安全专业的学生学习的基本都是理论知识&#xff0c;而最重要的实战能力薄弱。仅仅只会一点基础的专业知…

景区虚拟人智能互动导览提升客户服务体验

数字化浪潮下&#xff0c;文旅产正积极拥业数字化转型。虚拟数字人作为元宇宙的交互入口&#xff0c;其在文旅产业中的应用&#xff0c;对文旅产业的发展具有非常重要的意义。将超写实虚拟人化身为景点讲解员有哪些好处呢? 视觉冲击力更强&#xff0c;吸引眼球 超写实虚拟人的…

jvm之JMX

写在前面 本文来看先jmx相关内容。 1&#xff1a;jmx介绍 jvm在运行的过程中有很多的信息&#xff0c;比如堆内存&#xff0c;线程数&#xff0c;加载的类信息&#xff0c;CPU的使用量等&#xff0c;如果我们想要将这些信息暴漏让外界获取&#xff0c;该怎么做呢?此时就需要…

springAop原理分析-动态代理对象创建过程分析

概念 AspectJ Aspect 切面&#xff08;由多个切点组成&#xff0c;多个点组成面&#xff09; 启用AspectJ支持后&#xff0c;Spring 会自动检测出在应用程序上下文中定义的任何 Bean&#xff0c;如下使用Aspect 定义的一个切面示例。 package org.xyz; import org.aspectj.…

STM8、STM8S003F3P6 实现PWM控制电机HAS10227

背景 有个项目需要控制一台风机的转速&#xff0c;使用STM8S003F3P6 输出PWM控制&#xff0c;这里就详细记录一下调试记录 原理图 原理图比较简单&#xff0c;电机接口CN3 电机接口原理图 与MCU管脚连接位置如下图 首先我们要明白电机的原理 电机 简单来说就是 实现电能与…

闲置手机建站 - 安卓Termux+Hexo搭建属于你自己博客网站【cpolar实现公网访问】

文章目录 1. 安装 Hexo2. 安装cpolar内网穿透3. 公网远程访问4. 固定公网地址 Hexo 是一个用 Nodejs 编写的快速、简洁且高效的博客框架。Hexo 使用 Markdown 解析文章&#xff0c;在几秒内&#xff0c;即可利用靓丽的主题生成静态网页。 下面介绍在Termux中安装个人hexo博客并…

助力工业物联网,工业大数据之一站制造业务主题划分【十三】

文章目录 01&#xff1a;一站制造业务主题划分02&#xff1a;一站制造业务维度设计03&#xff1a;一站制造业务主题维度矩阵 01&#xff1a;一站制造业务主题划分 目标&#xff1a;掌握一站制造的主题域及主题的划分实施 来源 主题域划分&#xff1a;业务或者部门划分 业务&am…

PHP基于xlswriter支持无限表头层级Excel导出

本章介绍基于PHP扩展xlswriter的Vtiful\Kernel\Excel类可以支持无限层级的复杂表头导出&#xff01; 废了九牛二虎之力&#xff0c;终于把这个功能类写完了…后续会持续更新优化 准备xlswriter扩展 windows系统&#xff1a; 到PECL网站下载符合自己本地PHP环境的ddl文件下载地…