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

相关文章

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

【即时通讯】轮询方式实现

技术栈 LayUI、jQuery实现前端效果。django4.2、django-ninja实现后端接口。 代码仓 - 后端 代码仓 - 前端 实现功能 首次访问页面并发送消息时需要设置昵称发送内容为空时要提示用户不能发送空消息前端定时获取消息,然后展示在页面上。 效果展示 首次发送需要设置昵称 发送消息与消息展示 提示用户不能发送空消息 后端接口 发送消息 DB = []@ro

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

脏页的标记方式详解

脏页的标记方式 一、引言 在数据库系统中,脏页是指那些被修改过但还未写入磁盘的数据页。为了有效地管理这些脏页并确保数据的一致性,数据库需要对脏页进行标记。了解脏页的标记方式对于理解数据库的内部工作机制和优化性能至关重要。 二、脏页产生的过程 当数据库中的数据被修改时,这些修改首先会在内存中的缓冲池(Buffer Pool)中进行。例如,执行一条 UPDATE 语句修改了某一行数据,对应的缓

Java 多线程的基本方式

Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):

前端form表单+ifarme方式实现大文件下载

// main.jsimport Vue from 'vue';import App from './App.vue';import { downloadTokenFile } from '@/path/to/your/function'; // 替换为您的函数路径// 将 downloadTokenFile 添加到 Vue 原型上Vue.prototype.$downloadTokenF

单片机毕业设计基于单片机的智能门禁系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍程序代码部分参考 设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订