平衡小车的控制算法(PID,LQR,MPC)及arduino程序导航贴

news/2024/11/15 1:44:36/

目录

平衡小车电机位置测试小实验

1.编码器脉冲计数

PID控制算法

平衡小车PID调参实验

位置环

2.编码器计数转换角度

小车整体的动力学建模

通过特征值判断系统动态特性

龙伯格观测器


平衡小车电机位置测试小实验

1.编码器脉冲计数

const byte LeftMotorInterruptP = 22;  //左电机编码器中断引脚
const byte LeftMotorCountP = 23;      //左电机编码器计数引脚
const byte RightMotorInterruptP = 18; //右电机编码器中断引脚
const byte RightMotorCountP = 19;     //右电机编码器计数引脚const byte MotorDriverEn = 5;         //电机驱动器使能
const byte LeftMotorP1 = 15;          //左电机控制io口1
const byte LeftMotorP2 = 13;          //左电机控制io口2
const byte RightMotorP1 = 16;         //右电机控制io口1
const byte RightMotorP2 = 17;         //右电机控制io口2volatile long LeftMotorCounter = 0;   //左电机中断计数位置
volatile long RightMotorCounter = 0;  //右电机中断计数位置portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;  //声明一个portMUX_TYPE类型的变量,利用其对主代码和中断之间的同步进行处理
portMUX_TYPE mux_1 = portMUX_INITIALIZER_UNLOCKED;//左电机中断函数
void LeftMotorInterruptF() {portENTER_CRITICAL_ISR(&mux_1);delayMicroseconds(10);  //延时20ms作为消抖,如果是很稳定的中断可以不加或者加很少的消抖时间if(digitalRead(LeftMotorInterruptP) == LOW)  //因为是上拉触发,所以在消抖时间完后读取引脚高低电平,如果还是为低那么就代表出现了一次稳定的中断{if(digitalRead(LeftMotorCountP)==LOW)LeftMotorCounter++;elseLeftMotorCounter--;Serial.print("左边电机位置:");Serial.println(LeftMotorCounter);}portEXIT_CRITICAL_ISR(&mux_1);
}
//右电机中断函数
void RightMotorInterruptF() {portENTER_CRITICAL_ISR(&mux);delayMicroseconds(10);  //延时2ms作为消抖,如果是很稳定的中断可以不加或者加很少的消抖时间if(digitalRead(RightMotorInterruptP) == LOW)    //因为是下拉触发,所以在消抖时间完后读取引脚高低电平,如果还是为低那么就代表出现了一次稳定的中断{if(digitalRead(RightMotorCountP)==LOW)RightMotorCounter--;elseRightMotorCounter++;Serial.print("右边电机位置:");Serial.println(RightMotorCounter);} portEXIT_CRITICAL_ISR(&mux);
}void setup(){Serial.begin(115200);Serial.println("中断测试实验"); //off motor enablepinMode(MotorDriverEn,OUTPUT);digitalWrite(MotorDriverEn,LOW);pinMode(LeftMotorP1,OUTPUT);pinMode(LeftMotorP2,OUTPUT);pinMode(RightMotorP1,OUTPUT);pinMode(RightMotorP2,OUTPUT);digitalWrite(LeftMotorP1,LOW);digitalWrite(LeftMotorP2,LOW);digitalWrite(RightMotorP1,LOW);digitalWrite(RightMotorP2,LOW);pinMode(LeftMotorInterruptP, INPUT_PULLUP);  //先把引脚设置为上拉输入模式pinMode(RightMotorInterruptP, INPUT_PULLUP);  //先把引脚设置为上拉输入模式pinMode(LeftMotorCountP,INPUT);pinMode(RightMotorCountP,INPUT);attachInterrupt(digitalPinToInterrupt(LeftMotorInterruptP), LeftMotorInterruptF, FALLING);attachInterrupt(digitalPinToInterrupt(RightMotorInterruptP), RightMotorInterruptF, FALLING);
}void loop(){}

PID控制算法

电机速度环和位置环请看这篇文章:

PID控制算法及arduino应用(电机调速和位置控制)_Allen953的博客-CSDN博客​​​​​​​

2.编码器计数转换角度


const int CountperCircuit = 390;      //390个脉冲为一圈
const double pi = 3.141592653;        //piconst byte LeftMotorInterruptP = 22;  //左电机编码器中断引脚
const byte LeftMotorCountP = 23;      //左电机编码器计数引脚
const byte RightMotorInterruptP = 18; //右电机编码器中断引脚
const byte RightMotorCountP = 19;     //右电机编码器计数引脚const byte MotorDriverEn = 5;         //电机驱动器使能
const byte LeftMotorP1 = 15;          //左电机控制io口1
const byte LeftMotorP2 = 13;          //左电机控制io口2
const byte RightMotorP1 = 16;         //右电机控制io口1
const byte RightMotorP2 = 17;         //右电机控制io口2volatile long LeftMotorCounter = 0;   //左电机中断计数位置
volatile long RightMotorCounter = 0;  //右电机中断计数位置
volatile double LeftMotordeg = 0.0;   //左电机中断计数位置
volatile double RightMotordeg = 0.0;  //右电机中断计数位置portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;  //声明一个portMUX_TYPE类型的变量,利用其对主代码和中断之间的同步进行处理
portMUX_TYPE mux_1 = portMUX_INITIALIZER_UNLOCKED;//左电机中断函数
void LeftMotorInterruptF() {portENTER_CRITICAL_ISR(&mux_1);delayMicroseconds(10);  //延时20ms作为消抖,如果是很稳定的中断可以不加或者加很少的消抖时间if(digitalRead(LeftMotorInterruptP) == LOW)  //因为是上拉触发,所以在消抖时间完后读取引脚高低电平,如果还是为低那么就代表出现了一次稳定的中断{if(digitalRead(LeftMotorCountP)==LOW)LeftMotorCounter++;elseLeftMotorCounter--;LeftMotordeg = double(LeftMotorCounter)/double(CountperCircuit)*360.0;Serial.print("左边电机位置:");Serial.print(LeftMotordeg);Serial.println("'C");}portEXIT_CRITICAL_ISR(&mux_1);
}
//右电机中断函数
void RightMotorInterruptF() {portENTER_CRITICAL_ISR(&mux);delayMicroseconds(10);  //延时2ms作为消抖,如果是很稳定的中断可以不加或者加很少的消抖时间if(digitalRead(RightMotorInterruptP) == LOW)    //因为是下拉触发,所以在消抖时间完后读取引脚高低电平,如果还是为低那么就代表出现了一次稳定的中断{if(digitalRead(RightMotorCountP)==LOW)RightMotorCounter--;elseRightMotorCounter++;RightMotordeg = double(RightMotorCounter)/double(CountperCircuit)*360.0;Serial.print("右边电机位置:");Serial.print(RightMotordeg);Serial.println("'C");} portEXIT_CRITICAL_ISR(&mux);
}void setup(){Serial.begin(115200);Serial.println("中断测试实验"); //off motor enablepinMode(MotorDriverEn,OUTPUT);digitalWrite(MotorDriverEn,LOW);pinMode(LeftMotorP1,OUTPUT);pinMode(LeftMotorP2,OUTPUT);pinMode(RightMotorP1,OUTPUT);pinMode(RightMotorP2,OUTPUT);digitalWrite(LeftMotorP1,LOW);digitalWrite(LeftMotorP2,LOW);digitalWrite(RightMotorP1,LOW);digitalWrite(RightMotorP2,LOW);pinMode(LeftMotorInterruptP, INPUT_PULLUP);  //先把引脚设置为上拉输入模式pinMode(RightMotorInterruptP, INPUT_PULLUP);  //先把引脚设置为上拉输入模式pinMode(LeftMotorCountP,INPUT);pinMode(RightMotorCountP,INPUT);attachInterrupt(digitalPinToInterrupt(LeftMotorInterruptP), LeftMotorInterruptF, FALLING);attachInterrupt(digitalPinToInterrupt(RightMotorInterruptP), RightMotorInterruptF, FALLING);
}void loop(){}

小车整体的动力学建模

这个模型不是很严谨,因为不总是比较小,而且我们的目的也不是仅仅为了保持小车平衡,在保持平衡的同时也要使得趋于0。不过暂时粗略先用这个动力学模型来做,后面再重新建立更加准确的模型进行优化。

经过测量,我的平衡小车

质量:m=0.748kg

质心高度约为40mm:L=0.04m

重力加速度用9.8:g=9.8m/s^2

那么动力学模型即为:

通过特征值判断系统动态特性

 计算特征值

可以看到,两个特征值并不都小于0.也就是说系统不稳定。

这跟我们的经验也一样,如果平衡小车没有输入的话,它将发生倾倒。

然后我们看一下能控性

也就是Co矩阵的秩,如果Co矩阵是满秩的话,就意味着这个系统是可控的。

 可以看到Co矩阵是满秩的,也就意味着我们的系统是可控的。

然后我们就可以设计控制器进行控制了。

 我们设计一个线性控制器

这时,我们的控制器就设计好了,输入u就如上图最后一行一样。

可是我们的z并不知道啊。我的平衡小车上面是有一个mpu6050模块,可以测得小车的倾角,也就是

但是我们的 。现在我们可以用mpu6050这个传感,也就是倾角,但是倾角的角加速度我们没有传感器可以测得。也就是说我们现在无法知道z的准确值。

由于我们的控制器u是z的函数,因此我们要想办法得知z。那么接下来我们将使用一个观测器来得到

龙伯格观测器

推导

求出L以后,我们得出了观测器的表达式。

 其中为估计的初值,可以任意估计,因为随着时间增加,这个值会收敛到跟实际值几乎一样。

u为输入,这里我们的input为,也就是平衡小车轮子在水平方向的加速度。

y就是倾角

那么我们的观测器可以写为具体的表达形式为:


http://www.ppmy.cn/news/345289.html

相关文章

平衡小车从原理到实践

平衡小车从原理到实践 作者:公众号:小白学移动机器人 关于内容:参考很多网上大佬的博客加上自己的理解而成,适合平衡车初学者和想要了解原理的小伙伴。 1、平衡小车控制原理 先记住一句话,直立环和速度环的结合是保…

平衡车制作---原理篇

平衡车制作—原理篇 文章目录 平衡车制作---原理篇前言直立控制直观感受内部机理 速度控制方向控制总结 前言 本篇教程内容主要来自于《直立平衡车模参考设计方案》,且这里是从概念层面讲述的并没有具体的控制理论方面的内容。有了这些概念方面的知识制作一个初级版…

三天让车立起来!STM32平衡车入门PID —— 第三天(PID调参)

说明:本文章适用于STM32初学者,想完成一个好玩且有深度的项目但不知道从何下手的同学。 PID调参是平衡车的精髓所在,参数整定的好坏直接影响到平衡车的平衡效果。有的车平衡时来回晃而参数选的好的车就能稳稳地平衡在原地。可见PID调参在PID中…

JavaScript DOM

1、DOM介绍 DOM(Document Object Model):文档对象模型。 将 HTML 文档的各个组成部分,封装为对象。借助这些对象,可以对 HTML 文档进行增删改查的动态操作。 1.1、Element元素的获取操作 具体方法 方法名说明getElementById (id 属性值)根…

新手如何组装一台电脑

新手如何组装一台电脑 首先,我们要先了解一台电脑的基本构成由哪些? CPU显卡主板散热器磁盘内存电源机箱显示器 通常我们需要根据自己对电脑的定位,根据需求和资金确定CPU和显卡 CPU CPU主要有AMD和Intel。 Intel芯片单核能力足够强&…

BUUCTF 大帝的密码武器 1

题目描述:(下载题目,然后修改后缀名为.zip打开:) 公元前一百年,在罗马出生了一位对世界影响巨大的人物,他生前是罗马三巨头之一。他率先使用了一种简单的加密函,因此这种加密方法以…

Datax+DataX-Web分布式搭建

DataxDataX-Web分布式搭建 DataX简介 DataX 是一个异构数据源离线同步工具,致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 DataX本身作为数据同步框架,将不同数据源的同步…

服装库存管理系统 Mybatis+Layui+MVC+JSP【完整功能介绍+实现详情+源码】

完整源码资料 地址直达:http://t.csdn.cn/RWsGw 前言 这是大二时候写的第一个Java项目,框架基本上都没有用到、而且用到的技术很老很老。只简单使用了一个Mybatis简化数据库的操作。前端框架用的还是Layui,贼难用。闲的无聊,对这…