掌上单片机实验室 – 低分辨率编码器测速方式完善(24)

本文主要是介绍掌上单片机实验室 – 低分辨率编码器测速方式完善(24),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、背景

        本以为“掌上单片机实验室”这一主题已告一段落,可最近在测试一批新做的“轮式驱动单元”时,发现原来的测速算法存在问题。

        起因是:由于轮式驱动单元的连线较长,PCB体积也小,导致脉冲信号有干扰,加之脉冲周期正好和定时器溢出的周期相近,使得很多产品在测试过程中,PID调速不成功。先是怀疑硬件焊接存在问题,可连接示波器监测脉冲信号后发现,输出的脉冲是正确的,推测应该是软件上还有不完善之处。加之我一直对目前的测速算法有点不满意,觉得太过复杂,连自己隔段时间再看程序,都有点晕,所以决心彻底完善一下。

        这个算法断断续续搞了10多年了,一开始因为只是做示例程序,没有太花心思,只是将曾在工作中用过的思路搬了过来,以解决所做的小车编码器分辨率较低的问题,实现用低分辨率码盘实现测速、调速。测试虽不完美,但能实现,也就没有再深究。后来因为各种原因,小车的事情也是断断续续,测速的问题也就被搁置了。

        这次重拾小车,感觉应该彻底解决一下,不留遗憾;调速PID自整定问题解决了,测速就成了小车能否可靠调速的唯一障碍。所以再次审视自己原来的构思,是否设计上就存在不合理之处。

二、问题发现及完善方案

        目前的测速方式是:利用前一脉冲的周期,计算当前测速周期结束时不完整脉冲的当量,从而提高测量精度。

        因为目前小车硬件所提供的码盘,分辨率较低,脉冲频率一般在10 ~ 200Hz之间,如果将测速周期定为100ms,用计数法,每次只有不到20个脉冲,一般在10个一下,量化误差太大。

        所以才想出所谓基于前一脉冲周期倍频的方式。但实施下来发现,为了避免各种意外导致计算出错,尤其是采集脉冲通常使用中断,计算则在中断外完成,为了消除由此可能产生的异常,在程序上逐步增加了不少代码,导致可读性极差,且并未真正消除。

        这次在轮式驱动单元的成品测试中,对照示波器采集的脉冲信号,就发现了由于上述原因导致的粗大误差。

        重新思考原来的测速构思,发现自己有点“自寻烦恼“,折腾了半天,把代码搞得那么复杂,其最后的实质就是用测周期方式代替计数法测速(也就是频率)!所有的问题以及增加的防护代码都源于最后那个不完整的脉冲是否计入本次测速的计算。可实质是:即便实现了,也是基于前一脉冲周期的推测,而非实际情况,没有价值。

        所以,决定只使用周期计算,放弃最后一个不完整脉冲。但为了避免单个脉冲的波动(由于结构上的问题,存在这种可能),导致速度变化不真实,取前N个脉冲的平均周期作为计算依据。如针对我所做的轮式驱动单元以及FIRA小车,轮子转一圈的脉冲分别为100、60,假设用10个脉冲的平均周期计算,实质上只对应了轮子1/10(1/6)圈,也就是说可以一圈中调整10(6)次速度,完全可以满足需求。

        替换为这个算法后,程序大大简化了,逻辑很清楚。

        原来程序设计的脉冲周期采集方式我觉得还不错,保留不变,具体方式是:

        建立一个连续的 us 计时器,每采集一个脉冲,对应记录一个时标,设置一个16个单元的环形缓存,可记录前16个脉冲对应的时标。计算时,用当前脉冲时标减前N个脉冲的时标,即可得到N个脉冲的平均周期。

        之前为了尽量使用 Arduino 原生函数,us定时器直接使用了 micro() 函数;由于采集是在中断程序中完成,似乎存在问题,没有去仔细研究这个函数是如何实现的,暂时放弃,改为使用硬件定时器。

        为了可靠采集脉冲周期,尝试使用了 HAL 函数,可行。使用时发现,STM32duino也在不断完善,以前在2.2.1版本中也用过,这次升级为 2.7.1,发现原来的方式不行了,阅读硬件定时器头文件发现,增加了获取硬件定时器句柄的函数:

        以便方便使用HAL库,从而使用定时器的一些高级功能。

        唯一增加的防护性代码是:

        因为作为时标的计时器设计为32位,高16位是硬件定时器溢出中断程序中软件计时实现的;而记录脉冲时标也是在中断中操作,如果出现读取计时值时正好计时器产生溢出中断,而此时由于正处于脉冲中断服务中无法响应,则会出现计时器高位少计,导致脉冲时标出错,防护方式如下:

        此外,新增加了脉冲干扰处理,因为正常脉冲宽度至少1ms(按目前设计,转速最快也不到1kHz),小于此宽度应该是干扰信号所致。正好使用了硬件定时器,启用通道比较功能,脉冲中断只是启动定时器延时(暂定延时500us),延时触发中断后,采集脉冲引脚,如脉冲信号仍然有效,则确定为有效脉冲,执行相应处理:

        这样修改后的测速计算如下:

        和原来的测速计算比较(可以看前面上传的程序),新的只有20行代码,原来的有约70行代码。关键是,修改后的测速效果更好、更可靠了;原来在绘制速度曲线时,总会出现一些异常值,这次完善后从未出现。实际效果如下:

1、自整定波形:

2、调速波形:

        十分满意,圆梦小车应该说画上了一个完美的句号,因为作为小车底盘部分,测速、调试是核心功能。

三、结语

        圆梦小车从2005年开始做,测速、调速一直是困扰着小车,因为宗旨是作为学习素材,初衷就是要基于低端的电机、简易的编码器实现小车的测速和调速。通过开模,在轮毂上实现了60、100线的简单编码器,控制小车行走距离尚可,精度大约在2~3mm左右,作为测速就十分勉强了,只有通过算法弥补。这些年一直没有沉下心来去完善,这次总算是了了一桩心事。

        最近GPT比较热,能够自动生成代码,我在上述优化算法过程中,也尝试了 AI,它给出的代码猛一看,煞有介事,仔细一琢磨,似是而非。尤其是单片机应用这种和硬件直接相关,且很多时候是为了弥补硬件局限性、不一致性所构思的代码,似乎 AI 目前还无法应对。或者说这类代码网上分享的太少,类似于前面写的内容在网上占比很低,没有提供给AI足够的学习素材。看来在ChatGPT引来的职业哀鸣中,似乎嵌入式硬件工程师还能多存在一会儿。

————————————

完善后的单片机程序:

链接:https://pan.baidu.com/s/1L_iUJLdNrUkOCDE3acZGXw

提取码:132v

配套完善后的PC端程序:

链接:https://pan.baidu.com/s/1NBOYZzWUpszxQmsnMMfbww

提取码:ospn

这篇关于掌上单片机实验室 – 低分辨率编码器测速方式完善(24)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/622260

相关文章

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

Vue3视频播放组件 vue3-video-play使用方式

《Vue3视频播放组件vue3-video-play使用方式》vue3-video-play是Vue3的视频播放组件,基于原生video标签开发,支持MP4和HLS流,提供全局/局部引入方式,可监听... 目录一、安装二、全局引入三、局部引入四、基本使用五、事件监听六、播放 HLS 流七、更多功能总结在 v

Java发送SNMP至交换机获取交换机状态实现方式

《Java发送SNMP至交换机获取交换机状态实现方式》文章介绍使用SNMP4J库(2.7.0)通过RCF1213-MIB协议获取交换机单/多路状态,需开启SNMP支持,重点对比SNMPv1、v2c、v... 目录交换机协议SNMP库获取交换机单路状态获取交换机多路状态总结交换机协议这里使用的交换机协议为常

k8s admin用户生成token方式

《k8sadmin用户生成token方式》用户使用Kubernetes1.28创建admin命名空间并部署,通过ClusterRoleBinding为jenkins用户授权集群级权限,生成并获取其t... 目录k8s admin用户生成token创建一个admin的命名空间查看k8s namespace 的

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni

Pandas处理缺失数据的方式汇总

《Pandas处理缺失数据的方式汇总》许多教程中的数据与现实世界中的数据有很大不同,现实世界中的数据很少是干净且同质的,本文我们将讨论处理缺失数据的一些常规注意事项,了解Pandas如何表示缺失数据,... 目录缺失数据约定的权衡Pandas 中的缺失数据None 作为哨兵值NaN:缺失的数值数据Panda

java读取excel文件为base64实现方式

《java读取excel文件为base64实现方式》文章介绍使用ApachePOI和EasyExcel处理Excel文件并转换为Base64的方法,强调EasyExcel适合大文件且内存占用低,需注意... 目录使用 Apache POI 读取 Excel 并转换为 Base64使用 EasyExcel 处

Spring Boot中获取IOC容器的多种方式

《SpringBoot中获取IOC容器的多种方式》本文主要介绍了SpringBoot中获取IOC容器的多种方式,包括直接注入、实现ApplicationContextAware接口、通过Spring... 目录1. 直接注入ApplicationContext2. 实现ApplicationContextA

linux查找java项目日志查找报错信息方式

《linux查找java项目日志查找报错信息方式》日志查找定位步骤:进入项目,用tail-f实时跟踪日志,tail-n1000查看末尾1000行,grep搜索关键词或时间,vim内精准查找并高亮定位,... 目录日志查找定位在当前文件里找到报错消息总结日志查找定位1.cd 进入项目2.正常日志 和错误日