浅谈两轮平衡车的控制原理(续)

2023-05-16

前言:上次云里雾里的说了一通,不知道对平衡车的控制有没有说到点子上。单纯的讲解原理可能会很无聊,但是作为一个技术宅来说,就算头皮发麻也要接着看下去。哈哈,吾理小子争取用通俗的语言把自己懂的知识讲解出来。

好了,闲话少说,进入正题。上文已经做好了平衡车站立起来的全部准备工作,接下来就是控制的核心了,如果对上面讲到的内容还没有看到,建议先看上一篇,否则会有莫名其妙的感觉。

首先,说说陀螺仪的安装位置,建议有条件的话装在电机轴的正上方,两轮子中点处,这样做的好处是角速度响应比较平均。但是,吾理小子的条件有限,陀螺仪装在了右侧轮子附近,安装位置看下图。(PS:陀螺仪一定要装稳)

安装好陀螺仪之后,接下来开始写程序。关于MPU6050的程序,吾理小子不想啰嗦,直接说比较关键的地方吧。相信用过STM32的小伙伴对原子哥不会陌生吧,小编也是原子哥的受益者,在这里顺便感谢一下原子哥。

小编移植了原子哥的MPU6050程序,所以要说一下初始化问题。我们知道陀螺仪上电之后要初始化,然后要自校准。原子哥的程序是以上电的时候陀螺仪的姿态为参考,解算姿态。也就是说,每次测量的姿态都是以上电时刻为基准的。那么可能有人和小编一样纳闷,如果每次都是相对的参考平面,那岂不是要每次扶着平衡车上电初始化啊。考虑到这个问题之后,小编尝试寻找MPU6050的绝对参考平面。

原子哥初始化程序中有一个DMP初始化,打开看看

看到下面有一个自检函数,Go to你会发现有这样一段代码:

敲黑板,画重点啦。这就是获取当前加速度计的值,然后将其设置为基础值。各位看官明白什么意思了吧,就是自检函数中获取加速度计的值,将此时的值设置为基础值,也就是参考平面啦!

啦啦啦,那我们把这个值设置为零就和初始位置无关了吧,所以将此时的加速度计的值置零就行了,修改之后如下:

至此,我们上电之后的参考平面就是水平面啦,是不是很简单呢!

好了,接下来就是绝对无聊的代码与思路了。首先,简单描绘一下控制思路

各位请看上图,虽然它很简陋,但是基本能够说明问题。读取陀螺仪数据,通过PID控制器计算得到PWM的占空比输出,控制电机将车架姿态调整,继续读取陀螺仪数据,如此反复,就完成了动态调节。

程序中要实现这样的效果,一般会使用单片机内部定时器,开启定时器中断,在固定的时间节点去读取陀螺仪数据,然后进行PID计算,最后控制电机进行一次调节。小编也是这样实现PID调节的,定时器10ms中断一次。定时器的配置与中断服务函数就不贴了,只着重描述直立环的PID代码。 

void PID_Balance_Cal(Balance_PID * PID,float Angle,float Gyro)
{
	PID->Now  = Angle - 2;	
	PID->Out  = PID->Kp * PID->Now
	          + PID->Kd * Gyro;
}

这是直立环PID代码,入口参数有三个。第一个是PID结构体,第二个是测量的角度值,第三个是角速度值。后两个量与MPU6050安装方位有关。小编的陀螺仪安装位置与姿态第一幅图拍过了,小车前倾时roll角度变小,后仰时roll角度变大。小车前倾与后仰时,陀螺仪的数据也就是角速度变化的是x轴的,也就是gyrox。因此,调用PID的形参就是roll和gyrox。

再来看函数具体内容,第一行是计算当前误差,2代表的是小编平衡车的机械中值,这个在上一篇的开头中有说明。车架与重量分布不一样,这个值也不一样,一般都是在0°左右。第二行是PID的输出,就是常规位置式PID的公式。这里我们只用到了PD项,没有用到积分项,这是借鉴前人的经验而已。至于微分项为什么乘以gyro,现在进行一点自己的理解与说明。

大家调试过位置式PID的同志们都知道,计算公式是

PID->Out=(PID->Kp * PID->Error) + (PID->Ki * PID->Error_I) + (PID->Kd * PID->Error_D); 

在平衡车中用到的PID形式好像有点看不懂了。有没有这种感觉,其实并不是这样的,上面两个实质是一样的。一般来说,求微分项就是求角度的变化趋势,也就是求角度的微分,他的物理意义实际就是角速度,因此我们直接用陀螺仪角速度乘以微分项系数来表示微分结果,这是合情合理的吧!各位道友,不知小编的理解是否正确,欢迎各位批评指正。

好了,直立环的核心代码就这么几行,接下来就是参数整定了。

嗯……再三考虑,还是先把定时器中断里面的代码贴一下吧!

typedef struct
{
	float Kp;
	float Ki;
	float Kd;
	
	float Out;
	
	float Now;
	float Last;
	float Earlier;
	
	float Error;
	float Error_I;
	float Error_D;

} Balance_PID;  //定义直立环结构体,很多参数都是冗余。小编太懒,不想改

Balance_PID  Balance_pid; //初始化直立环结构体

void TIM5_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) 
	{
	    TIM_ClearITPendingBit(TIM5, TIM_IT_Update); //清中断标志
		
	    if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)  //读取陀螺仪数据
	    { 
		    MPU_Get_Accelerometer(&aacx,&aacy,&aacz);	//获取加速度计数据
		    MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);	//获取陀螺仪数据

		    PID_Balance_Cal(&Balance_pid,roll,gyrox);	//调用直立环 
		    Set_Motor_PWM((int)Balance_pid.Out,(int)Balance_pid.Out);  //设置PWM
	    }
	}
}

代码应该没有什么说的,自行看注释就好。

先确定参数正负,再确定大小。

设置Kp=100。烧代码,拿起小车,向前倾,发现车轮向后加速。这样的效果也就是说轮子的响应是加速小车倒下,在不是我们想要的结果,肯定是正负错了。

设置Kp=-100。烧代码,拿起小车,向前倾,车轮向前加速,向后倾,车轮向后加速,如此这就是正常的效果了。

同样的实验过程确定Kd:

设置Kp=0,Kd=0.5。烧代码,拿起小车,猛向前倾,发现车轮向后加速。这样的效果也就是说正负错了。

设置Kp=0,Kd=-0.5。烧代码,拿起小车,猛向前倾,车轮向前加速,猛向后倾,车轮向后加速,正常的效果。

上面的参数大小为什么这样取值,和PWM的计数上限有关。参数大小范围,可以这样评估。假如计数器上限是2000,车架的角度变化是-9°~9°,那么我们的Kp大概就在(2000/18=)100左右。我们知道P的系数是调整的步幅,步子太大,响应速度快,但是不稳定,步子太小可能达不到期望值。基本就是这个意思了。上面设置d的系数很小,是因为小车猛向前或者后时,gyrox的值可能达到上万的数值,所以这个只取0.5。好了,具体的细节就不多说了,参数整定多了,自然会明白。

至此,直立环就剩下参数的整定啦。各位可参见平衡小车之家的整定教程。讲道理,参数整定的好的话,小车应该可以很听话的站立起来了。但是小编遇见了下面的问题:

基本现象是小车能够站立,也能够看出在不断调整,但是小车总会慢慢旋转,就是右轮的动作幅度很大,左轮几乎不动,看到的现象就是小车在慢慢的原地转圈。其实小车稳定性还是很高的,但是就是会莫名的转圈,再怎样调整参数,都无法解决这个问题。小编有点抓狂了,好难受。(抱住肉肉的自己)

随后,仔细回顾代码发现,PD计算出的PWM控制两个电机是相同的值。灵光一闪,我已经知道问题在哪里啦,肯定是驱动板不对称或者电机参数不对称造成的,也就是说给相同的PWM两个电机响应的不一样。我决定尝试用编码器来测试一下,看来土豪级的编码器还是排上用场了。具体这样操作的:

 

初始化左右两电机的编码器,设置PWM:Set_Motor_PWM(1200,1200);

void Get_Speed_Data(void)          //获取当前速度
{
	Left_encode_val = TIM_GetCounter(TIM8);
	Right_encode_val= TIM_GetCounter(TIM4);	//读计数器值
	
	TIM8->CNT = 15000;    //将计数值赋初值
	TIM4->CNT = 15000;
	
	Left_Speed_Val= (15000-Left_encode_val)*2.578;  //uint:m/s    *1.0035
	Right_Speed_Val=(15000-Right_encode_val)*2.578;  //uint:m/s //计算实际速度
}

编写读取编码器数据子函数,为了放置缩小误差,我们直接看编码器的值。在定时器中断中调用上面子函数,然后把得到的值实时显示在SPI接口屏幕上。(豪华配置,一个个都体现了出来)如果没有屏幕,此时可以用串口看数据。在死循环中调用显示函数,具体代码

	while(1)
	{
//		sprintf(s,"%.3f",roll);
//		Gui_DrawFont_GBK16(60,16,RED,GRAY0,(unsigned char*)s);
			
		sprintf(s,"%d",Left_encode_val-15000);
		Gui_DrawFont_GBK16(60,80,RED,GRAY0,(unsigned char*)s);
		
		sprintf(s,"%d",Right_encode_val-15000);
		Gui_DrawFont_GBK16(60,96,RED,GRAY0,(unsigned char*)s);
	} 

将左右轮的编码器值显示在屏幕上。如此,在PWM均为1200情况下,在10ms(定时器中断间隔)时间段内,左右电机编码器的值,左轮数值22左右,右轮数值34左右。

我的天呐!各位发现了没有,10ms的时间居然相差这么大,那么为什么会原地转动,原因和预料的一样。

怎么办嘞?补偿呗,通过补偿发现,当设置左轮为1370时,和右轮编码器数值几乎相等,这就圆满啦(哈哈哈,兴奋一下)。注意,反相同样需要补偿。

补偿之后,还原原来的代码,烧代码,看效果。

哇,见证奇迹的时刻到了,小车直立环效果感人啊!站立的 非常稳,速度几乎为零。

各位道友可能看到说仅一个直立环是不足以让小车站稳的,那么小编的结论并非如此,仅仅直立环也可以站稳而且很稳。

PS:仅直立环是否能够站稳和小车的安装、结构、重量分布等等都有关系,因此,调试过程中一定以自己的现象为准,切记不能盲从。

最关键的直立环调试完了,效果感人,那么今天的内容也接近尾声啦!

随后的速度与转向环,吾理小子不想再接着写了,因为没有特别难的,各位自己修行吧,哈哈哈!多说一句,速度环不是常规的负反馈,而是正反馈。这样描述一下,就是小车速度要想降下来,必须先加速然后才能减速。欲知具体效果,需自身体验,谢谢!

感谢原子哥和平衡小车之家,有了你们这些大佬的默默付出,才会有我们这群小妖怪的茁壮成长!

最后,写的有点凌乱,有什么不对的地方请各位批评指正!

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

浅谈两轮平衡车的控制原理(续) 的相关文章

  • 解读编码和文件读写

    解读编码和文件读写 编码的本质就是让只认识0和1的计算机 xff0c 能够理解我们人类使用的语言符号 xff0c 并且将数据转换为二进制进行存储和传输 这种从人类语言到计算机语言转换的形式 xff0c 就叫做编码表 xff0c 它让人类语言
  • BeautifulSoup库的简单使用

    BeautifulSoup是什么 网页解析库BeautifulSoup xff0c 用来解析和提取网页中的数据 安装BeautifulSoup库 BeautifulSoup库目前已经进阶到第4版 xff08 Beautiful Soup 4
  • 运行地面站详细步骤

    第一步 xff1a 打开bin目录 xff0c 保留Backup DLL文件夹 xff0c 删除除Backup DLL文件夹之外的所有文件 xff1b 第二步 xff1a 打开Backup DLL文件夹 xff0c 复制里面所有的dll 粘
  • 关于qt和js的html一些修改

    1 调试打印js文件 maptype tms html 文件 xff0c 没有qdebug 和printf 可以用 xff0c 但可以用alert 来代替 xff0c 用alert 地图上会出现对应窗口显示 xff0c 来判断程序 逻辑 2
  • qt+directshow usb摄像头及音频设备录制视频

    最近来了个项目 xff0c 有一块功能是usb摄像头录制视频并且录音的实现 xff0c 网上的东西七七八八什么技术都有 xff0c 先用opencv打了半天环境不能录音频 xff0c 后来用ffmpeg xff0c 原谅我太菜 xff0c
  • VSCode中Git解决冲突的步骤

    VSCode中Git解决冲突的步骤 1 gt gt 合并分支后 如果存在冲突 右下角会出现一个提示框 提示 存在合并冲突 请在提交之前解决这些冲突 2 gt gt 左边导航第三个图标中 xff0c 找到产生冲突的文件 3 gt gt 打开文
  • VsCode一定要安装的几个插件

    1 Vetur VUE语法高亮 智能感知 Emmet等 xff0c 包含格式化功能 xff0c Alt 43 Shift 43 F xff08 格式化全文 xff09 xff0c Ctrl 43 K Ctrl 43 F xff08 格式化选
  • ccm-slam环境配置

    ccm slam 配置过程记录 介绍 xff1a 一种协同视觉slam方法 传统的slam是一个机器人完成定位与建图的任务 xff0c 但对于大范围的环境 xff0c 多机器人协同建图往往能提高效率 xff0c ccm slam就是基于这个
  • 从大到小排序,Comparator类型

    import java util Arrays import java util Comparator public class Main public static void main String args 注意 xff0c 要想改变默
  • 11种服务器编程语言对比(附游戏服务器框架) 2020.06

    各语言对比 语言版本TIOBE排名垃圾回收类型系统性能Web后端非Web后端特性Java142是中Python3 83是动态低C 43 43 174高不适合Node js147 是动态低PHP7 48是动态低不适合Go1 1412是中Rub
  • 【stm32定时器配置步骤和相关概念解析——LL库】

    系列文章目录 文章目录 系列文章目录前言一 cubeMX定时器介绍二 通用寄存器三 PWM模式四 LL库 PWM模式 xff08 定时器14为例 xff09 1 结构体说明2 LL库代码 前言 一 cubeMX定时器介绍 Slave Mod
  • 华为MateBook&暗影精灵游戏本恢复出厂设置

    总目录 文章目录 总目录前言一 华为MateBook恢复出厂设置1 接上电源2 重启 开机按F10 二 暗影精灵游戏本恢复出厂设置1 接上电源2 重启 开机按F11 前言 记一次个人华为笔记本和暗影精灵游戏本的恢复操作 xff0c 说不准下
  • C/C++类库大全(附github连接)

    C 43 43 资源大全中文版 浏览中发现一篇总结的很全的c c 43 43 类库 xff0c 在此做记录 xff0c 以备不时之需 github地址 xff08 内有各个库的源码连接 xff09 https github com jobb
  • VScode 中 Clangd 使用

    1 VScode 中 Clangd 使用 VScode 中 Clangd 优缺点 优点 占用系统资源确实比 C C 43 43 少了很多 xff0c 无论是 CPU 还是 内存的使用 xff08 最重要 xff09 缺点 操作相较于 C C
  • FreeRTOS 线程安全的printf输出(使用STM32F103)

    https blog csdn net baidu 23187363 article details 53811144 环境 STM32F103开发板 HAL库 xff08 标准库也没事换个串口输出函数就行 xff09 MDK5 28 ST
  • Windows下配置sphinx+reStructuredText详解

    Windows下配置sphinx 43 reStructuredText详解 最近有朋友想在windows下做个人笔记 xff0c 没有找到顺手的工具 xff0c 问我有什么好的工具推荐 正好前两天在网上看到一款做文档的利器sphinx 4
  • 进程的组成部分

    在UNIX系统中进程由以下三部分组成 xff1a 进程控制块PCB 数据段 正文段 进程控制块 PCB 是用来记录进程状态及其他相关信息的数据结构 PCB是进程存在的唯一标志 xff0c PCB存在则进程存在 系统创建进程时会产生一个PCB
  • 对一个程序的理解

    一 什么是程序 1 程序的结构 指令 数据 2 指令 操作CPU的一段指令集合 xff0c 更详细的说 xff0c 是对数据的加载 xff0c 移动 xff0c 以及需要进行的计算的集合 指令存储在 非易失存储器 xff08 一般指 xff

随机推荐

  • mv替换文件名前缀shell命令

    for name in prefix do mv name 96 echo e name sed s prefix g 96 done
  • VSCode Workspace使用,以及file.exclude、search.exclude的使用模板

    代码如下 xff1a 文件名 xff1a Project code workspace 文件描述 xff1a 此文件文件为VSCode工作区启动文件 文件内容 xff1a 代码路径 工作区设置 不包含的文件 包含路径 文件编码 针对的编译器
  • roslaunch turtlebot_gazebo turtlebot_world.launch 报错ResourceNotFound

    报错 xff1a ResourceNotFound gazebo ros 这里是引用 logging to home kwunphi ros log e14aa722 32b9 11ea 94f7 00d8613afe77 roslaunc
  • 基于MDK Keil将中断及中断服务函数定位到RAM中的.sct文件

    VectorTable ROM 0x08000000 0x00000200 VectorTable RAM 0x20000000 0x00000200 o RESET 43 First IntFunction ROM 0x08000200
  • Linux镜像各种文件名来源

    vmlinux或vmlinuz xff1a Linux直接编译得到 的elf文件 Image xff1a 上面的 elf 文件会比较大 xff0c 为了烧录方便 xff0c 会使用 objcopy工具制作成镜像文件 xff0c 叫 Imag
  • 字节序最本质的地方

    个人理解 xff1a 1 数据的传输路径是 内存 gt 总线 gt 内存 xff1b 2 内存有存放顺序 xff1b 3 总线有发送顺序 xff1b 4 不同的机器内存的存放顺序可能不同 xff1b 5 总线发送顺序也有不同 xff1b 所
  • gcc 关于目标平台相关选项的查询

    gcc target help 列出目标平台可以指定的选项 xff0c 包括gcc选项 汇编选项 链接选项 gcc help 61 target 列出目标平台可以指定的选项 xff0c 只有gcc选项 gcc march 61 armv7
  • 描述点云关键点提取ISS3D、Harris3D、NARF、SIFT3D算法原理

    ISS3D xff08 Intrinsic Shape Signatures 3D xff09 xff1a ISS3D算法是一种基于曲率变化的点云关键点提取算法 它通过计算每个点与其近邻点的曲率变化 xff0c 得到该点的稳定性和自适应尺度
  • 描述相机内部参数以及外部参数

    内部参数和外部参数是数字摄影测量中经常使用的两个概念 xff0c 它们分别用于描述相机内部性能和相机与物体之间的几何关系 内部参数 xff1a 内部参数是相机的内部性能参数 xff0c 包括焦距 主点位置 径向畸变等 这些参数决定了相机成像
  • 最优化建模、算法与理论(二)—— 典型优化问题

    参考书籍 最优化 xff1a 建模 算法与理论 文章目录 1 线性规划2 最小二乘问题3 复合优化问题4 随机优化问题5 半定规划6 矩阵优化7 整数优化附录 常用软件包 库或软件 1 线性规划 一般形式 min
  • 蒙特卡罗求积分(使用MATLAB实现,分层抽样,重点抽样,对偶变量,控制变量,Metropolis Hasting,Gibbs)

    蒙特卡罗求积分 64 author HCF 背景概述 为了解决某问题 xff0c 首先需要把它变成一个概率模型的求解问题 xff0c 然后产生符合模型的大量随机数 xff0c 最后对产生的随机数进行分析从而求解问题 xff0c 这种方法叫做
  • docker容器编译程序 的两种方案

    如果用docker 容器编译程序 有两种方案可供选择 1 xff0c 激活镜像作为slave编译 采用Jenkins提供的jnlp slave 或ssh slave 标准镜像二次封装 xff0c 或者初始镜像 xff0c 然后通过label
  • 安卓与串口通信-校验篇

    前言 一些闲话 时隔好几个月 xff0c 终于又继续更新安卓与串口通信系列了 这几个月太颓废了 xff0c 每天不是在睡觉就是虚度光阴 xff0c 最近准备重新开始上进了 xff0c 所以将会继续填坑 今天这篇文章 xff0c 我们来说说串
  • vscode的git冲突

    vscode的git冲突 vscode中使用git进行代码管理 xff0c 如果出现冲突了 xff0c git pull会报错 xff0c 需要进行以下步骤 xff1a git stash git pull git stash pop gi
  • 树莓派4b ubuntu mate 18.04设置开机自动登录,解决无HDMI无法开机问题

    一 树莓派4b ubuntu mate 18 04设置开机自动登录 之前安装的是树莓派4b Ubuntu server 的18 04版本 xff0c 通过命令行安装的ubuntu mate 18 04 xff0c 由于官方没有18 04ma
  • TX2 NX核心板-VNC远程桌面

    文章目录 前言一 前期准备二 TX2端安装VNC1 安装vino2 使能VNC服务3 编辑org gnome4 设置为Gnome编译模式5 设置VNC 登录密码6 配置本地网络地址为静态7 开机自启VNC 二 WINDOWS端安装VNC参考
  • docker(三)dockerfile

    文章目录 dockerfile构建过程基础知识dockerfile 的指令简单的dockerfile实验docker historyCMD 和 ENTRYPOUNT的区别举例 tomcat镜像 dockerfile构建过程 编写一个dock
  • FIND_IN_SET函数

    FIND IN SET函数是IN函数的升级版 功能类似 区别在于 如果是常量 xff0c 则可以直接用IN xff0c 否则要用FIND IN SET 函数 MySQL中原型为 xff1a FIND IN SET str strlist 假
  • 浅谈两轮平衡车的控制原理

    前言 xff1a 在IT行业摸爬滚打了好几年 xff0c 好不容易从学生熬成了社会人士 xff0c 通过自己的不断努力又从社会人士熬成了学生 这几年的修行 xff0c 同道博友给了我很多的帮助 xff0c 很早之前就有写博客的想法 xff0
  • 浅谈两轮平衡车的控制原理(续)

    前言 xff1a 上次云里雾里的说了一通 xff0c 不知道对平衡车的控制有没有说到点子上 单纯的讲解原理可能会很无聊 xff0c 但是作为一个技术宅来说 xff0c 就算头皮发麻也要接着看下去 哈哈 xff0c 吾理小子争取用通俗的语言把