智能小车——底层配置

需要一点点思考底层的相关配置都需要完成怎么样的配置,并进一步添加相关的状态机和控制算法。

FreeRTOS迁移

可以直接CubeMX生成,也可以手动把FreeRTOS的源码拖到工程中,然后再稍微配置一下,这个之前学正点原子的FreeRTOS的时候有做过。

底层初始化

ADC配置

需要用到的是两个ADC通道:。

  1. 配置PB1,对应的是ADC1,模拟输入且不带上下拉;ADC模式配置为独立、两采样间隔5个tick,DMA失能且用6分频;配置为12位模式,非扫描非连续,禁止触发检测右齐,规则序列为1。这个引脚就是ADC的通道9。
  2. 配置PB0,对应ADC2,其余的配置与PB1是一样的。就是ADC的通道8。

需要编写两个函数,来获取ADC采集的数据分别需要先完成配置采样时间,然后开启转换,通过while并判断标志位确认ADC转换完成后,将结果return出来。

在本次项目中,ADC1的Pin脚是连接到了小车运动模型的选择的,所以采集了对应的数据之后,需要做一个均值滤波;ADC2则是直接连接到了电池引脚,通过电路图做一个引脚夕グ计算转换之后就可以得到电池实际的电压值。

CAN配置

配置CAN总线的相关参数。

  • CAN1初始化

本次项目中使用的是PD0和PD1作为CAN总线的GPIO口,对应的是CAN1。两个引脚的GPIO均选为复用,推挽输出,设置为上拉;为了使用CAN1,还需要设置引脚复用;CAN的配置,先退出睡眠模式,进入初始化后,配置为非时间触发,自动离线管理,软件触发,禁止报文自动发送,报文不锁定,优先级通过标识符决定;之后通过参数配置模式、重新同步跳跃宽度、时间段1和时间段2的时间长度、分频系数,最后推出初始化模式;设置过滤器,进入过滤器初始化后,过滤器0不激活,位宽32位,工作在标识符屏蔽位,关联到FIFO0,32位ID和MASK暂时全配置为0,然后激活过滤器0;通过宏定义使能中断接收,FIFO0配置为允许中断,NVIC配置CAN1接受中断,抢占优先级1,子优先级3,然后使能IRQ,NVIC初始化之后再CAN的IT使能。

  • CAN发送报文

CAN1一共3个邮箱,先判断邮箱是否为空,如果邮箱都满了直接return 0xFF;有空邮箱,先清除之前的设置,判断待发送是标准帧/扩展帧,将数据取出,然后根据输入函数的id号、数据帧/远程帧,dlc以及实际数据,通过CAN1刚刚判断到的空邮箱进行数据发送。

  • CAN发送状态

通过判断邮箱的标志位,完成发送状态的获取。

  • 获取报文个数

需要判断在FIFO中的报文个数,可以直接通过CAN1的标志位来获取。

  • CAN接收报文

跟发送是类似的,需要邮箱号、id号、数据帧、标准帧判断、数据长度等输入参数;通过这些参数获取到当前报文的具体信息后,:将报文数据存到开辟好内存的数据数组之中,并在此之后释放邮箱。

  • CAN中断服务函数

通过宏定义控制,实际使用中需要开启。中断服务中,需要完成报文的接收,并根据接收到的报文ID号,来完成对应的小车命令计算设置

  • CAN接受数据

同理,调用CAN接收报文的函数,会先调用报文个数获取的函数,判断是否有内容接收,之后有报文就会调用接受函数,并返回读取的数据长度。8.给指定ID发送报文调用报文发送函数,对指定的id号发送报文。

DMA配置

dma这边是用在串口2的信息传输的,串口2会连接到WiFi/蓝牙的模块,用于APP控制小车。

dma需要传入参数:数据大小、数据基地址dma内存及地址、dma缓存大小;传输方向直接配置为内存到外设,外设地址寄存器不变数据宽度为8,内存数据宽度为8,正常缓存模式,dma通道高优先级,dma的内存到内存通道关闭;设置为以上之后直接初始化dma。

dma传输一次,都要先关闭,然后调用函数来传输一次,然后再开启dma。

encoder配置

这里就是配置电机编码器相关内容,涉及到了Timer的配置。

  • 初始化TIM2

将Timer2配置成编码器模式。需要配置2个引脚。所有引脚都配置成高速、复用开漏、上拉。

用到的是PA15和PB3,两者均复用为编码器接口。

TImer配置,不分频,自动重装,向上计数;编码器模式配置为递增和TI12,不设置滤波。最后定时器要开启更新中断,清除更新标志
位,最后使能TIM2。

  • 初始化TIM3

Timer3同样配置成为编码器模式。相关的两个引脚是PB4和PB5,其余配置均同上。

  • 初始化TIM4

同理,相关的引脚是PB6和PB7。

  • 初始化TIM5

同理,相关引脚是PA0和PA1。

  • 读取编码器

这个比较简单,只要读取CNT就可以了,同时每一次都可以直接CNT=0,清空寄存器,下一次就直接读取的是该时间间隔内编码器的计数值。

  • 中断服务函数

如果溢出了,直接清除中断标志位。

KEY配置

按键相关的配置内容。

  • KEY引脚配置

按键的配置引脚是PE0,配置为上拉输入即可。

  • 按键扫描

需要一个标志位记录是否按下,并结合当前的GPIO值,判断按键的按下与否。

还要判断是否为双击,需要再加上一个阈值,以此判断是否为双击。

LED配置

就是简单的GPIO输出配置,

对应引脚为PA12,配置为推挽输出,高速上拉模式。再配置一个蜂鸣器,PA8,配置参数相同。

需要在FreeRTOS专门开一个任务来管理LED的闪烁情况,来指示当前系统正常运行与否。

motor配置

这里是控制电机的PWM输出配置,同样是Timer相关的配置。

  • 使能引脚配置

配置的是PD3,输入模式,高速上拉。

  • 初始化TIM1

使用的都是TIM1,需要配置的是PE9、PE11PE13、PE14。全部需要配置定时器复用这四个引脚均配置为推挽输出复用,上拉;Timer的分频和自动重装在都是输入函数的参数,时钟分频为1,向上计数,完成定时器初始化;PWM模式配置为PWM1,输出使能,比较极性为高,四个通道均同样配置。最后使能TIM1输出。

  • TIM9配置

这里就配置PE5和PE6。配置的初始化内容上。对应的是输出通道1和2。

  • TIM10配置

这里只配置PB8,对应的是通道1。

  • TIM11配置

这里配置PB9,对应的是通道1。

OLED配置

这里就是通过OLED屏幕自己的一套时序来完成显示。

  • 初始化配置

对应的引脚是PD11、PD12、PD13、PD14。全部初始化为输出,无上下拉;同时为了使用后面的几个引脚,需要关闭外部低速时钟信号。

  • 读写函数

这个就根据IIC时序来模拟就好了。

  • 显示字符

需要先存储一个字符库,然后一个个调用之前的读写函数来写出来就可以了。

PS2配置

这里也是根据手柄自己的时序手册来完成信号的读取,需要开一个RTOS的任务来完成循环。

用到的引脚是PE15、PE8、PE10、PE12。PE15配置为输入下拉,剩下三个引脚都配置为推挽输出。主要用到的就是在Task中的read函数,会根据时序规定先清空然后读取一遍data存入开辟好的内存数组,通过这个数组的内容来获取是否有按键按下;关键的读取函数,就是根据时序来读取就可以了。

剩下的内容相当于对着PS2的操作手册,自己来编写时序的读写函数,完成信号的读取和发送。

IMU配置

使用的是通过IIC通讯的MPU传感器,用到的引脚是PB10和PB11,都配置为推挽输出,上拉。

之后通过软件来模拟IIC的读写时序,最后加上官网拉下来的MPU6050的文件,再适配一下就可以使用了。这里比较简单的就是直接找一个现成可以用的MPU6050的资料,省的自己搞,只要把他改成基于RTOS的任务就可以了。

串口配置

所有的控制命令的读写,都是在串口中来完成。

  • 总体架构

通过新建一个数据任务,在while循环中完成所有的串口以及CAN数据的发送。

  • 数据转换

将需要的数据,按照自定义的数据帧,完成数据封装。

需要发送的机器人本体运动数据,需要根据小车运动模型的不同来完成发送数据的封装;同时要读取IMU的数据和电池电源数据,最后封
装上帧头帧尾以及校验数据。将之前封装好的函数,调用串口的发送函数,将这些buffer一个个发送出去。

  • 数据发送
    CAN发送有所区别,一次只能发8个字节,所以通过0x101、0x102、0x103三个id号把24字节数据发送出去。

  • 串口1初始化
    对应的是PA9和PA18,初始化为复用推挽,上拉模式;需要开启串口的中断,抢占1子优先级0,使能irq;串口的配置波特率是函数输入参数,8位数据长度,一个停止位,无校验位,无硬件流控制,收发模式,然后使能串口中断再使能串口。

  • 串口2初始化

同理,对应的是PD5和PD6。抢占1子优先级0.

  • 串口3初始化

同理,对应的是PD8和PD9。优先级设置为2,0。

  • 串口5初始化

同理,对应的是PC12和PD2。优先级设置为2,0。

  • 串口中断函数

这个就根据不同的串口来完成对应的功能。串口1和串口3以及串口5是一样的,对应的是上位机通信。串口2是APP遥控。

  • 串口发送

直接调用简单的串口发送就可以。

  • 命令转换

通过接受的数据包,转换为实际想要的控制命令。

控制层

机器人选择

机器人运动学相关模型可以通过电位器来进行选择,所以需要进行配置。

配置的机器人选择函数,就是ADC读取电位器电压后,根据电压来设置机器人的选择控制变量。

具体的机器人初始化函数,就是通过机器人本体相关的一些结构参数,初始化设置好运动学模型相关的所需变量。

整体参数配置

机器人整体需要的参数如下:

  1. 小车运动模型选择参数,以及对应的ADC需要的选择变量
  2. 机器人的默认速度
  3. PID控制的相关参数
  4. 控制命令相关的平滑参数
  5. 控制电机相关的参数变量
  6. 相关控制命令下发方式的标志位
  7. 对应控制方法所需要的控制标记

在整体的控制函数初始化中,完成如下任务:

  1. 要完成对于底层初始化代码的调用:中断优先级分组配置(stm32底层配置)、LED初始化、蜂鸣器初始化、电机使能引脚初始化、OLED初始化、按键初始化、各个串口初始化(蓝牙初始为9600,其余波特率均115200)、ADC初始化、CAN初始化;
  2. 完成后进入机器人本体的选择,初始化电机编码器的定时器,初始化电机控制的PWM生成的定时器,初始化MPU所需的IIC通讯相关引脚,最后初始化PS2手柄的相关配置。

OLED显示

通过以上的状态变量,结合相关的电机控制状态,将内容显示在OLED屏幕上。

这里就是调用之前的OLED底层配置中已经完成的show函数,然后将需要的状态变量显示在屏幕。

滤波

针对IMU的原始数据,需要完成一定的滤波操作才能使用数据,不然对于当前的角度估计非常不准。

最好是采用卡尔曼滤波的方法,会更好的完成这个任务。

整体控制

这个就是整个机器人的状态机控制。

  • 运动学逆解

将上位机或遥控器下发的机器人移动命令,计算转换成电机旋转参数。

首先判断小车的运动模型,之后就直接进入电机的目标速度解算;解算完经过一定的限幅操作,最终存储到自定义的结构体中。

  • 电机控制函数

这里涉及的是设置PWM占空比参数,以及限幅函数。

  • PI控制

这里只有一个速度环,只有编码器的信息,没有电流环;就是一个简单的PI计算,不过需要写4个电机。

  • PS2手柄控制

通过对命令的解析,需要对手柄较小的遥控信号进行过滤;同时按照小车的运动学模型,将对应的命令转换为机器人移动的速度指令,然后通过调用之前的运动学逆解函数下发指令。

  • 按键功能

按下按键,可以更新IMU的零点。

  • 速度计算

通过读取编码器的数值,根据离散的时间间隔计算得到电机当前的旋转速度;然后根据小车的参数,计算当前的运动速度。

  • 关机

这里就是电池电压检测,如果欠压就会直接关闭PWM输出。

  • 总体控制

进入FreeRTOS控制的任务进程中,期间要完成计算机器人速度,获取运动指令(上位机或者遥控),电池电压正常则进入PI计算限幅后直接控制电机。

主函数

主函数中就是配置FreeRTOS的相关参数,然后创建一个start任务并开启RTOS的任务调度;

开始任务中,包含了之前的所有控制类的任务:控制层任务、IMU任务、显示任务、D任务、遥控任务以及下位机状态发送到上位任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/45683.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python | setup.py里有什么?

setup.py里有什么? 文章目录 setup.py里有什么?C/C扩展总结gcc/g的编译参数:Windows Visual StudioCmakesetup.py C/C扩展模块 为什么需要分发打包?Distutils一个简单的例子通用的 Python 术语 使用 Setuptools 构建和分发软件包源…

华为OD机试题-字符串重新排列

题目描述 https://www.cnblogs.com/smile-programmer/p/17322920.html 字符串重新排列 给定一个字符串s,s包括以空格分隔的若干个单词,请对s进行如下处理后输出: 1、单词内部调整:对每个单词字母重新按字典序排序 2、单词间顺序调…

C#单独摘出日期的某天

如果你想要在 C# 中获取日期中的“天”的部分,你可以通过将日期转换为字符串,解析字符串,或者使用 DateTime 结构的 Day 属性来实现。 using System;class Program {static void Main(){// 获取当前日期DateTime today DateTime.Today;// 使…

Sqlmap中文使用手册 - Request模块参数使用

目录 1. Request模块的帮助文档2. 各个参数的介绍2.1 --methodMETHOD2.2 --dataDATA2.3 指定参数分割符2.4 -cookie相关2.5 -agent相关2.6 --hostHOST2.7 --refererREFERER2.8 --headersHEADERS2.9 --auth-type / --auth-cred2.10 --auth-fileAUTH2.11 --ignore-codeIG2.12 --p…

基于Flask+Apache+WSGI等模块配置Deep Learning应用功能网站(Ubuntu 22.04服务器)

首先预设你已经在本地搭建好了网站,只需要放到服务器上,然后配置Apache / Nginx等反向代理软件,即可用服务器ip地址/域名进行访问。 因为操作不规范/坑太多,而反反复复配了至少10遍。接下来的教程主要是总结规范流程,…

PYTHON自学笔记(二)查漏补缺

迭代 字符串处理 函数 参数 必须参数(必须有序) 调用函数与生命函数的参数个数必须一样,否则报错 关键字参数(无需有序) 在调用函数的时候可以直接传参,方便测试 def printIfo(name, **var):print(…

Stable Diffusion 入门案例教程

Stable Diffusion 是一种基于 diffusion-based 的生成模型,可以生成高质量的图像和视频。下面是一个 Stable Diffusion 入门案例教程,旨在帮助您快速入门 Stable Diffusion。 安装 Stable Diffusion 首先,您需要安装 Stable Diffusion。可以…

Android Gantt View 安卓实现项目甘特图

需要做一个项目管理工具,其中使用到了甘特图。发现全网甘特图解决方案比较少,于是自动动手丰衣足食。 前面我用 Python和 Node.js 前端都做过,这次仅仅是移植到 Android上面。 其实甘特图非常简单,开发也不难,如果我…

Python番外篇:万法归一,一切皆对象

目录 Python中的对象 一切皆对象 数字是对象 字符串是对象 内置类型也是对象 函数和类也是对象 总结 Python中的对象 对象是Python对数据的抽象,在Python程序中,所有的数据,都可以由对象或对象之间的关系表示。 从某种意义上说&#…

基于AT89C51单片机GSM模块的家庭防火防盗报警系统设计(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于AT89C51单片机GSM模块的家庭防火防盗报警系统设计的详情介绍,如果对您有帮助的话,还请关注一下哦,如果有资源方面的需要可以联系我。 目录 摘 要 原理图 仿真图 元器件清单 代码 系统论文 参考文献 资源下载…

Memcached内存碎片清理术:优化缓存性能的策略

标题:Memcached内存碎片清理术:优化缓存性能的策略 内存碎片是Memcached在长期运行过程中常见的问题,它会降低缓存效率并影响性能。作为高效的分布式内存缓存系统,Memcached提供了多种内存碎片整理策略。本文将详细介绍这些策略&…

几何建模-Parasolid中GO功能使用

1.背景介绍 1.1 Parasolid和它的接口间关系 1.2 什么是GO GO全称是Graphical Output.你的程序需要在屏幕或者打印设备上显示模型数据时。在需要使用PK中的某个渲染函数时创建图形显示数据时,Parasolid会调用GO相关的函数。GO函数会输出绘图指令给你的应用程序提供…

《昇思25天学习打卡营第14天|SSD目标检测》

SSD(Single Shot MultiBox Detector)是一种用于目标检测的深度学习算法。它的设计旨在同时检测多个对象,并确定它们在图像中的位置和类别。与其他目标检测算法相比,SSD具有速度快和精度高的特点,在实时检测应用中非常受…

层次分析法:matlab代码实现

计算权重: 一、算术平均法 关于矩阵: 1、矩阵的输入写法 [ ; ; ]同行用空格或逗号隔开,不同行用分号间隔 2、矩阵求和 默认按列求和 asum(E) 等同于 asum(E,1) 得到行向量 按行求和 asum(E,2) 得到列向量 对整个矩阵求和 asum(E,"all&…

昇思25天学习打卡营第18天|MindNLP ChatGLM-6B StreamChat

现在各类chat AI不胜枚举,开源的闭源的都有,ChatGLM-6B是其中一个开源的chat AI模型,我们可以使用mindspore轻松的跑起来这个模型 官方提供的jupyter示例里面却少了安装mindnlp和mdtex2html,所以需要先把这两个模块安装一下。 !…

Python实战指南:一键解锁KimiGPT API,开启智能对话与文本生成的新纪元

Python实战指南:一键解锁KimiGPT API,开启智能对话与文本生成的新纪元 引言 随着人工智能技术的飞速发展,自然语言处理(NLP)成为了众多领域的核心技术之一。KimiGPT,作为国内广受欢迎的AI工具&#xff0c…

【/etc/profile、~/.bashrc、~/.bash_profile区别以及配置history记录】

目录 /etc/profile、~/.bashrc、~/.bash_profile区别/etc/profile~/.bash_profile~/.bashrc加载顺序和关系示例/etc/profile~/.bash_profile(用户级别)~/.bashrc(用户级别) history记录配置修改 /etc/profile确保用户的 ~/.bash_p…

TCP网络传输控制协议

目录 什么是TCP TCP的特点 TCP通信步骤 三次握手(建立连接) 数据传输 四次挥手(连接释放) 为什么要进行三次握手?两次握手行不行?一次握手行不行? 为什么是四次挥手?三次、两…

【Dison夏令营 Day 17】使用 Python Turtle 的 24 游戏求解器

24 点 是一个数学谜题,用基本算术运算符(、-、、)将 4 个数字运算成 24。例如,给定 4 个数字 1,5,5,5,我们可以得到表达式 (5-(15))5,等于 24。 我们可以用 Python 程序暴力解决这个问题。最多有 245444 7…

Vue的生命周期函数有哪些?详细说明

Vue.js 的生命周期函数包括以下几个阶段,每个阶段都有相应的钩子函数可以用来在特定时机执行自定义的逻辑。这些生命周期钩子函数使得我们可以在组件的不同阶段进行操作,从而管理组件的状态和行为。 1. beforeCreate: - 描述:…