学习四旋翼(二):控制方法之串级PID与卡尔曼滤波(含MATLAB示例)

2023-05-16

暑假期间,对于四旋翼有一点兴趣,没有亲手做,但是看了一些资料。这个系列文章只是对自己看的东西的记录,对于想要学习了解相关知识的同学没有任何参考价值!

本篇是系列的第二部分:介绍了我自己对于串级PID和卡尔曼滤波的理解。

1.串级PID

1.PID的思想

PID可以说是最著名的控制方式,公式如下(离散)
y ( n ) = K P e ( n ) + K i ∑ i = 0 n e ( i ) + K d [ e ( n ) − e ( n − 1 ) ] y(n)=K_Pe(n)+K_i\sum_{i=0}^ne(i)+K_d[e(n)-e(n-1)] y(n)=KPe(n)+Kii=0ne(i)+Kd[e(n)e(n1)]
y(n)是输出量,e(n)是目标量与输出量之间的误差。PID就是一个输出量和误差之间的函数。

输出量由这么几个部分组成:
1.比例项:以KP为系数,作为当前的误差对于输出的影响,如果误差越大,就要加大输出;
2.积分项:以KI为系数,作为过去误差对于输出的影响,如果累积的误差越大,输出也要考虑;
3.微分项:以KD为系数,作为将来误差对于输出的影响,如果误差变化率越大,我们预计将来的误差也会越大,所以输出也要考虑。

调节参数的影响:
1.KP越大,则被控质量追踪目标量的速度越快,但是被控质量在目标量附近震荡越大;
2.KD越大,则被控质量变换速度减缓,优点在于震荡也会变小,KD有压制KP的作用
3.KI的作用是消除稳差,但是参数不合适也会有累积效应。

2.串级PID
以我参考的开源四旋翼代码为例讲一讲我的理解:
在控制姿态角度时,使用的就是两级PID串联,第一级输入量是当前实际的偏航角度,目标量是遥控器发送的目标角度。也就是使用外环PID来控制角度,输出量自然就是角速度。

但是,飞行器的主控芯片实际能够控制的,只是桨叶的转速大小,而桨叶转速和角速度之间的关系是不确定的。所以就需要增加一个内环,目标量是外环的输出量,输入为当前的角速度,输出是发送给电调的信号。如果桨叶转速和角速度之间有一个明确的公式,那么一层PID就足够了,但是事实是不行。

外环PID一般不加入积分微分,只有比例P。因为添加I后相应变慢,添加D又会引入噪声。

2.卡尔曼滤波

卡尔曼滤波似乎是一个可以很复杂也可以很简单的东西,下面说一下我自己的理解。举个例子:我们一辆以1m/s匀速行驶的小车,开始离墙10m,1s后离墙距离,按照计算是9m。但是传感器的数据是8.9m,那么我应该信任哪个数据呢?合理的方式是结合两个数据,算出概率期望最大的数值。这个过程就是卡尔曼滤波。

1.运动方程和观测方程
x k = f ( x k − 1 , u k ) + w k ( 1 ) z k = h ( x k ) + v k ( 2 ) x_k=f(x_{k-1},u_k)+w_k (1)\\ z_k=h(x_k)+v_k(2) xk=f(xk1,uk)+wk(1)zk=h(xk)+vk(2)
公式1是运动方程,xk是当前的状态,xk-1是上一个时刻的状态,uk是输入量,wk是噪声。
公式2是观测方程,xk是当前的状态量,zk是观测量,vk是传感器所加入的噪声。
这里要再假设两点:1.马尔可夫性:k时刻的状态只与k-1时刻有关。2.状态xk的概率服从高斯分布。

2.线性系统与卡尔曼滤波
假设状态方程与观测方程都是线性的
x k = A k x k − 1 + u k + w k z k = C k x k + v k x_k=A_kx_{k-1}+u_k+w_k\\z_k=C_kx_k+v_k xk=Akxk1+uk+wkzk=Ckxk+vk
并且假设wk和vk都服从高斯分布,均值为0,方差分别为R和Q。

第一步:确定先验状态的两个方程,由于假定了高斯分布,根据高斯分布的叠加性质,可以求得
P ( x k ∣ x k − 1 , u 1 : k , z 1 : k − 1 ) ∼ N ( A k x k − 1 ^ + u k , A k P k − 1 ^ A K T + R ) P(x_k|x_{k-1},u_{1:k},z_{1:k-1})\sim N(A_k\hat{x_{k-1}}+u_k,A_k\hat{P_{k-1}}A_K^T+R) P(xkxk1,u1:k,z1:k1)N(Akxk1^+uk,AkPk1^AKT+R)
两个先验方程也就得到了
x k ‾ = A k x k − 1 ^ + u k P k ‾ = A k P k − 1 ^ A K T + R \overline{x_k}=A_k\hat{x_{k-1}}+u_k\\\overline{P_k}=A_k\hat{P_{k-1}}A_K^T+R xk=Akxk1^+ukPk=AkPk1^AKT+R
更新方程一共有三个,首先是计算K值卡尔曼增益
K = P k ‾ C K T ( C k P k ‾ C K T + Q k ) − 1 K=\overline{P_k}C_K^T(C_k\overline{P_k}C_K^T+Q_k)^{-1} K=PkCKT(CkPkCKT+Qk)1
然后计算后验概率的分布
x k ^ = x k ‾ + K ( z k − C k x k ‾ ) P k ^ = ( I − K C k ) P k ‾ \hat{x_k}=\overline{x_k}+K(z_k-C_k\overline{x_k})\\\hat{P_k}=(I-KC_k)\overline{P_k} xk^=xk+K(zkCkxk)Pk^=(IKCk)Pk
有很多资料Q和R的定义是反过来的,这样最后的公式也要相应调整。卡尔曼滤波可以从概率上证明是这个系统的最优解。

3.非线性系统到EKF
EKF也就是扩展卡尔曼滤波,对于非线性系统,通常做法是在某个点附近考虑运动方程以及观测方程的一阶泰勒展开。实际运用中,由于矩阵求导太复杂,我感觉我一时半会用不到,这个问题留到以后用到了再说。

4.一个使用卡尔曼滤波的实例:气压计和加速度融合定高
在网上看到一个教学项目,搬到这里来

这里使用MPU6050和DPS130卡尔曼滤波融合定高,首先对系统建模。

用x(k)代表系统在z轴上的状态,那么状态应该包含三个量:高度,速度,加速度。
x ( k ) = [ h ( k ) v ( k ) a ( k ) ] x(k)=\begin{bmatrix} h(k)\\v(k)\\a(k) \end{bmatrix} x(k)=h(k)v(k)a(k)
假设采样周期非常短,可以认为a(k+1)=a(k)
求得状态转移方程
[ h ( k + 1 ) v ( k + 1 ) a ( k + 1 ) ] = [ 1 T 0.5 T 2 0 1 T 0 0 1 ] [ h ( k ) v ( k ) a ( k ) ] \begin{bmatrix} h(k+1)\\v(k+1)\\a(k+1) \end{bmatrix}=\begin{bmatrix} 1&&T&&0.5T^2\\0&&1&&T\\0&&0&&1 \end{bmatrix} \begin{bmatrix} h(k)\\v(k)\\a(k) \end{bmatrix} h(k+1)v(k+1)a(k+1)=100T100.5T2T1h(k)v(k)a(k)
观测量y(k)包括了加速度和气压两个量,所以
y ( k ) = [ P ( k ) a ( k ) ] y(k)=\begin{bmatrix} P(k)\\a(k) \end{bmatrix} y(k)=[P(k)a(k)]
根据气压与高度的线性变化关系,可以求得:
[ P ( k ) a ( k ) ] = [ − 1 / 0.09 0 0 0 0 1 ] [ h ( k ) v ( k ) a ( k ) ] + [ P 0 0 ] \begin{bmatrix} P(k)\\a(k) \end{bmatrix}=\begin{bmatrix} -1/0.09&&0&&0\\0&&0&&1 \end{bmatrix} \begin{bmatrix} h(k)\\v(k)\\a(k) \end{bmatrix} +\begin{bmatrix} P_0\\0 \end{bmatrix} [P(k)a(k)]=[1/0.0900001]h(k)v(k)a(k)+[P00]
这就是观测方程,然后可以开始写卡尔曼滤波代码

这里设定测量误差R和过程误差Q,和上面的推导是反过来的。测量误差R是反映传感器得到信息质量的优劣,传感器得到信号质量越差,则R应越大。Q是过程噪声,如果为0,意味着将预测值当成最终结果。测试时可以先将Q从小往大调整,将R从大往小调整;先固定一个值去调整另外一个值,看收敛速度与波形输出。

代码如下

clear;
load('DataUp.mat');
len = length(z);
% 减去重力加速度后的加速度
a = (z-1)*9.8;

% 参数设置
sam_frq = 1000;
T = 1/sam_frq;
k = 0.09;%压高系数

% 观测误差R、过程误差Q
R = 0.5*eye(2);
R(1,1) = 150;    
R(2,2) = 0.5;
Q = 0.0001*eye(3);
Q(2,2) = 0.00001;

% 状态方程矩阵
F = [1,T,0.5*T*T;0,1,T;0,0,1];
H = [-1/k,0,0;0,0,1];
V = [pre(1);0];

% 数据初始化
Xkf = zeros(3,len);
Z = zeros(2,len);
Z(1,:) = pre;
Z(2,:) = a;
Xkf(:,1) = [0;0;0];
P0 = eye(3);
P0(1,1) = 10;

% 卡尔曼滤波
for i = 2:len
    Xn = F*Xkf(:,i-1);
    P1 = F*P0*F'+ Q;
    K = (P1*H')/(H*P1*H'+R);
    Xkf(:,i) = Xn + K*(Z(:,i)-H*Xn-V);
    P0 = (eye(3)-K*H)*P1;
end

%显示图像
figure;
plot((pre(1)-pre)*0.09);
hold on;
plot(Xkf(1,:));
hold on;
plot(Xkf(2,:));
hold on;
plot(Xkf(3,:));
hold on;
plot(a);在这里插入代码片

读取的MAT文件中共有73655组数据

上图是气压计直接求得高度数据和卡尔曼滤波后的高度数据比较,两者似乎很接近。
相应的速度和加速度经过卡尔曼滤波后的数据也能求出来。
在这里插入图片描述
上图是测量加速度和卡尔曼滤波后加速度对比,绿色滤波前,红色滤波后。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

学习四旋翼(二):控制方法之串级PID与卡尔曼滤波(含MATLAB示例) 的相关文章

  • pytorch: 计算网络模型的计算量(FLOPs)和参数量(Params)

    计算量 xff1a FLOPS xff0c 浮点运算次数 xff0c 指运行一次网络模型需要进行浮点运算的次数 参数量 xff1a Params xff0c 是指网络模型中需要训练的参数总数 第一步 xff1a 安装模块 xff08 tho
  • ROS学习02-拿到NVIDIA JETSON TX2该做些什么

    ROS学习02 拿到NVIDIA JETSON TX2该做些什么 在前一片文章中我们已经将NVIDIA JETSON TX2完美的刷机了 ROS学习01 NVIDIA JETSON TX2 使用Jetpack4 4刷机指南 刷完机后连上显示
  • ROS学习09-NVIDIA JETSON TX2安装配置TOF摄像头Intel® RealSense™ Tracking Camera T265

    ROS学习09 NVIDIA JETSON TX2安装配置TOF摄像头Intel RealSense Tracking Camera T265 这一节继续准备我们机器人的器官 xff0c 在惯性导航方面我们选择了Intel RealSens
  • ROS学习12-NVIDIA JETSON TX2 使用turtlebot3 gazebo模拟仿真机器人

    ROS学习12 NVIDIA JETSON TX2 使用turtlebot3 gazebo模拟仿真机器人 这一节我们要使用turtlebot3搭建一个仿真的机器人及环境 xff0c 这里是基于ROS1中的melodic版本 首先安装turt
  • 全方位移动全向轮、麦克纳姆轮底盘运动学逆解详解(内含电机输出方程)

    全方位移动全向轮 麦克纳姆轮底盘运动学逆解详解 xff08 内含电机输出方程 xff09 开始输出方程介绍定义底盘布局快速计算函数主函数最后 开始 智能小车全方位移动底盘常用包括 xff1a 全向轮底盘 xff0c 麦克纳姆轮底盘 xff0
  • 程序员3年5年10年三个阶段

    第一阶段 三年 三年对于程序员来说是第一个门槛 xff0c 这个阶段将会淘汰掉一批不适合写代码的人 这一阶段 xff0c 我们走出校园 xff0c 迈入社会 xff0c 成为一名程序员 xff0c 正式从书本上的内容迈向真正的企业级开发 我
  • CompletableFuture使用示例

    不进行异常处理 1 runAsync 无返回值 supplyAsync 有返回值 根据idea的提示和变量的范型也能看出来 runAsync 是不返回值的 而supplyAsync则会把比较的结果返回出去 2 thenApply thenA
  • 《Linux驱动:USB设备驱动看这一篇就够了》

    文章目录 一 xff0c 前言二 xff0c USB子系统2 1 USB驱动基础概念2 1 1 USB版本2 1 2 USB主从结构2 1 3 USB的传输类型2 1 4 USB设备描述符2 1 4 1 设备描述符2 1 4 2 配置描述符
  • ModbusPoll和ModbusSlave理解及模拟器ModbusTcp一对一和一对多通讯

    目录 ModbusPoll和ModbusSlave理解 Modbus总概 xff1a 主从区分 xff1a 模拟器简介 xff1a ModbusTcp一对一通讯 ModbusTcp一对多通讯 ModbusPoll和ModbusSlave理解
  • SpringSecurity关于关闭csrf后导致页面元素消失的问题及处理方法

    在学习SpringSecurity时进行自定义登录页面的编写时 xff0c 由于在学习的过程中暂时用不到csrf防护 xff0c 不关闭的话后面可能会因为没考虑csrf防护而遇到一连串的问题 xff0c 且关闭后直接使用GET请求也可以退出
  • 机器人开发ros初识

    首先 xff0c 采用ros系统的机器人一般都是有上位机和下位机的 xff0c 下位机以arduino为例 xff0c 负责订阅上位机发送的topic xff0c 获取信息后通过设计的代码进行相应处理控制硬件 xff0c 比如移动 xff0
  • 使用Python+requests简单实现模拟登录以及抓取接口数据

    前言 xff1a 说起爬虫这个东西 xff0c 大学时我习惯用PHP 43 CURL来实现 xff0c 后来用Java 43 WebMagic来实现 如今刚接触一下Python xff0c 开始了解一下Python的语法和框架等 xff0c
  • 常用数据集网盘免费下载(转载)

    List item 遥感影像库 链接 xff1a https pan baidu com s 1bGLRZo 密码 xff1a ic0t facebook大数据 链接 xff1a https pan baidu com s 1geGBLb9
  • C++连接MySQL 操作的封装

    以前写过一篇 c 43 43 连接mysql 的博客 xff0c 每次都要写类来封装数据库的操作函数 xff0c 参考一位大佬的封装 xff0c 不说了 xff0c 直接上代码 xff1a 头文件如下 xff1a pragma once i
  • C++11 线程池的使用

    本文主要介绍C 43 43 中线程池的实现以及C 43 43 11中新特性 仿函数 线程 互斥量 原子 条件变量等 的使用 xff0c 最终会实现一个简易的线程池 xff0c 可支持传参不传参等任务 目录 一 线程池的用途 1 线程池的作用
  • ubuntu 首次安装后配置开发环境

    目录 1 配置root 密码 2 安装SSH 3 安装网络 4 安装和配置 vim 5 配置C 43 43 开发环境 6 安装代码管理工具 git 6 1 配置邮箱和用户名 7 多用户与图形界面切换 1 配置root 密码 sudo pas
  • window11 无法切换输入法打印不出汉字问题修改

    1 xff09 按 WINDOW 43 R 键启动cmd 窗口 2 xff09 在cmd窗口中输入 services msc 启动服务窗口 3 xff09 找到 TextInputManagementService xff0c 开启即可
  • 在c++中字符串复制与内存复制之间的区别

    1 编程实现strcpy函数 字符串复制的实现 原型char strcpy char strdest const char strSrc 对于上述代码 xff0c 为什么要用char 类型呢 xff1f 为了能够链式表达式 2 内存复制函数
  • static静态变量与普通变量的区别

    1 static全局变量与普通全局变量的区别 全局变量的说明之前再加上static就构成静态全局变量 全局变量本身就是静态存储方式 xff0c 静态全局变量当然也是静态存储方式 这两者在存储方式上没有区别 区别在于 xff0c 非静态全局变
  • VS2013与数据库mysql8.0的连接

    1 准备 xff1a vs2013 mysql 8 0 1 1首先我们到官网上下载mysql 下载完成后解压 xff0c 安装 vs2013下载解压安装 2 我们打开安装后的mysql文件夹 我们一会要重点用到 include 和lib 所

随机推荐

  • 用VS2013中MFC开发视频播放器

    1 搭建开发环境 1 1 vs2013网上有许多软件可以自行下载或者 vs2013的安装包 有需要的留言我给发 1 2 搭建DirectShow开发环境 我参考的书上说要自己下一个DriectShow xff0c 但是我下载了好多次 xff
  • 用VS2013中MFC开发视频播放器(2)

    上一个博客我写了做视频播放器的环境搭建 xff0c 没写完这个项目 xff0c 所以今天在把它详细的写一遍流程 xff0c 介绍一下这个项目的编写 1 需求分析 xff1b 要求开发播放器系统能够播放媒体文件 xff0c 而且还可以进行播放
  • 基于正点原子探索者使用STM32CubeMX+FreeRTOS+LWIP

    开发板是使用正点原子的探索者为例 xff0c PHY芯片可以是LAN8720A和IP101GR xff0c 因为有两份代码参考 xff0c 一份是LAN8720A xff0c 一份是IP101GR 首先第一步 xff1a 我们使用移植好的功
  • C++笔试中遇到的问题

    1 sizeof与strlen的区别 xff1f 答 xff1a sizeof是操作符 xff0c 分配的数组实际所占的内存空间大小 xff0c 不受里面存储内容的影响 strlen是函数 xff0c strlen计算字符串的长度 xff0
  • CRC计算的简单原理及代码实现(python)

    目录 多项式的获取 CRC计算的示例图 示例代码 多项式的获取 举例如下 xff08 其余的多项式依次类推即可 xff09 xff1a 故最终多项式获取的参与异或计算的数据为 xff1a 1011 CRC计算的示例图 假设原始数据为 xff
  • 深度学习训练数据中的特征重要性排名

    查看神经网络模型特征重要性的思路 xff1a 依次变动各个特征 xff0c 通过模型最终预测的结果来衡量特征的重要性 神经网络特征重要性的获取步骤如下 xff1a 训练一个神经网络模型 xff1b 每次对一个特征列进行随机shuffle x
  • (笔记)Python import 其他路径下的文件

    一般情况下 xff0c 如果要import的文件和被import的文件位于同一路径下 xff0c 可以使用 xff1a import 文件名 的方式直接进行引用 但如果这两个文件不在同一路径下 xff0c 就需要在被import的文件路径下
  • (Note)Python osgeo&shapefile库的安装

    1 shapefile anaconda xff1a conda install pyshp pip xff1a pip install pyshpe 2 osgeo 进入Link xff1a https www lfd uci edu g
  • (Note)Python 统计列表中各元素出现的次数

    演示列表 xff1a Demo list 61 1 2 3 3 3 5 6 2 2 0 4 5 2 7 8 4 5 1 3 9 8 7 1 统计列表中不同元素的个数 Demo list 61 1 2 3 3 3 5 6 2 2 0 4 5
  • (Note)海韵&海韵代工的电源-风扇智能启停按钮

    海韵是电源四大厂之一 xff0c 旗下有众多型号的电源 其中 xff0c 部分电源的后部会有一个方形的按钮 xff08 在电源开关左侧 xff09 如图所示 xff1a 这是海韵FOCUS 43 电源特有的 34 HYBRIDMOOE 34
  • (Note)七彩虹30系列显卡——《一键超频》按键

    七彩虹部分30系高端显卡提供了一键超频功能 xff0c 通过按下超频按钮可以实现显卡一键超频 七彩虹显卡的一键超频按钮使用方法 xff1a 按下超频 xff0c 弹起默认 切换需要重启电脑 xff01
  • (Note)优化器Adam的学习率设置

    记录一下知乎看到的问题 xff1a Adam的学习率设置 常用的神经网络优化器Adam的自适应学习率并不是真正意义上的自适应 从统计的角度看 xff0c Adam的自适应原理也是根据统计对梯度进行修正 xff0c 但依然离不开前面设置的学习
  • (Note)深度学习与人工提取的特征

    首先 xff0c 深度学习一般 不需要人工提取特征 如果仅仅给网络提供人工提取的特征 xff0c 反而有可能会造成网络性能的下降 xff08 深度学习模型可能提取到一些人类不易察觉的特征 xff0c 这些特征可能对结果的判定有着较大的贡献
  • Linux驱动开发与裸机开发区别

    Linux驱动开发与裸机开发区别 裸机驱动开发回顾Linux驱动开发思维Linux驱动开发分类 裸机驱动开发回顾 1 底层 跟寄存器打交通 xff0c 有些MCU提供了库 Linux驱动开发思维 1 Linux下驱动开发直接操作寄存器不现实
  • Linux下使用U盘

    第一步 xff1a 插入U盘 xff0c 如果能够识别出U盘 xff0c 则会打印出一些信息 xff1b 第二步 xff1a 查看U盘系统分配给U盘的设备名 xff1b 输入如下命令进行查看 xff1a fdisk l dev sda 如果
  • (Deep Learning)交叉验证(Cross Validation)

    交叉验证 xff08 Cross Validation xff09 交叉验证 xff08 Cross Validation xff09 是一种评估模型泛化性能的统计学方法 xff0c 它比单次划分训练集和测试集的方法更加稳定 全面 交叉验证
  • (Linux)在Ubuntu系统中添加新用户并授予root权限

    向Ubuntu系统中添加新用户并为其授予root权限的步骤如下 打开终端Terminal 输入命令 sudo su 以 root 身份登录 注 sudo su 切换root身份 不携带当前用户环境变量 sudo su 切换root身份 携带
  • (深度学习)类别不平衡数据集中IOU和mIOU的选择

    测试集上的mIOU很高 xff0c 但是实际的分割结果很差 xff0c 几乎没有分割出前景 xff0c 主要是因为要分割的目标占总面积之比太少 xff0c 即出现样本不均衡的问题 此时 xff0c 前景所占的比例太小 xff0c 背景所占的
  • 系统调用,API,运行库函数和C标准库函数的区别

    1 为什么用户程序不能直接访问系统内核模式提供的服务 xff1f 在linux中 xff0c 将程序的运行空间分为内核与用户空间 xff08 内核态和用户态 xff09 xff0c 在逻辑上它们之间是相互隔离的 xff0c 因此用户程序不能
  • 学习四旋翼(二):控制方法之串级PID与卡尔曼滤波(含MATLAB示例)

    暑假期间 xff0c 对于四旋翼有一点兴趣 xff0c 没有亲手做 xff0c 但是看了一些资料 这个系列文章只是对自己看的东西的记录 xff0c 对于想要学习了解相关知识的同学没有任何参考价值 xff01 本篇是系列的第二部分 xff1a