-
2021-02-23 17:25:48
转载自:http://nicekwell.net/blog/20180121/ping-heng-zi-xing-che-li-lun-pian.html
本人是一名16届智能车比赛单车组的备赛学生,竞速组选择的是单车拉力组,从单车群车友的链接找到三篇文章学习,这是其中的第二篇,这一篇对平衡自行车的算法进行理论分析,包括模型分析、姿态检测方法、PID算法,控制算法。
欢迎大家一起就16届单车组比赛进行讨论交流。正文
模型分析
倒立摆
很显然我们知道自行车在左右方向上不稳定,这是一个很常见的物理模型——倒立摆。
顾名思义,倒立摆的意思就是倒着的摆,比如一个倒着的杆,
倒立摆的特性:不稳定,只要偏离平衡位置,就会有一个力(重力的分力)使系统更加偏离平衡位置,这样偏差就会越来越大。
一般道理的杆在前后左右方向都有可能倒下,在二维的平面上不稳定;而自行车尽在左右方向上可能倒下,是一维的倒立摆,这要简单一些。
以下是几个生活中常见的倒立摆例子:
自行车的平衡控制
自行车属于倒立摆模型,倒立摆是不稳定的,那么倒立摆应该如何控制才能平衡呢?
我们把问题分析一下:
(1)怎样的状态才叫平衡?
(2)我们能控制的是什么?
(3)如何控制才能稳定平衡?怎样的状态才叫平衡
我们要对“平衡”进行数学描述,所谓的平衡其实就是倒立摆的倾角稳定在一个我们想要的值。
我们能控制的是什么
对于倒立摆模型,通常我们能控制的是底端的 力 或 速度 或 位置,不同的控制量对应的控制方法不同。
对于自行车来说,他的控制方式不像通常的倒立摆那样直接控制底部,而是间接地通过转向来控制,当自行车以一个固定地速度前进时,自行车把手以一定角度转向(设为α),自行车会做相应半径地圆周运动,产生相应大小地横向力:
这就是我们进行平衡控制时的实际控制量——把手转角α,只要控制它就能控制回复力。
如何控制才能平衡
上面我们已经能够通过转向产生回复力,这个回复力可以把倒立摆”掰回”平衡位置,有往回掰的回复力就能稳定平衡了吗?
并不是这样,我们再来回顾一下中学物理:
1)过阻尼状态的摆会以较慢的速度回到平衡位置;
2)欠阻尼状态的摆会很快回到平衡位置,但会在平衡位置来回摆动;
3)临界阻尼状态的摆会以最快的速度稳定在平衡位置。结合到实际的自行车平衡中就是:
如果回复力不够大,就无法矫正,或者矫正速度很慢,这会导致系统不稳定;
如果回复力过大,就会导致矫正过度,这也会导致系统不稳定;
我们最希望的状态就是回复力刚刚好,刚好使倒立摆快速回到平衡位置,又不至于矫正过度。这是一个复杂的数学计算过程,回复力大小会在系统运行时不断地计算(本平衡自行车是20ms计算一次),用到的是PID算法,会在后面详细介绍。
自行车平衡需要解决的基本问题
1、获取左右方向的倾角θ;
2、以合适的算法控制转角α使系统稳定平衡
PS:这将会在下面详细讨论。姿态检测
检测的是什么
检测的是自行车左右倾斜的角度。
怎么检测
用一个叫gy521的模块,里面用的是mpu6050芯片,带有陀螺仪和加速度传感器。 gy521的具体使用会在第三篇(实践篇)介绍,这里我们知道通过这个模块我们可以得到自行车各个方向的加速度和角速度。 注意哦,我们不能直接得到倾斜角度,我们得到的是各个方向的加速度和角速度,需要进行一些复杂的计算才能得到正确的倾斜角度。
常用的算法有互补平衡滤波、卡尔曼滤波,由于篇幅和精力问题这部分暂不介绍,网上有大量资源,也可以查看本工程源码,以后有时间再写详细教程。
PID算法
前面已经分析了,我们通过控制把手转角来控制回复力,我们需要实时计算一个合适的回复力使系统稳定平衡。
PS:这部分内容也不做详细介绍了,网上有大量资源,也可以查看本工程源码。在这里引用动力老男孩举的一个例子,帮大家简单理解一下需要解决的问题,以及PID算法是如何解决的
有一个小球在光滑球面上,小球的位置是x,光滑球面顶端在L处,我们可以控制小球水平方向力F,现在要求让小球稳定平衡在x0处。
先看简单情况 x0=L,此时偏差为 L-x,
我们给出一个比例项§ F = kp*(L-x),这样就会有一个回复力,当偏差存在时就会有一个力把小球拉回L处。
这存在的问题是,小球接近L时是会有一定速度的,小球越来越接近L,此时的力仍然是在把小球往L处拉,这会导致小球到达L时(我们想要的位置)速度很大,小球无法立刻停下来,而是会冲过去。
这样小球就会在L附近来回摆动,这是不稳定的状态,属于欠阻尼状态。为了解决上述问题需要加一个微分项(D) F = kddx/dt = kdv,所谓”微分”指的是位置x对时间的微分,说白了就是速度。
意思就是当速度越大,就产生一个反向的力使速度减小,这样就可以防止出现上面小球冲过去的。
可以认为这一项具有”预测”功能,预测小球下一时刻的状态从而提前做出反应(预测小球将要到达L处,提前减速)。
也可以认为这一项具有阻尼作用,相当于系统中有一个和速度成比例的阻尼力。
这个”阻尼力”调得过小会导致欠阻尼状态,调得过大会导致过阻尼状态。积分项此时可以不用,积分项是当平衡位置x0不等于L时使用的。
当平衡位置不是L处,那么当小球静止在平衡位置x0时,由于在坡道上会有一个恒定的横向偏移力,此时比例调节作用为0(Δx=0),微分调节作用也是0(v=0),所以小球在该处无法平衡,会在更远离平衡位置处达到平衡,那么就会有一个长时间存在的偏差。
积分作用就是检测偏差进行累积,对于上面这个长时间存在的偏差进行积分(累积叠加),使系统在长时间范围可以稳定在要求的平衡位置。更多相关内容 -
高配版自平衡自行车资料.zip
2021-04-02 20:42:48高配版自平衡自行车资料动量轮,需要可下载 -
平衡自行车_stm32平衡自行车_STM32平衡单车_平衡自行车_自平衡自行车_自行车
2021-09-10 20:43:57基于stm32f103的能够实现自平衡的自行车,简易自主不倒自行车 -
平衡自行车基于STM32F103
2020-12-10 22:43:54关于STM32F103的平衡车,自行车。非动量轮,适合16th的Freescale智能车资料,其中包括源码,原理图,pcb等。 -
自平衡自行车源码.zip
2020-06-28 11:50:34平衡自行车源码,有兴趣的可以学习学习。欢迎各位下载 -
单片机控制PID调节的自平衡自行车.pdf
2021-07-12 17:16:36单片机控制PID调节的自平衡自行车.pdf -
自平衡自行车机器人的运动学解析.pdf
2021-08-14 09:21:44#资源达人分享计划# -
平衡自行车/低配版平衡自行车/平衡小车之家
2021-04-13 16:15:35关于STM32F103的平衡车,自行车。非动量轮,适合16th的Freescale智能车资料,其中包括源码,原理图,pcb等。 -
平衡自行车的原理以及制作方法
2021-07-18 00:10:21关注+星标公众号,不错过精彩内容来源 |http://nicekwell.net/今天给大家带来的是一个博主老倪制作的迷你的平衡自行车项目,虽然是4年前的老项目了,不过相信我们仍然能从中...关注+星标公众号,不错过精彩内容
来源 | http://nicekwell.net/
今天给大家带来的是一个博主老倪制作的迷你的平衡自行车项目,虽然是4年前的老项目了,不过相信我们仍然能从中学到一些新东西。
▼ 演示效果
自行车平衡DIY分为3部分介绍:
第一部分介绍自行车平衡基本物理原理;
第二部分理论篇,对平衡自行车的算法进行理论分析,包括模型分析、姿态检测方法、PID算法,控制算法;
第三部分实践篇,具体介绍平衡自行车用到的元器件,动力、转向、电路及代码分析。
篇一:自行车平衡原理
自行车是怎么平衡的,老外做过一个非常好的视频:
自行车是怎么保持平衡的?
这个视频很好地证明了常见的”角动量守恒”的说法是错误的,并且正确的说明了自行车平衡原理是和转向相关的,但没有具体指出平衡和转向的关系。
在这里我们就先来讨论一下”角动量守恒”这种最常见的猜测为什么是错误的,大致讨论一下转向是如何使自行车保持平衡的。
1、角动量守恒说
角动量守恒说的意思就是:轮子跑的时候在转动,此时轮子就类似于陀螺,角动量守恒使自行车保持不倒。
小时候也有过这样的疑问,如果把自行车车轮固定从下坡推下,自行车能不能一直往前走?
到底能不能呢?老外的视频做了这个试验:
固定之后就会倒下,可见轮子的陀螺仪效应并不是维持自行车不倒的原因。另外还有老外做了一个没有陀螺仪效应的自行车,该自行车也可以稳定平衡:
以上足以说明陀螺仪效应不是维持自行车平衡的根本原因。
2、转向时的”离心力”是自行车平衡的根本原因
那么什么才是维持自行车平衡的原因呢?
自行车可以看做是一个倒立摆(左右方向不稳定),这个倒立摆受重力作用是一个不稳定系统,需要额外的回复力维持平衡,而提供回复力的正是自行车转向时的”离心力”。
离心力是速度和把手转向角的函数,在一个固定的速度下,可以认为控制把手转向角度就是控制回复力。
我们先记住这一点:维持自行车平衡,需要通过一种合适的算法控制把手角度才能使自行车稳定平衡。
机械自平衡
或许有人会奇怪,有些自行车只要推起来就可以自己平衡,如下面视频:
我自己也买过一个如下面这样的遥控摩托车想要研究一下:
拆开后发现里面并没有精确的转向控制结构,仿佛在行驶时根本没有转向控制,就类似于上面自行车一样自己就可以平衡了。
这到底是怎么回事呢?其实这就是结构设计者的牛逼之处,设计的机械结构自带回复功能,机械结构使得转向会根据车身倾斜而改变,这种改变的幅度正好可以使自行车稳定平衡。
如果我们改变车身结构,可能就会破坏原有的参数,使得自行车无法稳定平衡。如在前轮绑一个重物:
在老外的视频中,分析了车身倾斜对转向的三个影响因素:
前轮转轴后倾,导致倾斜时前轮转向。
把手安装在前面,导致倾斜时前轮转向。
前轮转动时的陀螺仪效应,车身倾斜,陀螺仪效应使得前轮转向。
以上是所谓”机械自平衡”,平衡根本原因还是转向,只不过巧妙的机械设计使得前轮转向特性恰好很容易维持平衡。
手动自平衡
手动自平衡的意思就是我们自己手动控制让它平衡。
我们既然分析平衡原理,还要做一个平衡自行车出来,这一部分要好好研究一下,将会在后面理论篇重点讨论一下控制方法。
篇二:平衡自行车-理论篇
一、模型分析
1、倒立摆
很显然我们知道自行车在左右方向上不稳定,这是一个很常见的物理模型——倒立摆。
顾名思义,倒立摆的意思就是倒着的摆,比如一个倒着的杆,
倒立摆的特性:不稳定,只要偏离平衡位置,就会有一个力(重力的分力)使系统更加偏离平衡位置,这样偏差就会越来越大。
一般倒立的杆在前后左右方向都有可能倒下,在二维的平面上不稳定;而自行车仅在左右方向上可能倒下,是一维的倒立摆,这要简单一些。
以下是几个生活中常见的倒立摆例子:
2、自行车的平衡控制
自行车属于倒立摆模型,倒立摆是不稳定的,那么倒立摆应该如何控制才能平衡呢?
我们把问题拆分一下:
怎样的状态才叫平衡?
我们能控制的是什么?
如何控制才能稳定平衡?
2.1 怎样的状态才叫平衡
我们要对”平衡”进行数学描述,所谓的平衡其实就是倒立摆的倾角稳定在一个我们想要的值。
通常我们想要平衡在
θ = 0
处。2.2 我们能控制的是什么
对于倒立摆模型,通常我们能控制的是底端的 力 或 速度 或 位置,不同的控制量对应的控制方法不同。
对于自行车来说,它的控制方式不像通常的倒立摆那样直接控制底部,而是间接地通过转向来控制,当自行车以一个固定的速度前进时,自行车把手以一定角度进行转向(设为
α
),自行车会做相应半径的圆周运动,产生相应大小的”离心力”。在自行车这个费惯性系里看来,只要对把手进行一定角度的转向(
α
),就会产生一个相应大小的横向力:这就是我们进行平衡控制时的实际控制量——把手转角
α
,只要控制它就能控制回复力。2.3 如何控制才能平衡
上面我们已经能够通过转向产生回复力,这个回复力可以把倒立摆”掰回”平衡位置,有往回掰的回复力就能稳定平衡了吗?
并不是这样,我们再来回顾一下中学物理:
过阻尼状态的摆会以较慢的速度回到平衡位置;
欠阻尼状态的摆会很快回到平衡位置,但会在平衡位置来回摆动;
临界阻尼状态的摆会以最快的速度稳定在平衡位置。
结合到实际的自行车平衡中就是:
如果回复力不够大,就无法矫正,或者矫正速度很慢,这会导致系统不稳定;
如果回复力过大,就会导致矫正过度,这也会导致系统不稳定;我们最希望的状态就是回复力刚刚好,刚好使倒立摆快速回到平衡位置,又不至于矫正过度。
这是一个复杂的数学计算过程,回复力大小会在系统运行时不断地计算(本平衡自行车是
20ms
计算一次),用到的是PID算法,会在后面详细介绍。3、自行车平衡需要解决的基本问题
获取左右方向倾角
θ
以合适的算法控制转角
α
使系统稳定平衡
这将会在下面详细讨论。
二、姿态检测
1、检测的是什么
检测的是自行车左右倾斜的角度。
2、怎么检测
用一个叫
gy521
的模块,里面用的是mpu6050
芯片,带有陀螺仪和加速度传感器。gy521
的具体使用会在第三篇-实践篇介绍,这里我们知道通过这个模块我们可以得到自行车各个方向的加速度和角速度。注意哦,我们不能直接得到倾斜角度,我们的到的是各个方向的加速度和角速度,需要进行一些复杂的计算才能得到正确的倾斜角度。常用的算法有互补平衡滤波、卡尔曼滤波,由于篇幅和精力问题这部分暂不介绍,网上有大量资源,也可以查看本工程源码,以后有时间再写详细教程。
三、PID算法
前面已经分析了,我们通过控制把手转角来控制回复力,我们需要实时计算一个合适的回复力使系统稳定平衡。
这部分内容也不做详细介绍了,网上有大量资源,也可以查看本工程源码。
在这里引用动力老男孩[1]举的一个例子,帮大家简单理解一下需要解决的问题,以及PID算法是如何解决的。
有一个小球在光滑球面上,小球的位置是
x
,光滑球面顶端在L
处,我们可以控制小球水平方向力F
,现在要求让小球稳定平衡在x0
处。先看简单情况
x0=L
,此时偏差为L-x
,我们给出一个比例项
(P) F = kp*(L-x)
,这样就会有一个回复力,当偏差存在时就会有一个力把小球拉回L
处。这存在的问题是,小球接近L时是会有一定速度的,小球越来越接近
L
,此时的力仍然是在把小球往L
处拉,这会导致小球到达L
时(我们想要的位置)速度很大,小球无法立刻停下来,而是会冲过去。这样小球就会在
L
附近来回摆动,这是不稳定的状态,属于欠阻尼状态。为了解决上述问题需要加一个微分项
(D) F = kd*dx/dt = kd*v
,所谓”微分”指的是位置x
对时间的微分,说白了就是速度。意思就是当速度越大,就产生一个反向的力使速度减小,这样就可以防止出现上面小球冲过去的。
可以认为这一项具有”预测”功能,预测小球下一时刻的状态从而提前做出反应(预测小球将要到达
L
处,提前减速),也可以认为这一项具有阻尼作用,相当于系统中有一个和速度成比例的阻尼力。
这个”阻尼力”调得过小会导致欠阻尼状态,调得过大会导致过阻尼状态。
积分项此时可以不用,积分项是当平衡位置
x0
不等于L
时使用的,当平衡位置不是
L
处,那么当小球静止在平衡位置x0
时,由于在坡道上会有一个恒定的横向偏移力,此时比例调节作用为0(Δx=0)
,微分调节作用也是0(v=0)
,所以小球在该处无法平衡,会在更远离平衡位置处达到平衡,那么就会有一个长时间存在的偏差。积分作用就是检测偏差进行累积,对于上面这个长时间存在的偏差进行积分(累积叠加),使系统在长时间范围可以稳定在要求的平衡位置。
篇三:平衡自行车-实践篇
在本文将会介绍平衡自行车的具体制作过程,包括机械、电路和代码。
平衡自行车完整的代码托管在
https://github.com/nicekwell/balance_bike
上GitHub网站卡的同学也可以在文末下载打包好的文档。
一、材料
机械
名称 数量 备注 铜柱、铁丝、胶枪等基础材料和工具 自行车架 1 自己做车架是很麻烦的,我是直接买的车架,淘宝上搜”自行车 拼装 DIY”能搜到很多 舵机 1 转向用的,对于我用的1:6车架,普通舵机有点大,我用的是9g舵机 N20电机 1 选扭力大一点,这样转速会比较稳定 皮带轮和皮带 如上面的图片,我是用皮带来传输动力的 电路
名称 数量 备注 电池、电池盒 洞洞板 lm1117-3.3 降压芯片给控制系统供电 stm32f103c8t6核心板 1 gy521模块 1 加速度传感器 + 陀螺仪 升压模块 1 升到12v给电机供电,根据电机特性选择是否使用升压模块 8050三极管 2 驱动电机,由于自行车不需要反转,所以不需要使用电机驱动芯片,用三极管就能方便地实现。我用了两个三极管并联提高功率。 自锁开关 1 整个系统开关 led指示灯 1 配合1k限流电阻 蓝牙模块 1 可选,如果想要遥控的话就使用蓝牙 二、动力部分
传动方式
如图,我用的是皮带传送的方式,因为比较好实现。
电机选择
这个DIY是不考虑变速情况的,平衡的参数都是按照一个固定速度调的。
所以动力部分的作用就是提供一个恒定的速度,并且这个速度尽可能稳定,尽可能不受外部影响。
电机应选择扭力大一些、转速稳定的减速电机。
电机供电
电机是直接供电还是使用升压模块供电要根据电机特性,有些电机用升压模块可以提高功率,有些大电流电机用升压模块反而可能限制了电流。
我这里用升压模块升到12v给N20电机供电的。
另外,电机通过三极管受stm32控制,通过控制占空比也可以限制电机输出的功率。
三、转向部分
转向部分用一个舵机带动把手转动即可。
四、电路
在GitHub工程里有详细的引脚连接表
https://github.com/nicekwell/balance_bike
供电
用3.3v稳压芯片给整个控制系统供电,包括单片机、GY521模块、蓝牙模块。
用5v稳压芯片给舵机供电。
用12v升压模块给电机供电。
下载
我是用串口给stm32下载程序的。
引脚 功能 PA9 下载TXD PA10 下载RXD GY521
这个模块通过i2c通信,只需要连接4根线。
3.3v
GND
PB0 GY521 I2C SCL
PB1 GY521 I2C SDA (用的是IO模拟i2c)
电机
点击用
12v
升压模块供电,由于不需要反转,用三极管即可直接驱动,电路图如下:加三极管的目的是为了可以通过调节PWM占空比来限制输出功率,但我的实际情况是100%输出时动力才勉强足够。所以如果你不需要限制电机输出功率,或者通过其他方式限制输出功率,也可以不要三极管,不通过单片机控制。
舵机
舵机是用
5v
供电的,而单片机是3.3v
电平,对于pwm控制脚可以通过2个三极管实现同相的电平转换:蓝牙模块
下图是我使用的蓝牙串口模块,可以实现串口透传,只需要4根线连接:
vcc
、gnd
、txd
、rxd
。蓝牙模块是用来调试和遥控的,没有它也能跑。建议还是加上这个模块,在调试PID擦数时会非常方便。
关于调试方面的内容可以参考我写的另一片文章:谈一谈单片机开发的几种调试方案[2]
五、代码结构
代码提交在GitHub
https://github.com/nicekwell/balance_bike
主要分为3个部分:
1、基础的驱动程序,实现电机、舵机、
gy521
数据读取;2、平衡控制系统,核心是一个
20ms
定时器,每20ms
进行一次数据采集、计算和响应;3、遥控和调试系统,实现log输出、接收遥控信息。
驱动
名称 文件 功能 i2c i2c/i2c.c, include/i2c.h IO 模拟i2c驱动,提供i2c基础操作 gy521 gy521/gy521.c, include/gy521.h gy521模块驱动,基于i2c驱动,提供加速度和角速度的读取接口 motor motor/motor.c, include/motor.h 电机驱动,提供占空比控制接口 angle angle/angle.c, include/angle.h 舵机驱动,提供角度控制接口 平衡控制
main
函数会初始化一个定时器20ms中断一次,调用main/balance.c
里的balance_tick
函数,平衡算法在main/balance.c
实现。每
20ms
到来会执行一次:读取传感器加速度和角速度信息。
互补平衡滤波计算当前姿态。
用PID算法计算出前轮转角。
遥控和调试
两部分:状态输出和指令接收。
状态输出
在
main
函数的while
循环里,利用串口中断构建一个简单的界面显示状态。指令接收
串口接收到的数据会传给
main/control.c
,该文件分析串口数据,解释成相应的操作。主要是PID参数调节。参考资料
[1]
动力老男孩: http://www.diy-robots.com/
[2]谈一谈单片机开发的几种调试方案: http://nicekwell.net/blog/20170411/tan-%5B%3F%5D-tan-dan-pian-ji-kai-fa-de-ji-chong-diao-shi-fang-an.html
免责声明:本文素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。
------------ END ------------
后台回复『科普知识』阅读更多相关文章。
欢迎关注我的公众号,回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。
欢迎关注我的视频号:
点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。
-
平衡自行车,平衡自行车视频教学,MDK
2021-09-10 20:43:57基于stm32f103的能够实现自平衡的自行车,简易自主不倒自行车 -
手把手教你做一辆mini平衡自行车!
2021-07-17 00:22:24今天给大家带来的是一个博主老倪制作的迷你的平衡自行车项目,虽然是4年前的老项目了,不过相信我们仍然能从中学到一些新东西。▼ 演示效果自行车平衡DIY分为3部分介绍:第一部分介绍自行车平...今天给大家带来的是一个博主老倪制作的迷你的平衡自行车项目,虽然是4年前的老项目了,不过相信我们仍然能从中学到一些新东西。
▼ 演示效果
自行车平衡DIY分为3部分介绍:
第一部分介绍自行车平衡基本物理原理;
第二部分理论篇,对平衡自行车的算法进行理论分析,包括模型分析、姿态检测方法、PID算法,控制算法;
第三部分实践篇,具体介绍平衡自行车用到的元器件,动力、转向、电路及代码分析。
篇一:自行车平衡原理
自行车是怎么平衡的,老外做过一个非常好的视频:
自行车是怎么保持平衡的?
这个视频很好地证明了常见的”角动量守恒”的说法是错误的,并且正确的说明了自行车平衡原理是和转向相关的,但没有具体指出平衡和转向的关系。
在这里我们就先来讨论一下”角动量守恒”这种最常见的猜测为什么是错误的,大致讨论一下转向是如何使自行车保持平衡的。
1、角动量守恒说
角动量守恒说的意思就是:轮子跑的时候在转动,此时轮子就类似于陀螺,角动量守恒使自行车保持不倒。
小时候也有过这样的疑问,如果把自行车车轮固定从下坡推下,自行车能不能一直往前走?
到底能不能呢?老外的视频做了这个试验:
固定之后就会倒下,可见轮子的陀螺仪效应并不是维持自行车不倒的原因。另外还有老外做了一个没有陀螺仪效应的自行车,该自行车也可以稳定平衡:
以上足以说明陀螺仪效应不是维持自行车平衡的根本原因。
2、转向时的”离心力”是自行车平衡的根本原因
那么什么才是维持自行车平衡的原因呢?
自行车可以看做是一个倒立摆(左右方向不稳定),这个倒立摆受重力作用是一个不稳定系统,需要额外的回复力维持平衡,而提供回复力的正是自行车转向时的”离心力”。
离心力是速度和把手转向角的函数,在一个固定的速度下,可以认为控制把手转向角度就是控制回复力。
我们先记住这一点:维持自行车平衡,需要通过一种合适的算法控制把手角度才能使自行车稳定平衡。
机械自平衡
或许有人会奇怪,有些自行车只要推起来就可以自己平衡,如下面视频:
我自己也买过一个如下面这样的遥控摩托车想要研究一下:
拆开后发现里面并没有精确的转向控制结构,仿佛在行驶时根本没有转向控制,就类似于上面自行车一样自己就可以平衡了。
这到底是怎么回事呢?其实这就是结构设计者的牛逼之处,设计的机械结构自带回复功能,机械结构使得转向会根据车身倾斜而改变,这种改变的幅度正好可以使自行车稳定平衡。
如果我们改变车身结构,可能就会破坏原有的参数,使得自行车无法稳定平衡。如在前轮绑一个重物:
在老外的视频中,分析了车身倾斜对转向的三个影响因素:
前轮转轴后倾,导致倾斜时前轮转向。
把手安装在前面,导致倾斜时前轮转向。
前轮转动时的陀螺仪效应,车身倾斜,陀螺仪效应使得前轮转向。
以上是所谓”机械自平衡”,平衡根本原因还是转向,只不过巧妙的机械设计使得前轮转向特性恰好很容易维持平衡。
手动自平衡
手动自平衡的意思就是我们自己手动控制让它平衡。
我们既然分析平衡原理,还要做一个平衡自行车出来,这一部分要好好研究一下,将会在后面理论篇重点讨论一下控制方法。
篇二:平衡自行车-理论篇
一、模型分析
1、倒立摆
很显然我们知道自行车在左右方向上不稳定,这是一个很常见的物理模型——倒立摆。
顾名思义,倒立摆的意思就是倒着的摆,比如一个倒着的杆,
倒立摆的特性:不稳定,只要偏离平衡位置,就会有一个力(重力的分力)使系统更加偏离平衡位置,这样偏差就会越来越大。
一般倒立的杆在前后左右方向都有可能倒下,在二维的平面上不稳定;而自行车仅在左右方向上可能倒下,是一维的倒立摆,这要简单一些。
以下是几个生活中常见的倒立摆例子:
2、自行车的平衡控制
自行车属于倒立摆模型,倒立摆是不稳定的,那么倒立摆应该如何控制才能平衡呢?
我们把问题拆分一下:
怎样的状态才叫平衡?
我们能控制的是什么?
如何控制才能稳定平衡?
2.1 怎样的状态才叫平衡
我们要对”平衡”进行数学描述,所谓的平衡其实就是倒立摆的倾角稳定在一个我们想要的值。
通常我们想要平衡在
θ = 0
处。2.2 我们能控制的是什么
对于倒立摆模型,通常我们能控制的是底端的 力 或 速度 或 位置,不同的控制量对应的控制方法不同。
对于自行车来说,它的控制方式不像通常的倒立摆那样直接控制底部,而是间接地通过转向来控制,当自行车以一个固定的速度前进时,自行车把手以一定角度进行转向(设为
α
),自行车会做相应半径的圆周运动,产生相应大小的”离心力”。在自行车这个费惯性系里看来,只要对把手进行一定角度的转向(
α
),就会产生一个相应大小的横向力:这就是我们进行平衡控制时的实际控制量——把手转角
α
,只要控制它就能控制回复力。2.3 如何控制才能平衡
上面我们已经能够通过转向产生回复力,这个回复力可以把倒立摆”掰回”平衡位置,有往回掰的回复力就能稳定平衡了吗?
并不是这样,我们再来回顾一下中学物理:
过阻尼状态的摆会以较慢的速度回到平衡位置;
欠阻尼状态的摆会很快回到平衡位置,但会在平衡位置来回摆动;
临界阻尼状态的摆会以最快的速度稳定在平衡位置。
结合到实际的自行车平衡中就是:
如果回复力不够大,就无法矫正,或者矫正速度很慢,这会导致系统不稳定;
如果回复力过大,就会导致矫正过度,这也会导致系统不稳定;我们最希望的状态就是回复力刚刚好,刚好使倒立摆快速回到平衡位置,又不至于矫正过度。
这是一个复杂的数学计算过程,回复力大小会在系统运行时不断地计算(本平衡自行车是
20ms
计算一次),用到的是PID算法,会在后面详细介绍。3、自行车平衡需要解决的基本问题
获取左右方向倾角
θ
以合适的算法控制转角
α
使系统稳定平衡
这将会在下面详细讨论。
二、姿态检测
1、检测的是什么
检测的是自行车左右倾斜的角度。
2、怎么检测
用一个叫
gy521
的模块,里面用的是mpu6050
芯片,带有陀螺仪和加速度传感器。gy521
的具体使用会在第三篇-实践篇介绍,这里我们知道通过这个模块我们可以得到自行车各个方向的加速度和角速度。注意哦,我们不能直接得到倾斜角度,我们的到的是各个方向的加速度和角速度,需要进行一些复杂的计算才能得到正确的倾斜角度。常用的算法有互补平衡滤波、卡尔曼滤波,由于篇幅和精力问题这部分暂不介绍,网上有大量资源,也可以查看本工程源码,以后有时间再写详细教程。
三、PID算法
前面已经分析了,我们通过控制把手转角来控制回复力,我们需要实时计算一个合适的回复力使系统稳定平衡。
这部分内容也不做详细介绍了,网上有大量资源,也可以查看本工程源码。
在这里引用动力老男孩[1]举的一个例子,帮大家简单理解一下需要解决的问题,以及PID算法是如何解决的。
有一个小球在光滑球面上,小球的位置是
x
,光滑球面顶端在L
处,我们可以控制小球水平方向力F
,现在要求让小球稳定平衡在x0
处。先看简单情况
x0=L
,此时偏差为L-x
,我们给出一个比例项
(P) F = kp*(L-x)
,这样就会有一个回复力,当偏差存在时就会有一个力把小球拉回L
处。这存在的问题是,小球接近L时是会有一定速度的,小球越来越接近
L
,此时的力仍然是在把小球往L
处拉,这会导致小球到达L
时(我们想要的位置)速度很大,小球无法立刻停下来,而是会冲过去。这样小球就会在
L
附近来回摆动,这是不稳定的状态,属于欠阻尼状态。为了解决上述问题需要加一个微分项
(D) F = kd*dx/dt = kd*v
,所谓”微分”指的是位置x
对时间的微分,说白了就是速度。意思就是当速度越大,就产生一个反向的力使速度减小,这样就可以防止出现上面小球冲过去的。
可以认为这一项具有”预测”功能,预测小球下一时刻的状态从而提前做出反应(预测小球将要到达
L
处,提前减速),也可以认为这一项具有阻尼作用,相当于系统中有一个和速度成比例的阻尼力。
这个”阻尼力”调得过小会导致欠阻尼状态,调得过大会导致过阻尼状态。
积分项此时可以不用,积分项是当平衡位置
x0
不等于L
时使用的,当平衡位置不是
L
处,那么当小球静止在平衡位置x0
时,由于在坡道上会有一个恒定的横向偏移力,此时比例调节作用为0(Δx=0)
,微分调节作用也是0(v=0)
,所以小球在该处无法平衡,会在更远离平衡位置处达到平衡,那么就会有一个长时间存在的偏差。积分作用就是检测偏差进行累积,对于上面这个长时间存在的偏差进行积分(累积叠加),使系统在长时间范围可以稳定在要求的平衡位置。
篇三:平衡自行车-实践篇
在本文将会介绍平衡自行车的具体制作过程,包括机械、电路和代码。
平衡自行车完整的代码托管在
https://github.com/nicekwell/balance_bike
上GitHub网站卡的同学也可以在文末下载打包好的文档。
一、材料
机械
名称 数量 备注 铜柱、铁丝、胶枪等基础材料和工具 自行车架 1 自己做车架是很麻烦的,我是直接买的车架,淘宝上搜”自行车 拼装 DIY”能搜到很多 舵机 1 转向用的,对于我用的1:6车架,普通舵机有点大,我用的是9g舵机 N20电机 1 选扭力大一点,这样转速会比较稳定 皮带轮和皮带 如上面的图片,我是用皮带来传输动力的 电路
名称 数量 备注 电池、电池盒 洞洞板 lm1117-3.3 降压芯片给控制系统供电 stm32f103c8t6核心板 1 gy521模块 1 加速度传感器 + 陀螺仪 升压模块 1 升到12v给电机供电,根据电机特性选择是否使用升压模块 8050三极管 2 驱动电机,由于自行车不需要反转,所以不需要使用电机驱动芯片,用三极管就能方便地实现。我用了两个三极管并联提高功率。 自锁开关 1 整个系统开关 led指示灯 1 配合1k限流电阻 蓝牙模块 1 可选,如果想要遥控的话就使用蓝牙 二、动力部分
传动方式
如图,我用的是皮带传送的方式,因为比较好实现。
电机选择
这个DIY是不考虑变速情况的,平衡的参数都是按照一个固定速度调的。
所以动力部分的作用就是提供一个恒定的速度,并且这个速度尽可能稳定,尽可能不受外部影响。
电机应选择扭力大一些、转速稳定的减速电机。
电机供电
电机是直接供电还是使用升压模块供电要根据电机特性,有些电机用升压模块可以提高功率,有些大电流电机用升压模块反而可能限制了电流。
我这里用升压模块升到12v给N20电机供电的。
另外,电机通过三极管受stm32控制,通过控制占空比也可以限制电机输出的功率。
三、转向部分
转向部分用一个舵机带动把手转动即可。
四、电路
在GitHub工程里有详细的引脚连接表
https://github.com/nicekwell/balance_bike
供电
用3.3v稳压芯片给整个控制系统供电,包括单片机、GY521模块、蓝牙模块。
用5v稳压芯片给舵机供电。
用12v升压模块给电机供电。
下载
我是用串口给stm32下载程序的。
引脚 功能 PA9 下载TXD PA10 下载RXD GY521
这个模块通过i2c通信,只需要连接4根线。
3.3v
GND
PB0 GY521 I2C SCL
PB1 GY521 I2C SDA (用的是IO模拟i2c)
电机
点击用
12v
升压模块供电,由于不需要反转,用三极管即可直接驱动,电路图如下:加三极管的目的是为了可以通过调节PWM占空比来限制输出功率,但我的实际情况是100%输出时动力才勉强足够。所以如果你不需要限制电机输出功率,或者通过其他方式限制输出功率,也可以不要三极管,不通过单片机控制。
舵机
舵机是用
5v
供电的,而单片机是3.3v
电平,对于pwm控制脚可以通过2个三极管实现同相的电平转换:蓝牙模块
下图是我使用的蓝牙串口模块,可以实现串口透传,只需要4根线连接:
vcc
、gnd
、txd
、rxd
。蓝牙模块是用来调试和遥控的,没有它也能跑。建议还是加上这个模块,在调试PID擦数时会非常方便。
关于调试方面的内容可以参考我写的另一片文章:谈一谈单片机开发的几种调试方案[2]
五、代码结构
代码提交在GitHub
https://github.com/nicekwell/balance_bike
主要分为3个部分:
1、基础的驱动程序,实现电机、舵机、
gy521
数据读取;2、平衡控制系统,核心是一个
20ms
定时器,每20ms
进行一次数据采集、计算和响应;3、遥控和调试系统,实现log输出、接收遥控信息。
驱动
名称 文件 功能 i2c i2c/i2c.c, include/i2c.h IO 模拟i2c驱动,提供i2c基础操作 gy521 gy521/gy521.c, include/gy521.h gy521模块驱动,基于i2c驱动,提供加速度和角速度的读取接口 motor motor/motor.c, include/motor.h 电机驱动,提供占空比控制接口 angle angle/angle.c, include/angle.h 舵机驱动,提供角度控制接口 平衡控制
main
函数会初始化一个定时器20ms中断一次,调用main/balance.c
里的balance_tick
函数,平衡算法在main/balance.c
实现。每
20ms
到来会执行一次:读取传感器加速度和角速度信息。
互补平衡滤波计算当前姿态。
用PID算法计算出前轮转角。
遥控和调试
两部分:状态输出和指令接收。
状态输出
在
main
函数的while
循环里,利用串口中断构建一个简单的界面显示状态。指令接收
串口接收到的数据会传给
main/control.c
,该文件分析串口数据,解释成相应的操作。主要是PID参数调节。参考资料
[1]
动力老男孩: http://www.diy-robots.com/
[2]谈一谈单片机开发的几种调试方案: http://nicekwell.net/blog/20170411/tan-%5B%3F%5D-tan-dan-pian-ji-kai-fa-de-ji-chong-diao-shi-fang-an.html
原文链接:http://nicekwell.net/
项目作者: 老倪
转载请务必注明项目出处与原作者信息
-END-
电赛专栏
-END-
一年一度的电赛又到了,所以近期会写一些关于电赛的文章,欢迎关注!
-
平衡自行车,平衡自行车视频教学,MDK源码.zip
2021-10-11 23:54:51平衡自行车,平衡自行车视频教学,MDK源码.zip -
【动量轮自平衡自行车】STM32_PID(开源-含硬件资料)
2022-02-06 13:56:02【动量轮自平衡自行车】STM32_PID(开源-含硬件资料)动量轮自平衡自行车STM32
如何DIY一辆自平衡自行车?下面将制作内容分享给大家,欢迎讨论交流~。
目 录
3. 0.96寸OLED显示屏(四针、IIC通信、3.3V供电)
一、硬件篇(附淘宝链接,店铺不定,也可自行搜索购买)
1. STM32F103C8T6最小系统(小蓝板)
2. MPU6050姿态传感器(3.3V供电)
3. 0.96寸OLED显示屏(四针、IIC通信、3.3V供电)
4. HC-05蓝牙模块
(串口通信、用于接收小车运动指令)
使用教程链接:https://blog.csdn.net/weixin_44325419/article/details/110727911
5. 超声波测距模块
6. N20电机及驱动(电机选型:DC 12V A12型)
7. 无刷电机动量轮模组
该电机自带驱动和光电编码器。
该自平衡自行车中我们使用万宝至无刷伺服电机,内置驱动,支持正反转,PWM调速,并且带有100线编码器AB相双通道信号输出。
该电机接线图如上图所示,实际小车中的线的颜色可能与上图有所不符,大家要按照位置来判断而不是线的颜色。
1.)信号A相和信号B相为编码器脉冲输出端;
2.)正反转切换的线我们直接用单片机的引脚3.3V电平控制,是完全没有问题的;
3.)编码器供电接3.3V;
4.)PWM接单片机的PWM输出,启动运行我们接单片机IO口,在电机初始化时置为高电平;
5.)电源负极接GND,电源正极接12V。
8. 舵机
视频中所使用,有点小贵,可以买便宜的。
9. 3S航模电池(注意电池尺寸)
10. 稳压模块及开关
将航模电池电压降至5V给单片机、舵机、蓝牙、超声波、电机编码器供电。
11. 轮子及轴承
由于小车后轮是通过皮带传动,为减小摩擦,使后轮转动更加顺滑,需在后轮安装微型轴承。(轴承根据车轴尺寸购买)
尺寸如下:
12. 车架及转向结构(3D打印)
点击文章结尾处B站链接三连加关注并留言(或邮箱)即可获取车架及转向结构3D打印模型文件
13. 电路PCB
将上述功能模块集成在一块PCB电路板上(6.5x7.8cm),为方便焊接,电容电阻及三极管均为直插式元件。作者水平有限,PCB供大家参考,其中不足的地方可自行调整更改。
点击文章结尾处B站链接三连加关注并留言(或邮箱)即可获取PCB工程文件
二、软件篇
点击文章结尾处B站链接三连加关注并留言(或邮箱)即可获取Keil源码文件
1. main.c
#include "sys.h" float AdcValue; //电池电压数字量 float Pitch,Roll,Yaw; //角度 short aacx,aacy,aacz; //加速度传感器原始数据 short gyrox,gyroy,gyroz; //陀螺仪原始数据 int PWM1; int PWM_MAX=6500,PWM_MIN=-6500; //PWM限幅变量 int Encoder_Motor; //编码器数据(速度) int main(void) { NVIC_Config(); delay_init(); Led_Init(); Beep_Init(); Wave_SRD_Init(); uart3_init(9600); OLED_Init(); //初始化OLED OLED_Clear(); adc_Init(); MOTOR_1_Init(); MOTOR_2_Init(); PWM_Init_TIM3(7199,0);//定时器3初始化PWM 10KHZ,用于驱动动量轮电机 PWM_Init_TIM2(9999, 143);//定时器2初始化PWM 50HZ,用于驱动舵机 TIM_SetCompare1(TIM2, 790);//舵机复位 Init_TIM1(9998,7199); Encoder_Init_TIM4(65535,0); OLED_ShowString(25,4,"MPU6050...",16); MPU_Init(); //MPU6050初始化 while(mpu_dmp_init()) { OLED_ShowString(25,4,"MPU6050 Error",16); } OLED_ShowString(25,4,"MPU6050 OK!",16); Beep=1; delay_ms(400); Beep=0; MPU6050_EXTI_Init(); OLED_Clear(); OLED_ShowString(0,0,"Roll : C",16); OLED_ShowString(0,3,"Speed: R ",16); OLED_ShowString(0,6,"Power: V ",16); while(1) { Wave_SRD_Strat(); AdcValue=11.09*(3.3*Get_adc_Average(ADC_Channel_4,10)/0x0fff); //ADC值范围为从0-2^12=4095(111111111111)一般情况下对应电压为0-3.3V OLED_Showdecimal(55,0,Roll,9,16); OLED_Showdecimal(55,3,Encoder_Motor*0.25,9,16); OLED_Showdecimal(50,6,AdcValue,9,16); } }
2. PID控制算法
点击文章结尾处B站链接三连加关注并留言(或邮箱)即可获取PID相关教程资料
该小车更够实现直立平衡需要用到两个闭环控制,即直立环(PD控制、负反馈),速度环(PI控制、正反馈),代码原理及调试过程与两轮平衡小车调试过程基本一致。
关于PID控制算法的学习,内容较多,不好详细展开,网上资源丰富,大家可自行学习。这里推荐一篇知乎文章:https://zhuanlan.zhihu.com/p/39573490
3. TIM2中断
为避免小车在运行调试过程中受到超声波避障功能的干扰,可先将超声波避障功能关闭,超声波避障功能在定时器2中断服务函数中实现,所以将TIM2中断使能关闭即可。
//TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //使能TIM2中断,中断模式为更新中断:TIM_IT_Update
void TIM2_IRQHandler() { static int count=0; if(TIM_GetITStatus(TIM2, TIM_IT_Update)==1) //当发生中断时状态寄存器(TIMx_SR)的bit0会被硬件置1 { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //状态寄存器(TIMx_SR)的bit0置0 count++; if(Distance<8) //与障碍物距离小于8cm时,蜂鸣器发出警报病后退 { Beep=1,Led1=0,Led2=0; Backward(); TIM_SetCompare1(TIM2, 790);//舵机复位 } else Beep=0; if(count==25) //TIM2溢出时间为20ms,20x25=500ms,即后退500ms后停止 { Stopped();count=0; } } }
4. 电池电压检测
一般航模电池的电量是和电压相关的, 过放必然导致电池永久过放,电池损坏,所以我们有必要通过监控电池电压的变化, 近似表示电池的电量, 在电池电量比较低的情况下, 提醒我们充电,充电时间不超过2个半小时,以免电池过充。长期储存时应确保单节电压在3.8V左右,并且每月充电一次。
3S 满电的时候是 12.6V, 过放时电压低于 9.6V。
2S 满电的时候是 8.4 V , 过放时电压低于 7.4V。利用STM32内置ADC测量电池电压,ADC值范围为从0-2^12=4095(111111111111)一般情况下对应电压为0-3.3V,而3S航模电池电压为12V,直接测量将烧毁单片机,因此需要将电池分压,原理图如下:
简单分析可知, 电池电压经过电阻分压, 衰竭为原来的 1/11 之后, 送单片机 ADC检测,再将采集到的电压值乘以11即可得到电池的实际电压。(这里是乘以11.09,可根据实际情况进行微调)
#include "adc.h" #include "delay.h" //ADC初始化函数 void adc_Init() { GPIO_InitTypeDef GPIO_InitStructure; //定义一个引脚初始化的结构体 ADC_InitTypeDef ADC_InitStructure; //定义一个ADC初始化的结构体 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能CPIOB时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能TIM4时钟 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4; //引脚0 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; //引脚输入输出模式为模拟输入模式 GPIO_Init(GPIOA, &GPIO_InitStructure); //根据上面设置好的GPIO_InitStructure参数,初始化引脚GPIOA_PIN0 RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M ADC_DeInit(ADC1); //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //是否为扫描(一组)模式:否:单通道模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //是否为连续转换模式,否:单次转换模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据对齐模式:右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目 ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); //使能复位校准 while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束 ADC_StartCalibration(ADC1); //开启AD校准 while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束 ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 } //采集ADC值函数,输入参数为ADC通道 u16 Get_adc(u8 chn) { ADC_RegularChannelConfig(ADC1, chn, 1, ADC_SampleTime_239Cycles5 ); //ADC1,chn:ADC通道,第3个参数设置该通道的转换顺序(多通道模式下) //采样时间为239.5周期=239.5/ADCCLOK,ADCCLOK=72/6MHZ(6代表ADC初始化时的分频系数) ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果 } //采集多次ADC值求平均值函数,输入参数为ADC通道和采集次数 u16 Get_adc_Average(u8 chn, u8 times) { u32 temp_val=0; u8 t; for(t=0;t<times;t++) { temp_val+=Get_adc(chn); delay_ms(5); } return temp_val/times; }
AdcValue=11.09*(3.3*Get_adc_Average(ADC_Channel_4,10)/0x0fff); //ADC值范围为从0-2^12=4095(111111111111)一般情况下对应电压为0-3.3V
5. OLED显示
一般淘宝购买的OLED显示模块资料中,其显示函数中没有显示小数及显示正负的函数。因此在原有的显示函数中添加了如下函数,从而能够方便的实时显示小车的角度、动量轮转速、电池电压信息。
//显示9位字符,最高位正负,三位整数,第五位小数点,后四位小数部分 //x,y :起点坐标 //len :数字的位数 //size:字体大小 void OLED_Showdecimal(u8 x,u8 y,float num,u8 len,u8 size2) { u8 t,temp,len1,temp1; float temp2; u8 enshow=0; if(num < 0) { OLED_ShowChar(x,y,'0'- 3,size2); num =fabs(num); } else OLED_ShowChar(x,y,' ',size2);//第一位显示符号 temp1 = (int)temp; temp2 = num - temp1; len1 = len - 6;//len1为整数部分位数,若显示数位需要扩展,修改该行 OLED_ShowChar(x + size2/2*4,y,'0'- 2,size2);//浮点数的第5位显示小数点 x = x + size2/2; for(t=0;t<len1;t++)//整数部分的显示 { temp=(int)((num/oled_pow(10,len1-t-1)))%10; if(enshow==0&&t<(len1-1)) { if(temp==0) { OLED_ShowChar(x+(size2/2)*t,y,' ',size2); continue; }else enshow=1; } OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); } OLED_ShowChar(x+(size2/2)*4,y,((int)(temp2*10)%10) + '0',size2); //小数第一位 OLED_ShowChar(x+(size2/2)*5,y,((int)(temp2*100)%10) + '0',size2); //小数第2位 // OLED_ShowChar(x+(size2/2)*6,y,((int)(temp2*1000)%10) + '0',size2); //小数第3位 // OLED_ShowChar(x+(size2/2)*7,y,((int)(temp2*10000)%10) + '0',size2); //小数第4位 }
6. 代码阅读注意点
1.)所有头文件都包含在sys.h中,每个.h文件都包含sys.h,方便函数调用。
#ifndef __SYS_H #define __SYS_H #include "stm32f10x.h" #include "adc.h" #include "oled.h" #include "led.h" #include "beep.h" #include "wave.h" #include "control.h" #include "exti.h" #include "mpu6050.h" #include "inv_mpu.h" #include "inv_mpu_dmp_motion_driver.h" #include "motor.h" #include "pwm.h" #include "encoder.h" #include "usart.h" #include "delay.h" #include <math.h> #include <stdlib.h>
2.)中断优先级分组配置在sys.c文件中
#include "sys.h" /* ============================================================================================================================ NVIC_PriorityGroup | NVIC_IRQChannelPreemptionPriority | NVIC_IRQChannelSubPriority | Description ============================================================================================================================ NVIC_PriorityGroup_0 | 0 | 0-15 | 0 bits for pre-emption priority | | | 4 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_1 | 0-1 | 0-7 | 1 bits for pre-emption priority | | | 3 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_2 | 0-3 | 0-3 | 2 bits for pre-emption priority | | | 2 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_3 | 0-7 | 0-1 | 3 bits for pre-emption priority | | | 1 bits for subpriority ---------------------------------------------------------------------------------------------------------------------------- NVIC_PriorityGroup_4 | 0-15 | 0 | 4 bits for pre-emption priority | | | 0 bits for subpriority ============================================================================================================================ */ void NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStruct_extiB5; NVIC_InitTypeDef NVIC_InitStruct_extiA10; NVIC_InitTypeDef NVIC_InitStruct_usart3; NVIC_InitTypeDef NVIC_InitStruct_tim2; NVIC_InitTypeDef NVIC_InitStruct_tim1; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//4级抢占,4级响应。 //外部中断PB5 NVIC_InitStruct_extiB5.NVIC_IRQChannel=EXTI9_5_IRQn; NVIC_InitStruct_extiB5.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStruct_extiB5.NVIC_IRQChannelPreemptionPriority=0; NVIC_InitStruct_extiB5.NVIC_IRQChannelSubPriority=0; NVIC_Init(&NVIC_InitStruct_extiB5); //USART3 NVIC 配置 NVIC_InitStruct_usart3.NVIC_IRQChannel = USART3_IRQn; NVIC_InitStruct_usart3.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3 NVIC_InitStruct_usart3.NVIC_IRQChannelSubPriority = 0; //子优先级3 NVIC_InitStruct_usart3.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStruct_usart3); //根据指定的参数初始化VIC寄存器 // 定时器2中断 NVIC_InitStruct_tim2.NVIC_IRQChannel=TIM2_IRQn; //属于TIM2中断 NVIC_InitStruct_tim2.NVIC_IRQChannelCmd=ENABLE; //中断使能 NVIC_InitStruct_tim2.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级为1级,值越小优先级越高,0级优先级最高 NVIC_InitStruct_tim2.NVIC_IRQChannelSubPriority=1; //响应优先级为1级,值越小优先级越高,0级优先级最高 NVIC_Init(&NVIC_InitStruct_tim2); //根据NVIC_InitStruct_tim1的参数初始化VIC寄存器,设置TIM2中断 //外部中断PA10 NVIC_InitStruct_extiA10.NVIC_IRQChannel=EXTI15_10_IRQn; NVIC_InitStruct_extiA10.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStruct_extiA10.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStruct_extiA10.NVIC_IRQChannelSubPriority=1; NVIC_Init(&NVIC_InitStruct_extiA10); // 定时器1中断 NVIC_InitStruct_tim1.NVIC_IRQChannel=TIM1_UP_IRQn; //属于TIM1中断 NVIC_InitStruct_tim1.NVIC_IRQChannelCmd=ENABLE; //中断使能 NVIC_InitStruct_tim1.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级为1级,值越小优先级越高,0级优先级最高 NVIC_InitStruct_tim1.NVIC_IRQChannelSubPriority=2; //响应优先级为1级,值越小优先级越高,0级优先级最高 NVIC_Init(&NVIC_InitStruct_tim1); //根据NVIC_InitStruct_tim1的参数初始化VIC寄存器,设置TIM2中断 }
3.)STM32F10x系列的MCU复位后,PA13/14/15 & PB3/4默认配置为JTAG功能。有时我们为了充分利用MCU I/O口的资源,会把这些端口设置为普通I/O口。
使用JLINK向STM32烧录程序时,需要使用6个芯片的引脚(以STM32F103C8T6为例),分别是PB4 / JNTRST,PB3 / JTDO,PA13 / JTMS,PA14 / JTCK,PA15 / JTDI,NRST。当芯片IO口资源比较紧张时,可选择SW模式烧录程序。SWD只需用到PA13 / JTMS,PA14 / JTCK两根线,NREST可以接可不接,剩下的PB4 / JNTRST,PB3 / JTDO和PA15 / JTDI就可以当然普通IO使用,但是这三个口当然普通IO使用时需要先进行如下配置。(这里MPU6050模块用到PB3和PB4引脚)
mpuiic.c
//初始化IIC void MPU_IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB,ENABLE); //打开PB口时钟和AFIO复用时钟 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //重映射 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4; // 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIO GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4); //PB3,PB4 输出高 }
三、链接
-
平衡自行车-实践篇
2021-02-23 21:09:49本人是一名16届智能车比赛单车组的备赛学生,竞速组选择的是单车拉力组,从单车群车友的链接找到三篇文章学习,这是其中的第三篇,这一篇介绍平衡自行车的具体制作过程,包括机械、电路和代码。 欢迎大家一起就16届... -
高配版自平衡自行车附送资料.zip
2022-05-02 16:11:55平衡小车,运用到can总线,mpu6050,adc,iic,步进电机。可以蓝牙,wifi通信,可以通过Android控制小车,同时屏幕上也会显示当前小车信息。 -
行业资料-交通装置-一种力矩平衡自行车.zip
2021-08-30 03:15:11行业资料-交通装置-一种力矩平衡自行车.zip -
行业资料-交通装置-一种动平衡自行车.zip
2021-08-24 17:18:51行业资料-交通装置-一种动平衡自行车.zip -
惯性飞轮侧向平衡自行车机器人V1.0-电路方案
2021-04-22 01:02:03本设计所研究的是基于惯性飞轮的自行车侧向平衡控制。 下图为本实验平台: 飞轮平衡效果测试视频: 自行车初步行走测试视频: 主控采用STM32f103RCT6,传感器采用的是MPU6050,姿态解算采用的是卡尔曼滤波,侧向飞轮控制... -
自平衡自行车机器人的运动学分析 (2011年)
2021-04-25 06:38:20针对一种自行车机器人进行了运动学分析,得到了机器人横滚角度与车把转角和驱动速度之间的函数关系。从理论上给出了能调整机器人平衡所需要的驱动速度下界,只要驱动速度高于此临界值,就能通过调整车把保持车体平衡。... -
【原理分析】Google"炫炸天"的平衡自行车仅仅是概念吗?来看看惯性轮自行车吧...
2020-05-21 23:37:212、Google平衡自行车 下面是从谷歌平衡自行车宣传视频截图,大家可以欣赏一下谷歌的自平衡车: 分析分析: 大伙看完应该会不禁惊叹,真的太厉害了,终于可以解放双手了,甚至还会想着什么时候普及上架,遗憾的是,... -
自平衡自行车本质就是一个惯性飞轮,本质就是一样的!!!
2020-10-12 23:29:55自平衡自行车本质就是一个惯性飞轮,本质就是一样的!!! 什么向前跑,转弯,这都是最基础的电机转动,都不不需要控制什么。不管直行车怎么走,它永远都是一个只能左右摆动的东西,惯性飞轮只需要控制这个左右... -
NXTbike-GS(自平衡自行车机器人 by steer-into-fall):NXTbike-GS 基于嵌入式编码器机器人 NXT 的设计。...
2021-05-30 22:15:13带有由 nxtOSEK 提供动力的陀螺仪传感器的 NXT 自行车。 由代尔夫特理工大学的 JTM Mutsaerts 建造, 自行车动力学实验室, http://www.bicycle.tudelft.nl 。 分配给副教授 Jo W. Spronck。 使用与 NXTway-GS ... -
做一辆超mini平衡自行车,全开源!
2022-02-09 00:12:02大家好,我是张巧龙,今天给大家带来一个平衡自行车,我实验室一个19级的本科生做的,他今年也获得了全国电赛二等奖(F题)的成绩。人嘛,非常帅的一个小伙子。B站ID:_旺仔小菠萝,欢迎大家围观... -
自行车平衡原理
2021-02-23 15:59:29本人是一名16届智能车比赛单车组的备赛学生,竞速组选择的是单车拉力组,从单车群车友的链接找到三篇文章学习,这是其中的第一篇,欢迎大家...博主曾做过一个自平衡的自行车, 自己平衡的自行车 自行车平衡DIY -
基于ADAMS与MATLAB的自平衡车系统控制仿真.pdf
2021-06-27 16:34:32基于ADAMS与MATLAB的自平衡车系统控制仿真.pdf -
基于LQR控制的机器人自行车静态平衡研究.pdf
2021-08-14 06:39:20#资源达人分享计划# -
基于STM32的迷你独轮平衡小车-bbear_balance_car_motor.pdf
2019-09-03 10:59:44基于STM32的迷你独轮平衡小车-bbear_balance_car_motor.pdf