掌上单片机实验室 – 低分辨率编码器测速方式完善(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

相关文章

linux打包解压命令方式

《linux打包解压命令方式》文章介绍了Linux系统中常用的打包和解压命令,包括tar和zip,使用tar命令可以创建和解压tar格式的归档文件,使用zip命令可以创建和解压zip格式的压缩文件,每... 目录Lijavascriptnux 打包和解压命令打包命令解压命令总结linux 打包和解压命令打

Python中常用的四种取整方式分享

《Python中常用的四种取整方式分享》在数据处理和数值计算中,取整操作是非常常见的需求,Python提供了多种取整方式,本文为大家整理了四种常用的方法,希望对大家有所帮助... 目录引言向零取整(Truncate)向下取整(Floor)向上取整(Ceil)四舍五入(Round)四种取整方式的对比综合示例应

Rust格式化输出方式总结

《Rust格式化输出方式总结》Rust提供了强大的格式化输出功能,通过std::fmt模块和相关的宏来实现,主要的输出宏包括println!和format!,它们支持多种格式化占位符,如{}、{:?}... 目录Rust格式化输出方式基本的格式化输出格式化占位符Format 特性总结Rust格式化输出方式

将java程序打包成可执行文件的实现方式

《将java程序打包成可执行文件的实现方式》本文介绍了将Java程序打包成可执行文件的三种方法:手动打包(将编译后的代码及JRE运行环境一起打包),使用第三方打包工具(如Launch4j)和JDK自带... 目录1.问题提出2.如何将Java程序打包成可执行文件2.1将编译后的代码及jre运行环境一起打包2

C++一个数组赋值给另一个数组方式

《C++一个数组赋值给另一个数组方式》文章介绍了三种在C++中将一个数组赋值给另一个数组的方法:使用循环逐个元素赋值、使用标准库函数std::copy或std::memcpy以及使用标准库容器,每种方... 目录C++一个数组赋值给另一个数组循环遍历赋值使用标准库中的函数 std::copy 或 std::

spring-boot-starter-thymeleaf加载外部html文件方式

《spring-boot-starter-thymeleaf加载外部html文件方式》本文介绍了在SpringMVC中使用Thymeleaf模板引擎加载外部HTML文件的方法,以及在SpringBoo... 目录1.Thymeleaf介绍2.springboot使用thymeleaf2.1.引入spring

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

SQL 中多表查询的常见连接方式详解

《SQL中多表查询的常见连接方式详解》本文介绍SQL中多表查询的常见连接方式,包括内连接(INNERJOIN)、左连接(LEFTJOIN)、右连接(RIGHTJOIN)、全外连接(FULLOUTER... 目录一、连接类型图表(ASCII 形式)二、前置代码(创建示例表)三、连接方式代码示例1. 内连接(I

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干