用STM32F401和nRF24L01制作无线调速小车
硬件配置
在做这个小项目前, 考察过STM32F103C8T6
, STM32F401CCU6
和STC89C52
这三个MCU, 并实际跑了一些用例
- STC89C52在代码上要简单得多, 它的问题是没有ADC功能, 所以无法用于遥控器部分, 只能用于小车部分, 而且PWM输出是软输出, 通过主循环实现的. 带ADC功能的STC单片机型号有STC12C5A系列和STC15F, STC15W系列, 但是现在市场价格都很贵, 单单芯片就需要22RMB.
- STM32F103C8T6的功能应对这个项目没问题, 在网上这个型号的代码特别丰富, 问题在于现在价格太贵了, 一个原装芯片的最小系统板价格为38RMB, CH版也要25RMB, 相对于高一代且系统板价格仅为15RMB的STM32F401CCU6没有优势.
- STM32F401CCU6最小系统板价格15RMB, 功能应对这个项目没有问题, 它的劣势是可参考的资料少. STM32F4系列在国内使用的较少, 代码例子在网上少并且很多是针对F407这些高级型号的, 如果用在F401上需要额外的调整.
最终选择的是STM32F401CCU6, 代码上的问题都不是问题, 对吗?
遥控器部分
- 电源: 3.7V 18650锂电
- 3.3V稳压: 一个1N4148二极管
- MCU: STM32F401CCU6最小系统板
- 输入: 双轴摇杆模块
- 无线: nRF24L01模块
硬件部分的说明
- 1N4148能产生0.6V的压降, 对于3.7V的锂电来说是足够的, 实际测试18650两端电压约4.0V, 通过1N4148后输出的电压是3.2V. STM32F401CCU6, nRF24L01和双轴摇杆耗电量都非常小, 1N4148应付这个没问题.
- 因为单节18650电池盒输出线是裸的多芯软线, 不方便直接连到模块上, 并且因为这部分两个模块nRF24L01和双轴摇杆都需要用到3.3V电压, 所以另外用万能板做了一个中转, PCB接线端子用来连接电源线, 3V3通过一个1N4148后接到3V3的排针上, 另一个排针是地线.
- 这个接线端子是从炸掉的L9110s模块上拆的
小车部分
- 电源: 7.4V (18650锂电x2)
- 6V稳压: 串联两个IN4007
- 3.3V稳压: AMS1117 3.3V模块
- MCU: STM32F401CCU6
- 无线: nRF24L01模块
- 电机驱动: L9110双路x2
- 小车底盘
- 48:1减速电机x4
硬件部分的说明
- 电机用的是普通的48:1减速电机, 工作电压为6V, 另外L9110s虽然标称能到12V, 市面上的L9110s大部分到不了这么高, 安全电压在7V左右, 所以这里需要将电压降到6V附近, 通过两个1N4007能产生1.2V的压降
- 运行时每个电机的电流为0.15A, 合计0.6A, STM32F401,nRF24L01的耗电可以忽略不计, 1N4007的工作电流为1A, 应该是够的
- STM32需要的3.3V和电源电压相差较远, 直接用AMS1117模块做降压了
- 因为有4个电机, 所以需要两个双通道L9110s模块
- 电池盒引出的是裸的多芯软线, 不方便直接连到模块上, 因此另外用万能板做了个中间板, 加了接线端子连接电池盒, 正极串联两个1N4007输出到正极排针, 另外还有地线排针, 以及四组排针用于L9110s的输入(各侧的两个通道共用一组PWM)
接线
遥控器部分
MCU需要的接口如下
- UART: 方便调试
- PA9 => USB2TTL的RX
- PA10 => USB2TTL的TX
- SPI: 连接nRF24L01
- PA5,PA6,PA7, PB13,PB14,PB15
- ADC: 两个pin, 连接双轴摇杆
- PA0 => 摇杆AXIS X
- PA1 => 摇杆AXIS Y
- VCC
- GND
与nRF24L01的接线
STM32 | nRF24L01 |
---|---|
PA4 SPI1_NSS | N/A |
PA5 SPI1_SCK | SCK |
PA6 SPI1_MISO | MISO |
PA7 SPI1_MOSI | MOSI |
PB13 | IRQ |
PB14 | CE |
PB15 | CSN |
小车部分
MCU需要的接口如下
- UART: 方便调试
- PA9,PA10, 同上
- SPI: 连接nRF24L01
- PA5,PA6,PA7, PB13,PB14,PB15
- PWM: 4个pin, 输出4组PWM, 分别对应左右侧的两组 L9110
- PA0,PA2: 左侧电机
- PA1,PA3: 右侧电机
nRF24L01接线同上.
功能实现
遥控器部分
这一块主要是通过两个ADC通道采集摇杆电压, ADC采集使用的DMA的模式, 在主循环中定时(几十到几百毫秒)去读取电压, 并转换到[0, FF]区间, 通过nRF24L01发射出去. ADC采集电压时, 每个通道使用4个u16做缓存, 输出的数值是对这个4个数值做平均, 抑制抖动.
涉及的技术名词: UART, ADC, DMA, TIMER, SPI
小车部分
小车部分的功能有几部分:
- nRF24L01的中断接收. 需要将nRF24L01的接收配置为中断模式, 这样只有在遥控端发出指令时, 小车才做相应的动作, 相比在循环中检测接收信息并调整输出的实现方式更及时高效.
- PWM输出控制小车的速度和方向.
- 将接收得到的X轴Y轴向量, 映射到两路电机的方向和强度.
涉及的技术名词: UART, TIMER, EXTI, SPI, PWM
以下具体说明
nRF24L01的中断接收
这部分需要在STM32上新增一个EXTI中断源, 映射到nRF24L01的IRQ PIN脚. 这个中断是低电平触发, 注意在处理完中断后, 需要清空接收缓冲, 不然下一次还会读到旧值.
中断处理的方法内根据接收到的数值调整PWM输出, 实现遥控功能.
这里还有一个定时器TIM3, 当前设置的定时时间为0.5秒, 每次中断处理时会将定时器初始化, 在定时器经过0.5秒后触发时, 会将PWM输出归零, 归零后电机都会停止. 通过这个机制, 在遥控器发出指令后小车会在当前指令下输出PWM 0.5秒, 如果持续收到指令则持续输出, 如果未收到指令, 则在0.5秒后停止输出, 体现在小车运动上, 就是每次指令下小车会移动0.5秒.
PWM输出控制速度和方向
PWM的频率选择: 48:1减速电机是淘宝上最便宜常见的减速电机, 最佳PWM频率是25Hz-50Hz. 这个频率的来源在这里, 里面有很详细的说明和实验测试结果. 我把我关心的部分内容翻译了一下, 可以看这里. 我在实际使用中观察到的结果是符合这篇文章的结论的.
这里多说几句. 关于电机的PWM频率选择, 在网上查了很久, 得到的结果大部分是错误的, 很多人文章里写的频率是6-20KHz. 这里需要注意区分一下, 如果你用的是直流有刷电机, 那么用这么高的PWM频率是会出问题的, 建议在几十到几百Hz的范围去测试.
PWM控制速度比较好理解, 但是控制方向的具体实现需要通过两个PWM配合. 尝试过通过1路PWM+1路GPIO进行方向切换, 但是无法正常工作, 最后还是要通过两路PWM. 根据方向, 设置其中一路PWM输出为0. 这里为了避免出现双高电平(网上有很多人提到双高导致L9110s烧毁), 在程序中先设置输出为0的一路PWM, 再输出另一路不为0的PWM.
X轴Y轴向量映射到左右两路电机
这一块花了我一些时间. 在网络上找到的资料看, 实现方式更多是通过Y轴计算出左右电机整体的前进后退占空比, 然后通过X轴计算左右电机占空比差值, 再将这两个结果叠加, 得到最后的左右电机占空比. 这个计算方式的问题是当工作点在Y轴区间两端的时候, 此时叠加的差值会使Y轴的值超出区间, 但是实际上这个数值是不可能的, 所以要么将两个通道的数值都往回拉, 要么就忽略Y轴超出区间的部分, 都不是很合理.
我使用的计算方式, 是先规定摇杆圆周4个方向上对应LR通道的值:
- 0° => L:FF, R:-FF
- 90° => L:FF, R:FF
- 180° => L:-FF, R:FF
- 270° => L-FF, R:-FF
将摇杆得到的XY轴的值做成向量, 将这个向量投影为圆周上某一点, 再根据圆周上这个点两端的值计算当前点的LR值.
因为摇杆得到的XY轴空间, 实际上是一个正方形, 将其映射到圆上时, 有一个有趣的现象, 当角度位于0°到45°时, 向量的长度等于X轴的值, 而在45°到90°时, 向量长度等于Y轴的值, 这个使得计算简便了许多.
遇到的问题
L9110s发热烧毁
电源为两节18650, 电压为3.7x2=7.4V, 两路pwm输出, 当从0,0 -> 0,全速时, 电机无动作, L9110s发烫然后冒烟烧毁. 这个直接导致两个模块各烧了一片L9110s. 于是上网查相关的资料
相关的讨论
- Is this the reason for burning my h-bridge? https://www.eevblog.com/forum/beginners/is-this-the-reason-for-burning-my-h-bridge/
- L9110 IC goes up in smoke https://forum.arduino.cc/t/l9110-ic-goes-up-in-smoke/367873
- L9110 up in smoke https://forum.arduino.cc/t/l9110-up-in-smoke/381488
- https://forum.arduino.cc/t/fried-my-mega-and-multiple-dc-motor-control-boards-how-can-i-prevent-this/664303
- AB全高状态,静态加电时AB=HH没有发热,但是给1kHz脉冲,9110就冒烟.正常驱动A=H,B=L时,B变H感觉有短时间刹车现象,因为如果A=0,电机停得慢,当A=H,B由L变H就快速停.按理AB=HH是可以的,只是实际结果,静态没问题,动态就烧了 https://www.amobbs.com/thread-4986052-1-1.html
- https://www.zhihu.com/question/52548517
- https://www.icxbk.com/ask/detail?tid=30203
- 对直流电机选择最优的PWM频率 https://learn.adafruit.com/improve-brushed-dc-motor-performance?view=all
因为模块已经带了输出电容和上拉电阻, 所以
可能的原因是
- 电机启动电流过大导致模块烧毁. 电机静态电阻为6.5Ω, 电压7.4V时电流超过1A,
应对方案: 串联一个5Ω的限流电阻, 可以将电流降到7.4/(6.5+5)=0.64A, 避免超出L9110s的最大电流, 运转中的电机阻抗为40Ω - 45Ω, 此时电阻上的分压不到1V, 影响不大. - L9110s耐压超限. 有人说最高到6.5V.
应对方案: 在L9110s输入电压前串联2个1N4007, 将电压降到7.4-1.4=6V, 串联2个时,启动电流1A,正向电阻0.7Ω, 空转时0.15A,正向电阻5Ω - PWM频率过高. 过高的PWM频率会导致电机在低占空比时无法启动,
- PWM同时输出高电平
最终解决方案
- 串联两个1N4007将电压降到6.2V
- PWM频率降到100Hz
有些占空比下电机不动
在逐渐增大占空比的过程中, 有些值下电机不转, 能听到吱吱声, 如果手摸着L9110s芯片, 能感觉到此时有一阵发烫, 所以此时电流到位了, 但是没能驱动电机.
这个原因和前一个问题是一样的, 因为PWM频率过高(17.5KHz), 无法驱动电机, 在将频率降到100Hz后这个问题就没再出现.
小车在运行一段时间后中断灯常亮, 失去响应
经过检查, 是因为在处理nRF24L01接收中断时, 加入了一个延时1ms的处理, 会卡在这个延时函数上, 将这个延时处理删除后就未再出现这个情况
参考
用STM32F401和nRF24L01制作无线调速小车的更多相关文章
- 玩转X-CTR100 l STM32F4 l TB6612直流电机调速控制
我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] 本文介绍X-CTR100控制器的直流调速电机控制,X ...
- 直流调速系统Modelica基本模型
为了便于在OpenModelica进行仿真,形成一个完整的仿真模型,没有使用第三方的库,参照了DrModelica的例程,按照Modelica库的开源模型定义了所用的基本元件模型. 首先给出一些基本类 ...
- 过渡与动画 - steps调速函数&CSS值与单位之ch
写在前面 上一篇中我们熟悉五种内置的缓动曲线和(三次)贝塞尔曲线,并且基于此完成了缓动效果. 但是如果我们想要实现逐帧动画,基于贝塞尔曲线的调速函数就显得有些无能为力了,因为我们并不需要帧与帧之间的过 ...
- PLECS_晶闸管调速系统_9w
3. 直流电机开环调压调速系统模型搭建 (1)电路图 (2)仿真 当 α = pi / 2.7 的时候,直流电机的稳定转速大约保持很低的速度. 随着α的减少,直流电机的速度逐渐增大.当α = pi / ...
- 过渡与动画 - 逐帧动画&steps调速函数
写在前面 上一篇中我们熟悉五种内置的缓动曲线和(三次)贝塞尔曲线,并且基于此完成了缓动效果. 但是如果我们想要实现逐帧动画,基于贝塞尔曲线的调速函数就显得有些无能为力了,因为我们并不需要帧与帧之间的过 ...
- 过渡与动画 - 缓动效果&基于贝塞尔曲线的调速函数
难题 给过渡和动画加上缓动效果是一种常见的手法(比如具有回弹效果的过渡过程)是一种流行的表现手法,可以让界面显得更加生动和真实:在现实世界中,物体A点到B点往往也是不完全匀速的 以纯技术的角度来看,回 ...
- [问题解决]不使用PWM调速系统,彻底解决一个L298N带动两个电机却转速不同的问题
问题描述:由单片机的VCC引脚供电,使用L298N控制两个电机,发现左右两个轮子的转速老是不一样,更多的情况是左轮转速高(左轮电机接OUT1和OUT2),右轮转速低(右轮电机接OUT3和OUT4)甚至 ...
- 直流电机PWM调速系统中控制电压非线性研究_控制元件_工业自动化控制_文章
直流电机PWM调速系统中控制电压非线性研究_控制元件_工业自动化控制_文章_e-works数字化企业网 http://articles.e-works.net.cn/Component/Article ...
- 51单片机—使用PWM对直流电机调速
文章目录 - 什么是PWM - PWM是怎么对直流电机进行调速的 - 通过定时器中断实现PWM调速 - 上代码 - 什么是PWM PWM(脉宽调制),是靠改变脉冲宽度来控制输出电压,通过改变周期来控制 ...
- Renix中如何实现流调速——网络测试仪实操
在Renix操作中有时我们需要进行流调速,那么如何实现呢?接下来为您详细介绍. 第一步:预约测试资源 首先打开Renix软件,连接机箱, 预约端口 第二步:流调速 例如:端口下有3条流,分别设置为10 ...
随机推荐
- python3使用json、pickle和sqlite3持久化存储字典对象
技术背景 在各种python的项目中,我们时常要持久化的在系统中存储各式各样的python的数据结构,常用的比如字典等.尤其是在云服务类型中的python项目中,要持久化或者临时的在缓存中储存一些用户 ...
- Laravel - blade 基础语法和include的使用
<!-- 1. 模板中输出PHP变量 --> @section('footer') <div style="color:#fff"> @par ...
- 常见的IE布局兼容问题
(1) div 中内容在IE和火狐中居中问题: (2)高度的问题,div出现重叠 (3)浮动引发的问题如外围DIV无法框住内部元素: (4)IE浮动margin产生双倍距离-display:inli ...
- MyBatis04——使用注解开发
使用注解开发 MyBatis3提供了新的基于注解的配置,但是MyBatis映射并不能用注解来构建. sql类型主要分成: @select @update @insert @delete 注意:利用注解 ...
- Nginx双层域名时 iframe嵌入/跳转页面的处理过程
Nginx双层域名时 iframe嵌入/跳转页面的处理过程 背景 两年前在上一家公司内遇到一个Nginx的问题 当时的场景是 双层nginx代理时(一层域名侧, 一层拆分微服务的网关层) 程序里面会打 ...
- [转帖]Docker限制容器的资源
docker在默认运行容器的情况下,是不会对运行的容器进行资源限制的,在自己的实验环境的话是随便你怎么弄的,不过在生产中是一定会对docker运行的容器进行资源限制的,如果不限制的话在生产中会带来 ...
- redis 6源码解析之 sds
redis使用sds(simple dynamic string)实现了字符串的存储.sds实际上就是TLV格式的数据结构.其数据结构主要分为如下5种,主要分为首部和数据部分,首部给出了type和le ...
- vue混入mixin
<div id="app"> --{{nick11}} </div> <script> // 全局混入 不需要注册 var m1 = Vue.m ...
- c#通过表达式树优雅的实现分组取TopN笔记
需要引入nuget包来实现ef.functions调用row_number Thinktecture.EntityFrameworkCore.SqlServer 调用方式: //顺排 context. ...
- VictoriaMetrics源码阅读:极端吝啬,vm序列化数据到磁盘的细节
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu 公众号:一本正经的瞎扯 源码请看:https://github.com/ahfuzhang/vi ...