【平衡小车入门】(PID、FreeRTOS、hal库)

news2024/9/23 13:26:30

本篇博客记录自己复刻的平衡小车

    • 前言
    • 一、硬件需求
    • 二、最终效果
    • 三、整体流程
      • 第一步:stm32通过DRV8833电机驱动模块使用PWM驱动直流减速电机
      • 第二步:理解PID算法在平衡小车中的应用
      • 第三步:PID调参
    • 四、源代码获取

前言

从代码上看,平衡小车的实现是比较简单的,特别是只实现平衡。在平衡的基础上可以加上其他功能:视觉、循迹、避障、蓝牙控制等。项目源码直接使用b站up主:会飞的摄影师呀,然后自己对标准库用的比较多,hal库的库函数大多数不熟悉,在复刻完成之后又在b站看了另一个up(天下行走)的视频,使用标准库+裸机开发,代码很简单,之后可能会在发一篇讲讲后面这个。

一、硬件需求

①MPU6050
②STM32F103C8T6
③oled液晶屏
④18650电池两节
⑤DRV8833电机驱动模块
⑥MP1584EN(5V固定输出降压模块)
⑦HC-05蓝牙模块
⑧JGA25-370直流减速电机(6V/280转每分钟)
⑨面包板或者pcb
⑩底座(用于将两电机连接固定)
其余就是一些小东西:铜柱(M3*60+6)、螺丝,螺母(M3)、杜邦线、万用表、电烙铁套件、双面胶或热熔胶、拨动开关(SS-12F44 3脚2档立式)
下面是pcb板:
在这里插入图片描述
pcb版小车:
在这里插入图片描述
面包板小车:

在这里插入图片描述
搞下面这个面包板的原因是pcb版的效果不好,调参调了挺久还是不那么稳,我想着应该是结构问题,pcb过宽,高度也太高,小车因为惯性就不好平稳,然后换成面包板之后重心降低了很多,重量也轻了,所以之后可能会自己画一个板子,画窄一些。

二、最终效果

①pcb平衡小车:


②面包板平衡小车:


从视频也可以看出来,面包板小车更加平稳。

三、整体流程

第一步:stm32通过DRV8833电机驱动模块使用PWM驱动直流减速电机

这是所有小车的第一步,电机不动那还怎么接下来的步骤,STM32使用定时器可以输出不同的PWM波,将PWM波输出至电机驱动模块,就可以驱动电机转起来了。
在这里插入图片描述
在这里插入图片描述
本项目中就使用上图所示的PWM控制电机速度表来控制两个电机,AIN1连接PA7、AIN2连接PA3(电机1);BIN1连接PA6、BIN2连接PA4(电机2)。AO1、AO2接电机的驱动口,一般是最左和最右那两个,中间四个接口是电机的编码器接口。在进行组装之前,先测试电机的转动方向和转速,并且测量电机的死区,这在设置电机转速时会用到。死区的测法就是从低开始给PWM,看PWM为多少时电机开始转动,那死区就是不转动的那部分PWM区,要想让电机转动起来,那给的PWM就必须大于死区。设置电机最终转速的函数如下:

void Set_PWM(int motor1,int motor2)
{
    if(motor1>0)//正转 
		{
        PWMA2=Dead_Zone+(abs(motor1))*1.17;
        PWMA1=0;
    }
    else//反转
    {
        PWMA2 =0;
        PWMA1=Dead_Zone+(abs(motor1))*1.17;
    }
    if(motor2>0)//正转
		{
        PWMB2 = Dead_Zone+(abs(motor2))*1.17;
        PWMB1 = 0;
    }
    else
    {   PWMB2 = 0;
        PWMB1=Dead_Zone+(abs(motor2))*1.17;
    }
}

其中Dead_Zone就是死区值,abs是绝对值函数。

第二步:理解PID算法在平衡小车中的应用

在平衡小车中想实现PID算法,编码器和姿态传感器(比如MPU6050)是必不可少的。
平衡小车实现PID控制算法,一共需要三个部分:直立环、速度环、转向环。如果只想小车上电之后保持直立,不施加外部干扰的话,只需要直立环就够了;如果想要直立,并且能够抗外界干扰的话就需要直立环+速度环;如果需要蓝牙遥控啥的那就需要再加上转向换。

PID控制就是对偏差进行比例、积分和微分控制,最终目的就是使偏差接近于0。可以看出PID分成三个部分,可以任意组合,直立环一般使用PD、速度环使用PI、转向环使用PD。

总的公式是:PWM = Kpe(k)+Kie(k)的积分+Kd*e(k)的微分
e(k)就是所谓的偏差,也就是真实值-设定值。
各个环的输入都是不一样的:
①直立环的输入就是目标角度、真实角度、y轴角速度,这里的目标角度就是机械中值,需要在调试PID参数之前确定,确定方法可以看视频,由于mpu6050摆放的方向不一样,那么需要观察的值也就不一样。真实角度就是mpu6050的姿态角,根据我的摆放位置,此值就是pitch。y轴角速度就是角度偏差的微分(此次偏差-上次偏差),就是上面总的公式中Kd乘的那部分。
②速度环的输入是左右编码器读取的值、目标速度,这里如果只实现直立的话,那么目标速度肯定是0,因为想要小车静止不动的。
③转向环,根据不同的需求,参数各不相同,本项目的转向环输入是目标偏航角、z轴角速度。偏航角顾名思义就是转向相关,z轴角速度就是转向偏差的微分(此次偏差-上次偏差)。
上面说的这些直接看视频更加直接,而且很容易理解:https://www.bilibili.com/video/BV1j7411z7uX/?p=3&spm_id_from=pageDriver&vd_source=2a10d30b8351190ea06d85c5d0bfcb2a

本项目使用的是并级PID,还有一种串级PID,下面的图就是两种方法对比:

在这里插入图片描述
在这里插入图片描述
PID部分的代码也是非常简单,前提是移植了别人写好的MPU6050相关函数,不然要自己解算姿态角的话还是很麻烦的:

/**************************************************************************************************************
*函数名:Vertical_Ring_PD()
*功能:直立环PD控制
*形参:(float Angle):x轴的角度/(float Gyro):y轴的角速度
*返回值:经过PID转换之后的PWM值
**************************************************************************************************************/
//直立环的PD


int	Vertical_Ring_PD(float Angle,float Gyro)
{
    float Bias;//目标偏差
    int balance;
    Bias=Angle-Mechanical_balance;//目标值减去机械中值(不一定为0)即测量值-理论值这是p算法要用的
    balance=PID.Balance_Kp*Bias+ Gyro*PID.Balance_Kd;//这里的Kd是偏差的微分,离散系统中两次角度的差值也就是微分,对应就是角速度,这里传入的Gyro就是y轴角速度,
	  //这要根据平衡小车上MPU6050摆放的方向有关,因为小车只会往两个方向倒下,这里看mpu6050上的标注就好了,我这里是沿着y轴两边倒下,也就是y轴的角速度。
	 //第一个参数是当前角度,这就是读取mpu6050的原始数据,然后经过dmp解算之后得到的欧拉角,这里传进来的就是pitch,俯仰角,就是此时小车直立的角度。

    return balance;

    //printf("balance = %f\n",balance);
}


/**************************************************************************************************************
*函数名:Vertical_speed_PI()
*功能;速度环PI控制
*形参:(int encoder_left):左轮编码器值/(int encoder_right):编码器右轮的值/(float Angle):x轴角度值
*返回值:
**************************************************************************************************************/

int Vertical_speed_PI(int encoder_left,int encoder_right,float Angle,float Movement )
{
    static float Velocity,Encoder_Least,Encoder;//Encoder是经过一定程度滤波后的速度测量值,Encoder_Least是最新数据
    static float Encoder_Integral;
    Encoder_Least =(encoder_left+encoder_right)-0;    //获取最新速度偏差=测量速度(左右编码器之和)-目标速度(此处为零)
    Encoder *= 0.8f;																	//一阶低通滤波器 ,上次的速度占80%,f为滤波系数
    Encoder += Encoder_Least*0.2f;                   //一阶低通滤波器, 本次的速度占20%   
    Encoder_Integral +=Encoder;                       //积分出位移 积分时间:10ms
    Encoder_Integral=Encoder_Integral-Movement;
    //if(Movement == 0 ) Encoder_Integral=0;
    if(Encoder_Integral>10000)  	Encoder_Integral=10000;           //积分限幅
    if(Encoder_Integral<-10000)	  Encoder_Integral=-10000;            //积分限幅
 
    Velocity=Encoder*PID.Velocity_Kp+Encoder_Integral*PID.Velocity_Ki;//速度控制,P算法为Kp*误差,误差等于测量值-理论值,此时目标速度为0
	                                                                    //,所以直接Kp*测量值(这里的测量值是经过一阶低通滤波后的值)


    if(Turn_off(Angle)==1)   Encoder_Integral=0;            //电机关闭后清除积分
    return Velocity;
}


/**************************************************************************************************************
*函数名:Vertical_turn_PD()
*功能:转向环PD
*形参:taget_yaw 目标yaw, yaw 陀螺仪yaw , gyro 陀螺仪yaw方向角速度
*返回值:无
***************************************************************************************************************/
int Vertical_turn_PD(float taget_yaw,float yaw,float gyro)
{
    float Turn;
    float Bias_yaw;
    Bias_yaw=taget_yaw-yaw;
		if (Bias_yaw<-180) Bias_yaw+=360;
		if (Bias_yaw>180) Bias_yaw-=360;
	
    Turn=-Bias_yaw*PID.Turn_Kp-gyro*PID.Turn_Kd;
    return Turn;
}

第三步:PID调参

这里强烈建议观看b站视频,跟着进行调参:https://www.bilibili.com/video/BV1ib411v7YU/?p=10&spm_id_from=pageDriver&vd_source=2a10d30b8351190ea06d85c5d0bfcb2a
调参才是整个小车制作过程中最折磨的,会一直觉得调的还不够好,但其实这是多方面因素决定的。

四、源代码获取

关注+点赞就可以私信免费获取

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

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

相关文章

安装Pytorch中的torchtext之CUDA版的正确方式

安装Pytorch和torchtext&#xff1a; Previous PyTorch Versions | PyTorch Installing previous versions of PyTorchhttps://pytorch.org/get-started/previous-versions/ 上面的命令如下&#xff1a; pip install torch2.1.2 torchvision0.16.2 torchaudio2.1.2 --index-…

【RPA】智能自动化的未来:AI + RPA

伴随着人工智能&#xff08;AI&#xff09;技术的迅猛进步&#xff0c;机器人流程自动化&#xff08;RPA&#xff09;正在经历一场翻天覆地的变革。AI为RPA注入了新的活力&#xff0c;尤其在处理复杂任务和制定决策方面。通过融合自然语言处理&#xff08;NLP&#xff09;、机器…

【我与Java的成长记】之String类详解

系列文章目录 能看懂文字就能明白系列 C语言笔记传送门 Java笔记传送门 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言一、字符串构…

Mongodb启动为Windows服务开机自启动

注意&#xff1a;mongodb的安装目录不应有中文&#xff0c;如果有&#xff0c;服务启动的路径会出现乱码&#xff0c;导致找不到对应的文件 1.安装好mongoDB 2.创建data目录&#xff0c;并在其中创建db目录和log目录 3.在log目录中创建mongodb.log文件 4.打开cmd&#xff08;用…

【网络攻防实验】【北京航空航天大学】【实验一、入侵检测系统(Intrusion Detection System, IDS)实验】

实验一、入侵检测系统实验 1、 虚拟机准备 本次实验使用1台 Kali Linux 虚拟机和1台 Windows XP 虚拟机,虚拟化平台选择 Oracle VM VirtualBox,如下图所示。 2、 Snort环境搭建 实验前,先确保Kali Linux虚拟机能够访问外网,将网络模式设置为“网络地址转换”: 2.1 安装…

计算两个数相除后的余数返回值为浮点型math.fmod(x, y)

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 计算两个数相除后的余数 返回值为浮点型 math.fmod(x, y) [太阳]选择题 请问以下代码执行math.fmod()后输出的结果是&#xff1f; import math print("【执行】math.fmod(10, 4)"…

redis特点

一、redis线程模型有哪些&#xff0c;单线程为什么快&#xff1f; 1、IO模型维度的特征 IO模型使用了多路复用器&#xff0c;在linux系统中使用的是EPOLL 类似netty的BOSS,WORKER使用一个EventLoopGroup(threads1) 单线程的Reactor模型&#xff0c;每次循环取socket中的命令…

【数据结构】一篇文章带你学会八大排序

一、排序的概念1. 排序的使用&#xff1a;2. 稳定性&#xff1a;3. 内部排序&#xff1a;4. 外部排序︰5. 排序的用途&#xff1a; 二、排序的原理及实现1. 插入排序1.1 直接插入排序1.1.1 直接插入排序在现实中的应用1.1.2 直接插入排序的思想及个人理解1.1.3 直接插入排序的排…

嵌入式系统中的故障容错和恢复机制有哪些常用的方法和技术?

嵌入式系统是一种在特定应用领域内运行的计算机系统&#xff0c;其对系统可靠性和稳定性有着较高的要求。在嵌入式系统中&#xff0c;故障容错和恢复机制是至关重要的&#xff0c;因为它们能够确保系统在面临故障和异常情况时能够继续正常工作或者快速恢复正常状态。本文将介绍…

MPLS VPN功能组件(4)

数据转发过程 VPN数据的转发 顶层公网标签 由LDP分配,指示LSR如何将标签报文从始发的源PE通过LSP标签交换到达目的PE 内层私网标签(VPN标签) 由MP-BGP分配,在将每一条客户路由变为VPNv4路由前缀时会自动为每一条VPNv4前缀关联一个标签 内层私网标签用于指示目的PE将该标签报…

“手把手教你玩转函数递归,建议收藏!“

目录 1. 什么是递归 2. 递归的限制条件 3. 递归的举例 4. 递归与迭代 正⽂开始 1. 递归是什么&#xff1f; 递归是学习C语⾔函数绕不开的⼀个话题&#xff0c;那什么是递归呢&#xff1f; 递归其实是⼀种解决问题的⽅法&#xff0c;在C语⾔中&#xff0c;递归就是函数⾃…

Pandas数据预处理之数据标准化-提升机器学习模型性能的关键步骤【第64篇—python:数据预处理】

文章目录 Pandas数据预处理之数据标准化&#xff1a;提升机器学习模型性能的关键步骤1. 数据标准化的重要性2. 使用Pandas进行数据标准化2.1 导入必要的库2.2 读取数据2.3 数据标准化 3. 代码解析4. 进一步优化4.1 最小-最大缩放4.2 自定义标准化方法 5. 处理缺失值和异常值5.1…

MCS-51系列单片机简介

MCS-51系列单片机简介 MCS-51系列单片机是因特尔(Intel)公司生产的一个系列单片机的名称。比如&#xff1a;8051/8751/8031、8052/8752/8032、80C51/87C51/80C31、80C52/87C52/80C32等&#xff0c;都属于这一系列的单片机。 MCS-51系列单片机从功能上&#xff0c;可分为51和52…

深度学习入门笔记(九)自编码器

自编码器是一个无监督的应用&#xff0c;它使用反向传播来更新参数&#xff0c;它最终的目标是让输出等于输入。数学上的表达为&#xff0c;f(x) x&#xff0c;f 为自编码器&#xff0c;x 为输入数据。 自编码器会先将输入数据压缩到一个较低维度的特征&#xff0c;然后利用这…

Java图形化界面编程—— LayoutManager布局管理器笔记

2.4 LayoutManager布局管理器 之前&#xff0c;我们介绍了Component中有一个方法 setBounds() 可以设置当前容器的位置和大小&#xff0c;但是我们需要明确一件事&#xff0c;如果我们手动的为组件设置位置和大小的话&#xff0c;就会造成程序的不通用性&#xff0c;例如&…

数字图像处理实验记录七(彩色图像处理实验)

一、基础知识 经过前面的实验可以得知&#xff0c;彩色图像中的RGB图像就是一个三维矩阵&#xff0c;有3个维度&#xff0c;它们分别存储着R元素&#xff0c;G元素&#xff0c;B元素的灰度信息&#xff0c;最后将它们合起来&#xff0c;便是彩色图像。 这一次实验涉及CMYK和HS…

Java 获取、创建 stream 流操作对象的几种方法

Java 获取、创建 stream 流操作对象的几种方法 package com.zhong.streamdemo.createstreamdemo;import java.util.*; import java.util.stream.Stream;/*** ClassName : CreateStream* Description : 创建 stream 操作对象* Author : zhx* Date: 2024-02-08 13:10*/ public c…

查看网络配置的ipconfig命令

ipconfig是调试计算机网络的常用命令&#xff0c;通常大家使用它显示计算机中网络适配器的IP地址、子网掩码及默认网关。其实这只是ipconfig的不带参数用法&#xff0c;而它的带参数用法&#xff0c;在网络中应用也是相当不错的。 1.语法 ipconfig [/all] [/renew[Adapter]] [/…

分布式springboot 3项目集成mybatis官方生成器开发记录

文章目录 说明实现思路实现步骤第一步&#xff1a;创建generator子模块第二步&#xff1a;引入相关maven插件和依赖第三步&#xff1a;编写生成器配置文件第四步&#xff1a;运行查看结果 说明 该文章为作者开发学习记录&#xff0c;方便以后复习和交流主要内容为&#xff1a;…

《游戏引擎架构》 -- 学习2

声明&#xff0c;定义&#xff0c;以及链接规范 翻译单元 声明与定义 链接规范 C/C 内存布局 可执行映像 程序堆栈 动态分配的堆 对象的内存布局 kilobyte 和 kibibyte 流水线缓存以及优化 未完待续。。。