PID深度仿真并通过vofa+打印出数据曲线

文章介绍了使用PID算法控制机器人下潜深度的过程,通过设定目标深度,结合牛顿定律计算加速度、速度和深度。文中提到了Keil5编译器、Vofa+软件用于数据打印和仿真,并强调了C语言基础和PID理解的重要性。同时,给出了PID控制器的初始化和计算函数示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 现在试想以下场景,当机器人正在下浅定深度在某个值

static float depth = 0 //深度为 0
static float v =0 //速度为 0
static float a =0 //加速度为 0
static float m=10 //机器人的质量为 10
static float kv = 1 //在水下受到与速度成正比的比例系数
static float f = 1 //水中的静态阻力
a = (F 推力– kv*v-f)/m //根据牛顿定律求出加速度的值
v +=a //加速度的积分为速度
depth += v //速度积分为深度

使用 pid 算法输入深度值的差,输出为推力的值,不断调试 pid 的参数值 使用单片机的串口(usart)重定向到上位机实时观察 depth 深度的曲线,可以使用 vofa+上位 机软件,实现深度从 0 开始一直闭环到深度 20 的值

以下为vofa+仿真的效果

pid深度仿真

用keil5进行编译,选用vofa+的firewater协议进行数据打印。但是要注意要对“printf”函数进行重定义,强烈建议去看一下小破站江科大自动化科协stm32教程有关于串口数据收发的教程,非常详细易懂。

VOFA+有三种协议设置

  1. rawdata:和普通的串口助手一样,发送什么显示什么。
  2. firewater:最简单在VOFA+里绘制波形的协议,建议仅在通道数量不多、发送频率不高的时候使用。要注意想要打印出数据在“printf”函数中在最后要用“\n”进行换行
  3. justfloat:有一定的数据格式,此协议非常适合用在通道数量多、发送频率高的时候。//设个本菜鸡还没有学

PID部分本站的佬们讲的都很好,可以找一些教程进行学习。

我对PID的理解是

首先要设定一个目标值target,每轮执行程序都要用target-current_depth来计算出error;

1.P比例环节        Pout=P*error P为我们设定的比例系数,由式子可以看出距离越远Pout越大,就像向一个水桶里注水一样,刚开始error大于0注水会用较大的水流注入,当距离我们的目标值越近所用的水流就越小;但当error小于0时就需要从桶中舀出水原理与注水时相同。P的大小可影响Pout的大小,P越大越快,但不宜太大,因为这样会产生过大的波动,影不利于控制。

2.D微分环节      仅仅靠比例环节很难趋近于目标值,因为其产生的是较大的波动,像刹车一样,很难立刻就停下来,所以要依靠微分环节。 Dout=D*(derror/dt),由此得到Dout的大小由误差的变化性速度有关,方向与速度变化方向有关,而且总是与速度方向相反,因此始终会有一个阻尼作用,最终会趋近于目标值。

3.I积分环节        用P和D环节就基本可以趋近于目标值了,那为什们还要用积分环节呢?试想一下,像一个漏水的水桶里注水,漏水就相当于一个静态误差,如果每次像桶内加的水和漏掉的水相等,那水位将不再变化,而加入积分环节,每次都会将误差进行累加,当出现上述情况时,积分环节会加大进水量,从而超过水位不动时的水位线,进而趋近于目标。

这部分我知到写的很烂5555~也借鉴了一些佬的思想,表达能力太差,写错的地方请帮忙指正哈

以下为main函数

#include "stm32f10x.h" 
#include "Serial.h"
#include <stdio.h>

typedef struct 
{
    float Kp; // 比例系数
    float Ki; // 积分系数
    float Kd; // 微分系数
    float target; // 设定值
    float integral; // 积分项
    float last_error; // 上一次的误差
} PID;

PID pid;
// 初始化pid控制器
void PID_Init(PID *pid, float Kp, float Ki, float Kd, float target) 
{
    pid->Kp = Kp;
    pid->Ki = Ki;
    pid->Kd = Kd;
    pid->target = target;
    pid->integral = 0;
    pid->last_error = 0;

}
//计算P I D
float PID_Calc(PID *pid, float feedback) 
{
    
    float error = pid->target - feedback;//计算误差
    float P = pid->Kp * error;//比例项
    pid->integral += error;//积分项
    float I = pid->Ki * pid->integral;
    float derivative = error - pid->last_error;//微分项
    float D = pid->Kd * derivative;   
    pid->last_error = error;//上一次的误差
    float output = P + I+ D;
    return output;
}

int main(void) 
{
    float target = 20; 
   float current_depth = 0;
    float m = 10; 
    float kv = 1; 
    float f = 1; 
    float a = 0; 
    float v = 0; 

    PID pid;
	
    Serial_Init();
    PID_Init(&pid, 5, 0.5, 0.1, target);
    
   while (1) 
		 {
        
        float F = PID_Calc(&pid, current_depth);//推力大小
        
        a = (F - kv * v - f) / m;//加速度
        v += a ;//速度
        current_depth += v ;//深度
 Serial_Printf("%f\n",current_depth);

			}

}

学习过程中遇到了不少麻烦,比如c语言不扎实,对代码的书写能力较弱,所以扎实的c语言功底是十分重要的,还有就是对PID的理解还不够深刻,还需继续学习。

新人写稿 如有错误 欢迎指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值