pid算法C语言实现

理论我就不多说了,网都已经很多了,但能直接看到效果的确不多。这里我就提供一个C语言实现的可以看到效果的实际例程。

pid.h

#ifndef __PID_H
#define __PID_Htypedef struct pid {int error_last;int error_last_last;float kp;float ki;float kd;// 仅位置式PID使用long integral;int target;int current;int times;
}ppid_t;#define KP  0.1
#define KI  0.8
#define KD  0.1
#define PID_MAX 100
#define PID_MIN -100void pid_init(int target, int init);
void pid_set_target(int target);
void pid_set_proportion(float kp, float ki, float kd);
int pid_get_change_value(int current);
int pid_get_point_value(int value);
int pid_get_times();#endif

pid.c


#include "pid.h"
static ppid_t pid;/*
* @brife   : pid结构初始化
* @param   : target 目标值
* @param   : init 初始值
* @return  : 无
*/
void pid_init(int target, int init)
{pid.error_last = target - init;pid.error_last_last = target - init;pid.kp = KP;pid.ki = KI;pid.kd = KD;pid.integral = 0;pid.target = target;pid.current = init;pid.times = 0;
}/*
* @brife  : 设置pid目标值
* @param  : target 目标值
* @return : 无
*/
void pid_set_target(int target)
{pid.target = target;
}/*
* @brife  : 设置pid比例,微分,积分比例大小
* @param  : kp 比例值
* @param  : ki 积分比例
* @param  : kd 微分比例
* @return : 无
*/
void pid_set_proportion(float kp, float ki, float kd)
{pid.kp = kp;pid.ki = ki;pid.kd = kd;
}/*
* @brife  : 增量式pid, 获取下次改变值
* @param  : current 当前值
* @return : 改变值,可正,可负
*/
int pid_get_change_value(int current)
{int error = 0;int p_out, i_out, d_out;int ret;error = pid.target - current;p_out = pid.kp * (error - pid.error_last);i_out = pid.ki * error;d_out = pid.kd * (error - 2 * pid.error_last + pid.error_last_last);ret = p_out + i_out + d_out;if(ret > PID_MAX)ret = PID_MAX;if(ret < PID_MIN)ret = PID_MIN;pid.error_last_last = pid.error_last;pid.error_last = error;pid.times += 1;return ret;
}/*
* @brife  : 位置式pid获取下次预测值
* @param  : 当前值
* @return : 下次预测值
*/
int pid_get_point_value(int value)
{int ret = 0;int p_out, d_out;long i_out = 0;int error = 0;error = pid.target - value;pid.integral += error;if(pid.integral > (1 << 30))pid.integral = 0;p_out = pid.kp * error;i_out = pid.ki * pid.integral;d_out = pid.kd * (error - pid.error_last);if((p_out + i_out + d_out - value) < PID_MIN)ret = value + PID_MIN;else if((p_out + i_out + d_out - value) > PID_MAX)ret = value + PID_MAX;elseret = p_out + i_out + d_out;pid.error_last = error;pid.times += 1;return ret;
}/*
* @brife  : pid 调整次数
* @param  : 无
* @return : pid调整次数
*/
int pid_get_times(){return pid.times;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "pid.h"int main(int argc, char **argv)
{int target, current;if(argc < 3){fprintf(stderr,"Usage: ./main target current\n");exit(1);}target = atoi(argv[1]);current = atoi(argv[2]);pid_init(target, current);while(1){current += pid_get_change_value(current);printf("%d: current %d\n", pid_get_times(), current);sleep(1);}exit(0);
}

编译与运行

gcc -o main main.c pid.c./main 500 123

下面是运行结果。可以看到越来越近500,但到500后有又到了501,可以通过调整kp, ki, kd改善,但也没有那个必要,实际工程中多1格,少1格一般没有太大影响。前期以100的进度增加,因为pid.c中做了限制。这是考虑到实际工程中的设定值斜率往往不能太大。

1: current 220
2: current 320
3: current 420
4: current 474
5: current 493
6: current 500
7: current 501
8: current 501
9: current 501
10: current 501
11: current 501
12: current 501
13: current 501
14: current 501
15: current 501

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

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

相关文章

cookie/sessionStorage/localStorage 的区别

cookie/sessionStorage/localStorage 的区别 cookie、sessionStorage、localStorage 都是保存本地数据的方式 其中&#xff0c;cookie 兼容性较好&#xff0c;所有浏览器均支持。浏览器针对 cookie 会有一些默认行为&#xff0c;比如当响应头中出现set-cookie字段时&#xff0c…

剑指Offer 20.表示数值的字符串

20.表示数值的字符串 题目 官方地址 代码&#xff08;正则表达式&#xff09; public boolean isNumeric (String str) {if (str null || str.length() 0)return false;return new String(str).matches("[-]?\\d*(\\.\\d)?([eE][-]?\\d)?"); }在给定的代码…

PCIE链路信息

目录 简介&#xff1a; 目的&#xff1a; 详情&#xff1a; 简介&#xff1a; PCIe有很多寄存器&#xff0c;也有很多控制&#xff0c;包括链路状态信息&#xff0c;上一节我们讲到了PCie的链路训练&#xff0c;这节文章将继续学习PCIe相关知识。 目的&#xff1a; 从设计…

【Python从小白到高手】---函数基础

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【Python小白从入门到精通】&#x1f388; 本专栏旨在分享学习Python的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录…

iPhone 6透明屏是什么?原理、特点、优势

iPhone 6透明屏是一种特殊的屏幕技术&#xff0c;它能够使手机屏幕变得透明&#xff0c;让用户能够透过屏幕看到手机背后的物体。 这种技术在科幻电影中经常出现&#xff0c;给人一种未来科技的感觉。下面将介绍iPhone 6透明屏的原理、特点以及可能的应用。 iPhone 6透明屏的原…

本地 shell无法连接centos 7 ?

1、首先检查是否安装ssh服务&#xff1b; yum list installed | grep openssh-server# 没有安装尝试安装下 yum install openssh-server 2、检查ssh服务是否开启 systemctl status sshd.service# 未开启&#xff0c;开启下 systemctl start sshd.service # 将sshd 服务添…

socker套接字

1.打印错误信息 2.socketaddr_in结构体 结构体&#xff1a; &#xff08;部分库代码&#xff09; (宏中的##) 3.manual TCP: SOCK_STREAM &#xff1a; 提供有序地&#xff0c;可靠的&#xff0c;全双工的&#xff0c;基于连接的流式服务 UDP: 面向数据报

406 · 和大于S的最小子数组

链接&#xff1a;LintCode 炼码 - ChatGPT&#xff01;更高效的学习体验&#xff01; 题解&#xff1a;同向双指针 九章算法 - 帮助更多程序员找到好工作&#xff0c;硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧 class Solution { public:/*** param nums: an array …

《Java面向对象程序设计》学习笔记——第 5 章 继承与接口

​专栏&#xff1a;《Java面向对象程序设计》学习笔记 第 5 章 类与对象 5.1 子类与父类 有新类继承一般类视频讲解的状态和行为&#xff0c;并根据需要增加新的状态和行为。 由继承得到的类称为子类&#xff0c;被继承的类称为父类&#xff08;超类&#xff09;。 Java 不…

【maven】构建项目前clean和不clean的区别

其实很简单&#xff0c;但是百度搜了一下&#xff0c;还是没人能简单说明白。 搬用之前做C项目时总结结论&#xff1a; 所以自己在IDE里一遍遍测试程序能否跑通的时候&#xff0c;不需要clean&#xff0c;因为反正还要改嘛。 但是这个项目测试好了&#xff0c;你要打成jar包给…

element-tree-line el-tree 添加结构线 添加虚线

概览&#xff1a;给element组件添加上虚线&#xff0c;通过使用插件element-tree-line 参考连接&#xff1a; 参考别人的博客 安装插件&#xff1a; # npm npm install element-tree-line -S # yarn yarn add element-tree-line -S main.js全局注册引入插件&#xff1a; imp…

Python批量查字典和爬取双语例句

最近&#xff0c;有网友反映&#xff0c;我的批量查字典工具换到其它的网站就不好用了。对此&#xff0c;我想说的是&#xff0c;互联网包罗万象&#xff0c;网站的各种设置也有所不同&#xff0c;并不是所有的在线字典都可以用Python爬取的。事实上&#xff0c;很多网站为了防…

Linux文本三剑客---grep、sed、awk

目录标题 1、grep1.1 命令格式1.2命令功能1.3命令参数1.4grep实战演练 2、sed2.1 认识sed2.2命令格式2.3常用选项options2.4地址定界2.5 编辑命令command2.6用法演示2.6.1常用选项options演示2.6.2地址界定演示2.6.3编辑命令command演示 3、awk3.1认识awk3.2常用命令选项3.3awk…

向表中随机插入字符串数据

已知表 向该表中插入指定次数的随机字符串&#xff1a; 代码如下: DROP PROCEDURE sc //CREATE PROCEDURE sc(num INT) BEGIN DECLARE str VARCHAR(26) DEFAULT "abcdefghijklmnopqrstuvwxyz"; DECLARE cnt INT DEFAULT 0; DECLARE startIndex INT DEFAULT 1; DE…

线程、进程的区别

线程、进程的区别 在开发中&#xff0c;我们经常听到线程和进程两个概念&#xff0c;它们都是操作系统的基本概念&#xff0c;操作系统以进程为基本单位分配存储器&#xff0c;以线程为基本单位分配CPU。虽然它们有很多相似之处&#xff0c;但是它们也有很大的区别。本文将详细…

msvcp120.dll丢失的解决方法(亲测可修复方的法)

在运行某些软件的时候&#xff0c;计算机提示msvcp120.dll丢失&#xff0c;无法打开运行软件。在第一次遇到这个问题的时候&#xff0c;相信很多人都不知道是怎么回事。下面小编把msvcp120.dll是什么以及如何解决这个问题的详细方法给大家科普一下。 问题描述&#xff1a; 在使…

00-Hadoop入门

Hadoop入门 Hadoop四高 1&#xff09;高可靠性 Hadoop底层维护多个数据副本&#xff0c;所有即使hadoop某个计算元素或存储故障&#xff0c;也不会造成数据丢失 2&#xff09;高扩展性 在集群间分配任务数据&#xff0c;可方便的扩展数以千计的节点 3&#xff09;高效性 …

Ubuntu安装MySQL 8.0与Navicat

目录 Ubuntu安装MySQL 8.0 1、更新软件包列表 2、安装 MySQL 8.0 3、启动 MySQL 服务 5、确保MySQL服务器正在运行 5、root 用户的密码 6、登录MySQL&#xff0c;输入mysql密码 7、MySQL默认位置 Ubuntu安装Navicat 1、下载 Navicat 2、额外的软件包 3、执行命令 U…

周末在家值班,解决几个月前遗忘的Bug

问题&#xff1a; 周末被迫在家值班&#xff0c;无聊之际打开尘封已久的Bug清单&#xff0c;发现有Bug拖了几个月还没解决… 场景是这样子的&#xff0c;有个功能是拿Redis缓存热点数据进行展示&#xff0c;暂且称它为功能A&#xff0c;有个另外的功能B&#xff0c;它会去更新缓…

lifecycleScope Unresolved reference

描述 导入了lifecycle.lifecycleScope&#xff0c;但是在activity中使用lifecycleScope报错出现Unresolved reference找不到引用。 导包 import androidx.lifecycle.lifecycleScope使用 lifecycleScope.launch(Dispatchers.IO) {...}错误 方案 代码中的activity继承Activ…