PID c++算法学习和实现

原理图:
在这里插入图片描述
在这里插入图片描述
(1)位置式PID
1:当前系统的实际位置,与你想要达到的预期位置的偏差, 2:进行PID控制,误差会一直累加,会使当前输出与过去的所有输入相关,输入uk出错,会导致系统大幅波动 3:位置式PID在积分项达到饱和时,误差仍然会在积分作用下继续累积,一旦误差开始反向变化,系统需要一定时间从饱和区退出,所以在u(k)达到最大和最小时,要停止积分作用,并且要有积分限幅和输出限幅, 4:用位置式PID时,一般我们直接使用PD控制,不使用积分项

实际应用中,用差分代替微分,连加代替积分,也就是离散型PID
令:
在这里插入图片描述

(1)实现:位置模式PID

#include <math.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include "matplotlibcpp.h"
#include <vector>
#include <math.h>
#include <string>
#include<stdlib.h>
namespace plt = matplotlibcpp;


class pid_p
{
private:
    float ki;
    float kp;
    float kd;
    float ek;
    float ek_1;
    float actual;
    float de;
    float target;
    float yk;
public:
    pid_p();
    ~pid_p();
    pid_p(float p,float i,float d);
    void get_error();
    
    void get_value(float act,float tar);
    float update();
};

pid_p::pid_p():kp(0),ki(0),kd(0),ek(0),ek_1(0),de(0),actual(0),yk(0)
{
}
pid_p::pid_p(float p,float i,float d):ek(0),ek_1(0),de(0),actual(0),yk(0)
{
    kp=p;
    ki=i;
    kd=d;
}

pid_p::~pid_p()
{
}
void pid_p::get_value(float act,float tar)
{
    actual=act;
    target=tar;
    get_error();
    printf("actual:%f,target%f",actual,target);
}
void pid_p::get_error()
{
    ek=target-actual;
}
float pid_p::update()
{
    de+=ek;
    yk=kp*ek+ki*de+kd*(ek-ek_1);
    printf("p:%f,i:%f,d:%f,act:%f,yk:%f,ek:%f\r\n",kp,ki,kd,actual,yk,ek);
    ek_1=ek;
    return yk;

}

//输入三个参数kp,ki,kd
int main(int argc,char ** argv)
{   float target=1000;
    std::string str_p=argv[1];
    std::string str_i=argv[2];
    std::string str_d=argv[3];
    // std::string str_p="0.35";
    // std::string str_i="0.0001";
    // std::string str_d="0.0001";
    float act=0;int N=100;
   
    float kp=atof(str_p.c_str());
    float ki=atof(str_i.c_str());
    float kd=atof(str_d.c_str());
    
    pid_p a(kp,ki,kd);
    std::vector<float> x,y;
    for (int i=0;i<N;i++)
    {
        x.push_back(i);
        y.push_back(act);
        a.get_value(act,target);
        act+=a.update();
        a.pid_printf();
        //if(act>target)break;
    }
    plt::plot(x,y);
    plt::show();
}

(2)增量式PID
原理:使控制器输出为增量,尽量使每次数据均与过去数据无关,没有积分项。
公式:Kp比例系数、Ki积分系数、Kd微分系数、e(k)偏差
Δu(k)=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]

实现

/*
*  定义PID的结构体,结构体内存储PID参数、误差、限幅值以及输出值
*/
typedef struct
{
    float Kp; 
    float Ki;
    float Kd;
    
    float last_error;  //上一次偏差
    float prev_error;  //上上次偏差
    
    int limit;   //限制输出幅值
    int pwm_add; //输出的PWM值  
}PID;
/**
  * @brief  PID相关参数的初始化 
  * @param  PID的结构体指针
  */
void PID_Init(PID *p)
{
    p->Kp = Velocity_Kp;
    p->Ki = Velocity_Ki;
    p->Kd = Velocity_Kd;
    p->last_error = 0;
    p->prev_error = 0;
    p->limit = limit_value;
    p->pwm_add = 0;
}
/**
  * @brief  PID相关参数的初始化 
  * @param  targetSpeed目标速度值,PID的结构体指针p
  */
int PID_Cal(int targetSpeed,int currentSpeed,PID *p)
{
   int error = targetSpeed - currentSpeed;  //得到目标速度与当前速度的误差
    p->pwm_add += p->Kp*(error - p->last_error) + p->Ki*error + p->Kd*(error - 2*p->last_error+p->prev_error);   //根据增量PID公式计算得到输出的增量
  
    p->prev_error = p->last_error;  //记录上次误差
    p->last_error = error;    //记录本次误差
  
    if(p->pwm_add>p->limit) p->pwm_add=p->limit;  //限制最大输出值
    if(p->pwm_add<-p->limit) p->pwm_add=-p->limit;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)  //定时器6中断回调函数,每50ms调用一次
{
  float c_leftSpeed,c_rightSpeed;  
  if(htim==(&htim6))
  {
    GetEncoderPulse(); 
    c_leftSpeed = CalActualSpeed(encoderPulse[0]);   //获得当前的速度值
    c_rightSpeed = CalActualSpeed(encoderPulse[1]);
      
      PID_Cal(leftTargetSpeed,c_leftSpeed,&LeftMotor_PID);//左边电机的PID计算
      PID_Cal(rightTargetSpeed,c_rightSpeed,&RightMotor_PID);//右边电机的PID计算
      
      MotorControl(leftMotor_PID.pwm_add,RightMotor_PID.pwm_add);
     
      //通过上位机查看速度曲线以及PID调速效果
      printf("{currentLeftSpeed is:%.2f}\r\n",c_leftSpeed); 
    printf("{currentrightSpeed is:%.2f}\r\n",c_rightSpeed);
  }
}

关于PID的参数调节,一般遵循以下原则:

先调整比例系数Kp,然后再调整积分系数Ki,最后再调整微分系数Kd。
调整Kp时,从小到大进行调整,选取偏小的比例系数使得输出曲线基本贴合目标直线。
调整Ki,用Ki消除静态误差。
调整Kd,提高调速的响应速度。

(3) 积分分离式PID

原理:在系统误差较大时,取消积分环节;当误差较小时,引入积分环节。这样既不影响控制器的动态性能,又可以提高控制器的稳态精
实现:在位置式/增量式PID加入积分环节一个阈值,实现略

(4) 抗饱和积分式PID
原理:在计算U(k)的时候,先判断上一时刻的控制量U(k-1)是否已经超出了限制范围。若U(k-1)>Umax,则只累加负偏差;若U(k-1)<Umin,则只累加正偏差。从而避免控制量长时间停留在饱和区。
实现:

class pid_antisaturation
{
    private:
        float kp,ki,kd,uk,uk_1,yk,ek,ek_1,ek_2;
        const float max_uk_1=500,min_uk_1=-500;
    public:
        pid_antisaturation():kp(0),ki(0),kd(0),uk(0),yk(0),ek(0),ek_1(0),ek_2(0),uk_1(0)
        {};
        pid_antisaturation(float p,float i,float d):kp(p),ki(i),kd(d),uk(0),yk(0),ek(0),ek_1(0),ek_2(0),uk_1(0)
        {};
        void get_value(float act,float target);
        void update_error();
        float update();
};
void pid_antisaturation::get_value(float act,float target)
{
    uk_1=uk;
    uk=act;
    yk=target;
}
void pid_antisaturation::update_error()
{
    ek_2=ek_1;
    ek_1=ek;
    ek=yk-uk;
}
float pid_antisaturation::update()
{
    float increase;
    update_error();
    if((uk_1>max_uk_1)&(ek>0))
    {
        ek=0;
    }
    if((uk_1<min_uk_1)&(ek<0))
    {
        ek=0;
    }
    increase=kp*(ek-ek_1)+ki*ek+kd*(ek-2*ek_1+ek_2);
    printf("p:%f,i:%f,d:%f,act:%f,yk:%f,ek:%f\r\n",kp,ki,kd,uk,yk,ek);
    return increase;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python将pdf转为docx

如何使用python实现将pdf文件转为docx文件 1.首先要安装pdf2docx库 pip install pdf2docx2.实现转换 from pdf2docx import Converterdef convert_pdf_to_docx(input_pdf, output_docx):# 创建一个PDF转换器对象pdf_converter Converter(input_pdf)# 将PDF转换为docx文件pdf…

【技术干货】长运通SiP微模块技术介绍

一、什么是SiP技术&#xff1f; SiP原文“System in Package”&#xff0c;字面含义是系统级封装&#xff0c;国际半导体技术发展路线图 ( ITRS 2005 )对 SiP 的定义是&#xff1a;系统级封装是采用任何组合, 将多个具有不同功能的有源电子器件与可选择性的无源元件以及诸如 M…

解决CSS中鼠标移入到某个元素其子元素被遮挡的问题

我们在开发中经常遇到一种场景&#xff0c;就是给元素加提示信息&#xff0c;就是鼠标移入到盒子上面时&#xff0c;会出现提示信息这一功能&#xff0c;如果我们给盒子加了hover&#xff0c;当鼠标移入到盒子上时&#xff0c;让他往上移动5px&#xff0c;即transform: transla…

2024年下载排行第一的数据恢复软件EasyRecovery

EasyRecovery数据恢复软件是一款功能强大的数据恢复工具&#xff0c;它能够帮助用户恢复因各种原因丢失的数据&#xff0c;无论是误删除、格式化、分区丢失还是其他存储介质故障&#xff0c;都能得到很好的解决。 使用EasyRecovery进行数据恢复&#xff0c;用户只需按照简单的…

租用境外服务器,越南服务器的优势有哪些

自从中国加入世界贸易组织之后&#xff0c;国内经济增加速度非常快&#xff0c;同时越来越多的人选择去东南亚国家发展&#xff0c;因为当地的中国人很多&#xff0c;所以中国企业在当地面临着更小的文化差异。东南亚地区也是最新的经济体&#xff0c;互联网正处于蓬勃发展的阶…

【日志跟踪】SpringBoot实现简单的日志链路追踪

引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j&l…

Java编译期注解处理器AbstractProcessor使用

我们接触的注解主要分为以下两类 运行时注解&#xff1a;通过反射在运行时动态处理注解的逻辑编译时注解&#xff1a;通过注解处理器在编译期动态处理相关逻辑 编译期注解我们常用的有Lombok&#xff0c;在class文件中自动生成get和set方法 解编译期处理流程最关键的一个类就…

数字乡村创新实践探索农业现代化与乡村振兴新路径:科技赋能农村全面振兴与农民福祉新纪元

目录 引言 一、数字乡村与农业现代化新路径 1、智慧农业引领农业现代化 2、农业产业链的数字化转型 二、数字乡村与乡村振兴新路径 1、农村信息化水平的提升 2、农村治理模式的创新 三、科技赋能农村全面振兴与农民福祉新纪元 1、提升农业生产效益与农民收入 2、促进…

【Qt 学习笔记】Qt常用控件 | 按钮类控件Push Button的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 按钮类控件Push Button的使用及说明 文章编号&#xff1…

路径规划 | 基于蜣螂优化算法的无人机三维路径规划(Matlab)

目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 基于蜣螂优化算法的无人机三维路径规划【23年新算法应用】可直接运行 Matlab语言 1.读取地形数据&#xff0c;利用蜣螂算法DBO优化三维路径&#xff0c;目标函数为总路径最短&#xff0c;同时不能撞到障碍物&#xff…

Android Studio使用USB真机调试详解

本文为大家分享了Android Studio使用USB真机调试的具体方法&#xff0c;供大家参考&#xff0c;具体内容如下 以小米4为例&#xff0c;先将手机通过USB连接电脑&#xff0c;在设备管理器中确保驱动安装正确。 对手机的设置 1.设置手机为开发者模式&#xff08;设置- 关于手机…

windows应急响应基础知识

一、系统排查 1、系统详细信息 systeminfo2、网络链接 netstat -ano LISTENING 服务启动后首先处于侦听 ESTABLISHED 建立连接。表示两台机器正在通信。 CLOSE_WAIT 对方主动关闭连接或者网络异常导致连接中断&#xff0c;这时我方的状态会变成CLOSE_WAIT 此时我方要调用…

如何查找overlayfs对应的POD如何根据pod找到containerd id

如何查找overlayfs对应的POD mount |grep overlayfs | grep 1738 ctr -n k8s.io c list | grep 11ac4083419be11174746b68d018a0a402d9ae43c6b52125810fe1ec7db63bc6 查找目录并统计大小 find / -name "jfsCache" -exec du -sh {} | sort -rh如何根据pod找到c…

HarmonyOS4-网络连接-http请求数据

使用Axios发送请求&#xff1a; 详细资料来源于官方文档。

java数据结构与算法刷题-----LeetCode338. 比特位计数

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 位运算统计1的个数动态规划 位运算统计1的个数 &#x1f3c6;Le…

2023年图灵奖揭晓,你怎么看?

Avi Wigderson——理论计算机科学的先锋&#xff0c;荣获2023年图灵奖 在科技界&#xff0c;图灵奖堪称与诺贝尔奖齐名的崇高荣誉&#xff0c;它每年授予对计算机行业的贡献达到重大突破的个人或团队。今年&#xff0c;这一声誉卓著的奖项被授予了普林斯顿大学的数学教授 Avi …

上位机图像处理和嵌入式模块部署(树莓派4b安装opencv)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 树莓派4b上面安装的镜像应该是debian系统&#xff0c;本身是可以用apt-get进行软件下载的。这一点对于我们来说就非常的方便。因为&#xff0c;如果…

毕设选51还是stm32?51太简单?

如果你更倾向于挑战和深入学习&#xff0c;STM32可能是更好的选择。如果你希望更专注于底层硬件原理&#xff0c;51可能更适合。我这里有一套嵌入式入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习嵌入式&#xff0c;不妨点个关注&#xff…

Spring Boot | SpringBoot对 “SpringMVC“的 “整合支持“、SpringMVC“功能拓展实现“

目录: SpringMVC 的 “整合支持” ( 引入"Web依赖启动器"&#xff0c;几乎可以在无任何额外的配置的情况下进行"Web开发")1.SpringMVC "自动配置" 介绍 ( 引入Web依赖启动器"后&#xff0c;SpringBoot会自动进行一些“自动配置”&#xff0…

计算机网络 Cisco路由器基本配置

一、实验内容 1、按照下表配置好PC机IP地址和路由器端口IP地址 2、配置好路由器特权密文密码“abcd&#xff0b;两位班内序号”和远程登录密码“star” 3、验证测试 a.验证各个接口的IP地址是否正确配置和开启 b.PC1 和 PC2 互ping c.验证PC1通过远程登陆到路由器上&#…