基于STM32的二轮自平衡小车

前言

近年来,移动机器人是目前科学领域比较活跃的领域之一,其应用范围越来越广泛,面临的环境也越来越复杂,这就要求机器人能够适应一些复杂的环境和任务。二轮自平衡机器人正是在这一背景下提出来的,对于制作此种类型的自平衡小车无疑对我stm32的学习有莫大的好处,一方面深入了解stm32以及学习串级PID的运用,另一方面也是对我近期学习的硬件方面知识一个检验。

本人为32小白水平有限,同时也是第一篇博客,如果有地方描述不清晰不正确,欢迎大佬指出一起讨论

原理介绍

系统框图

在这里插入图片描述

获取小车的速度和角度是实现小车自平衡的前提,数据在stm32的中断控制中配合PID算法使用,输出数值给PWM寄存器控制相应电机,从而实现平衡。遥控部分是控制转向,根据移动终端向蓝牙发送数据从而实现相应的运动。

在这里插入图片描述

我们可以将平衡小车的运动方式类比为手指上放置一根筷子,保持其直立状态,根据生活经验可知,当筷子向某个方向倒下时,我们眼睛观察到筷子倒下反馈给大脑,大脑控制手迅速向筷子倒下的方向运动,使其始终保持原有直立状态。同样,平衡小车道理相同,当传感器检测到小车有倒下的趋势时,控制轮子向相同方向运动,不同角度会输出不同速度即可保持平衡。

运动分析

平衡小车的控制可以分为直立控制,速度控制以及转向控制,即直立环、速度环和转向环,使小车能够保持平衡状态的是速度环以及直立环,通过传感器读取角度输出不同的PWM即不同的速度使其保持平衡。其中单独的直立环可以使小车保持直立,但如果受到外力的影响,那么不用多想,小车一定会倒下,将直立环和速度环串起来,那么当小车受到外力时,也能迅速平衡。

运动控制

小车的直立控制是通过负反馈控制的

高中时期大家对正反馈和负反馈都有所了解,这里不过多解释。直立控制实际上就是将小车控制在一定角度内,这个角度由小车的机械零点有关(你搭建的小车重心),对于机械零点的确定会在调试中说明,上文提到如果只有直立环不足以小车完全保持平衡,所以我们还需要加入速度环。

小车的速度控制是通过正反馈控制的

我们可以假设此时小车处于直立状态,如果小车想向前运动,那么小车必然要向前倾斜获取向前的加速度,但是向前倾斜轮子必然要向后转动,那么小车的速度会下降(轮子向后转动了)假如为负反馈那么小车必然会增加倾角,一直循环下去这样则会加速小车的倒下,所以在速度控制中反馈系统应该是正反馈。

转向控制

​所谓转向环即当小车已经能保证基本的平衡时,通过蓝牙控制使小车改变方向的控制系统

  • 定时器PWM输出以及编码器模式
PWM输出

脉冲宽度调制(PWM),是英文“Pulse Width Modulation” 的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。

当小车在运行过程中随着倾角的改变小车的速度也应该发生变化,如果只是单纯给予高低电平,只能以额定速度运动,显然不能达到我们想达到的程度,所以我们需要定时器输出PWM波,我们选用的主控模块只有4个定时器(1个高级3个通用)一个定时器有4个通道控制小车显然是足够的。当然如果你选择其他系列芯片会有多个定时器,选择也会更多

(注意基本定时器无法输出PWM脉冲)

其中如果用到高级定时器TIM1以及TIM8注意除了基础的配置还需要使能刹车和死区寄存器,以使能整个PWM输出,还需要使能高级定时器特有的寄存器。

TIM_CtrlPWMOutputs(TIM1,ENABLE); //高级定时器特有

编码器模式

上文系统框图可以看出,速度系统需要一个速度反馈,其他系统的反馈可以通过6050读取,那么此时小车的速度如何读取呢?这里就需要编码器读取此时的速度。编码器会引出AB相,通过STM32的编码器模式以特定的GPIO口连接编码器AB相,读取脉冲,从而读取速度。

在这里插入图片描述

通过查阅参考手册不难得知只有高级定时器以及通用定时器具有检测编码器的功能,基本定时器并不具备这种功能。所以我们可以配置定时器来读取编码器数据。

这里需要注意的是:编码器模式只有定时器的通道一和通道二可以使用,即只有TIMx_CH1 TIMx_CH2 可以使用

千万注意这一点,如果自己打板的话没注意这一点就可以重新打板了 /(ㄒoㄒ)/

参考手册如下:

在这里插入图片描述

选择编码器接口模式的方法是:如果计数器只在TI2的边沿计数,则置TIMx_SMCR寄存器中的SMS=001;如果只在TI1边沿计数,则置SMS=010;如果计数器同时在TI1和TI2边沿计数,则置SMS=011。

通过设置TIMx_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性;如果需要,还可以对输入滤波器编程。

两个输入TI1和TI2被用来作为增量编码器的接口。参看下表:
在这里插入图片描述

在这里插入图片描述

假定计数器已经启动(TIMx_CR1寄存器中的CEN=’1’),计数器由每次在TI1FP1或TI2FP2上的有效跳变驱动。 TI1FP1和TI2FP2是TI1和TI2在通过输入滤波器和极性控制后的信号;如果没有滤波和变相,则TI1FP1=TI1,TI2FP2=TI2。根据两个输入信号的跳变顺序,产生了计数脉冲和方向信号。依据两个输入信号的跳变顺序,计数器向上或向下计数,同时硬件对TIMx_CR1寄存器的DIR位进行相应的设置。不管计数器是依靠TI1计数、依靠TI2计数或者同时依靠TI1和TI2计数。在任一输入端(TI1或者TI2)的跳变都会重新计算DIR位。

编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。这意味着计数器只在0到TIMx_ARR寄存器的自动装载值之间连续计数(根据方向,或是0到ARR计数,或是ARR到0计数)。所以在开始计数之前必须配置TIMx_ARR;同样,捕获器、比较器、预分频器、触发输出特性等仍工作如常。在这个模式下,计数器依照增量编码器的速度和方向被自动的修改,因此计数器的内容始终指示着编码器的位置。计数方向与相连的传感器旋转的方向对应。

在这里插入图片描述

当定时器配置成编码器接口模式时,提供传感器当前位置的信息。使用第二个配置在捕获模式的定时器,可以测量两个编码器事件的间隔,获得动态的信息(速度,加速度,减速度)。指示机械零点的编码器输出可被用做此目的。根据两个事件间的间隔,可以按照固定的时间读出计数器。如果可能的话,你可以把计数器的值锁存到第三个输入捕获寄存器(捕获信号必须是周期的并且可以由另一个定时器产生);也可以通过一个由实时时钟产生的DMA请求来读取它的值。

更详细请参考编码器配置原理

MPU-6050姿态解算
  • 六轴传感器读取角度
    想要小车直立起来由上文可知我们需要读取y轴的倾斜角度以及y轴的加速度,当然如果用到转向环还要读取z轴的角度。MPU-6050可读取3轴的角度以及3轴的加速度和芯片的温度。其中角度是直立环重要参数,角速度是速度环以及转向环的重要参数。

    获得6050的数据我们可以通过移植官方的DMP库,通过DMP,就可以使用InvenSense公司提供的运动处理资料库,非常方便地实现姿态解算,也可以获得原始数据后使用卡尔曼滤波解算姿态。
    需要注意的是AD0接口如果接地,则6050的IIC地址为0x68,如果接vcc,则6050的IIC地址0x69

    参考资料 MPU-6050

PID
  • PID算法

    上边运动分析中已经提及小车的运动需要直立环速度环以及转向环。PID的学习包括理论知识以及调参的经验等。

    参考资料 PID算法原理、调试经验和代码z2r8

模块选型

主控模块

主控模块我们使用STM32f103c8t6 ,这款模块有3个通用定时器,一个高级定时器,3路串口,2路IIC,72Mhz,对于我们的需求是绰绰有余的。

在这里插入图片描述

编码器

在这里插入图片描述

编码器电机我们使用的是平衡之家的一款mini电机,由于打出的板子体型较小,所以没有选择体积大的电机。

额定电压7.4V,当然也可以工作在12V环境下,编码器供电5v。

价格差不了多少,还是体积大一点的搭建出来的小车看起来大气

在这里插入图片描述
在这里插入图片描述

电机线1/6接在电机模块的A/BOUT处,电机线2/5接5v以及接地,编码器AB相接在预留出来的定时器接口只有通道1/2支持

电机驱动模块

电机驱动模块选择的是TB6612模块,VM需要12v供电,SYBT需要5v供电否则电机不会转动, 同时输出两路PWM,同时控制两个电机。

在这里插入图片描述

这里其实一开始选择是功能更强大的A4950,但是因为摔了一下电机模块就直接罢工(太便宜),所以在购置硬件时千万不要图便宜,买好的不买便宜的

降压模块

降压模块选择一块带数显的,方便观察电池电量,不多叙述。
在这里插入图片描述

MPU-6050模块

不多赘述,同样6050也不要图便宜(这一块可能就是因为质量问题,导致程序无法进入6050的外部中断,最后没办法放入主程序运行

在这里插入图片描述

蓝牙通讯模块

在这里插入图片描述

转向环则是实现小车转弯的一环。通常利用上位机与平衡小车的交互来来控制转向,这里使用的是蓝牙模块HC-06,HC-05/HC-06 /SPP-C这些通用的型号都可以用,蓝牙模块通过串口通信来传输数据。

硬件准备

IO口分配

定时器TIM4预留给OLED 每10ms刷新一次数据

定时器TIM3用于测距通过OLED展示距离

另外注意编码器只能用通道1/2

GPIO 复用情况 连接外设
PA2 USART2_RX 蓝牙 TX
PA3 USART2_TX 蓝牙 RX
PA0 TIM2_CH1 电机A编码器A相
PA1 TIM2_CH2 电机A编码器B相
PA6 TIM3_CH1 电机B编码器B相
PA7 TIM3_CH2 电机B编码器A相
PA8 TIM1_CH1 TB6612 PWMA
PA11 TIM1_CH4 TB6612 PWMB
PB1 TIM3_CH3 SR04 -> Trig
PB0 TIM3_CH4 SR04 -> Echo
PB5 6050外部中断
PB6 IIC1 SCL 6050 SCL
PB7 IIC1 SDA 6050 SDA
PB10 IIC2 SCL OLED SCL
PB11 IIC2 SDA OLED SDA
PB12 BIN2
PB13 BIN1
PB14 AIN1
PB15 AIN2

原理图绘制

原理图如图所示,供电接口采用的T型接口,电机等处加入100nf电容进行滤波。

在这里插入图片描述

PCB绘制

PCB未铺铜如图所示

在这里插入图片描述

铺铜以及添加泪滴效果

在这里插入图片描述

2D预览

在这里插入图片描述

实物图

在这里插入图片描述

硬件组装

3S电池搭建在最底层,中间放置降压模块,铜柱搭建最上方PCB,防止电机运动时的抖动影响系统的运行。

其实这里是有问题的,预留的OLED位置不够,导致只能放置在边上,PCB打孔处和降压模块冲突,整体排布也影响重心,需要调试机械中值。

实物图如下

在这里插入图片描述
在这里插入图片描述

硬件装配完成,下面我们开始软件编程

软件调试

程序是删减后的,并不完整 ,程序还是自己写学习才更有意义😀

配置编码器

#include "encoder.h"

void Encoder_TIM2_Init(void)
{
   
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_ICInitTypeDef TIM_ICInitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;//初始化GPIO--PA0、PA1
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0 |GPIO_Pin_1
  • 75
    点赞
  • 431
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
MATLAB中实现两轮平衡小车需要使用控制系统工具箱。以下是一个简单的例子,展示了如何使用MATLAB控制两轮平衡小车的运动。 首先,我们需要创建一个机器人模型。这里我们使用一个二维的矩阵表示机器人的位置和姿态。我们可以使用`rand`函数生成随机的初始位置和姿态。 ```matlab robot = [0, 0; 0, 0]; % 初始化机器人位置和姿态 ``` 接下来,我们需要定义一个控制器函数,用于计算机器人在给定时间步长下的控制输入。这里我们使用PID控制器作为示例。 ```matlab function u = controller(robot, target_pose, kp, ki, kd) % robot: 当前机器人状态,包括位置和姿态 % target_pose: 目标位置和姿态 % kp, ki, kd: PID控制器参数 % 计算误差 error = target_pose - robot; % 计算控制输入 u = kp * error + ki * sum(error); u = u / norm(u); u = u + kd * (target_pose - robot); end ``` 现在我们可以编写主程序,使用PID控制器控制两轮平衡小车的运动。 ```matlab % 设置仿真时间和时间步长 T = 0.1; dt = 0.01; t = 0:dt:T; % 设置目标位置和姿态 target_pose = [1, 1; 0, 1]; % 设置PID控制器参数 kp = 1; ki = 0.1; kd = 0.5; % 初始化机器人状态 robot = [0, 0; 0, 0]; % 进行仿真 for i = 1:length(t) % 计算控制输入 u = controller(robot, target_pose, kp, ki, kd); % 更新机器人状态 robot = robot + u * dt; % 绘制机器人位置 plot(robot(1), robot(2)); hold on; plot(target_pose(1), target_pose(2), 'ro'); hold off; drawnow; end ``` 这个例子中,我们使用了一个简单的二维平面和一个点作为目标位置。你可以根据实际需求修改目标位置和姿态,以及调整PID控制器参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值