两轮平衡小车制作保姆式教程(2-1)——软件模块:JY62

2024-01-27 10:36

本文主要是介绍两轮平衡小车制作保姆式教程(2-1)——软件模块:JY62,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

✅作者简介:大家好我是:麦克斯科技,希望一起努力,一起进步!

📃个人主页:麦克斯科技

🔥系列专栏:两轮平衡小车制作保姆式教程
🏷️非常欢迎大家在评论区留言交流,互相学习!

提前声明:博客中给出的代码经过多个项目测试,实测能用,性能稳定,请大家放心使用!

前言

本系列博客将从硬件到软件详细介绍“如何制作一辆两轮自平衡小车”,笔者毫无保留,以最通俗易懂的语言,以最简单的实现方案,分享自己从0到1制作平衡小车的全过程,相信跟着我的教程,大家也能顺利制作一台属于自己的平衡车。系列专栏:🔥两轮平衡小车制作保姆式教程🔥

首先,给大家提前交个底,其实制作一台平衡小车并不难,用到的主要模块就是陀螺仪,而最主要的控制算法就是PID算法,而且平衡小车对陀螺仪与PID算法的掌握程度要求并不是很高,所以适合初学者来作为项目练手。

该系列教程一共分为4个板块,分为《硬件选型》、《软件模块》、《直立环、速度环、转向环》、《调参保姆级教程》,4个板块条理清晰,层次分明,简明扼要,请大家跟着我开始学习吧!

软件模块

软件主要模块:陀螺仪、编码器、0.96寸OLED显示屏、电机、直立环、速度环、转向环等。

陀螺仪JY62

这里我用钱来解决了麻烦的问题,重金入手了一个性能较好的六轴陀螺仪jy62。只需要使用单片机的一个串口,这个模块对数据的处理已经做的很成功了。

我使用的主控是TM4C123,我也会给出使用STM32的代码,两个芯片是同一个处理思路,只是两个芯片的底层函数不一样。照着我的文件形式,建立imu.c与imu.h或者mt_jy62.c与mt_jy62.c,复制粘贴我的代码,根据实际情况修改,绝对能用,我在电赛和课设都是用的这个代码,实测真好用!

TM4C123的JY62底层程序

imu.c

//
// Created by 麦克斯科技.
//
#include "platform/platform.h"static uint8_t buffer[11];
imu_data_t acceleration, gyroscope, angle;// uart1
void imu_init()
{SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);GPIOPinConfigure(GPIO_PB0_U1RX);GPIOPinConfigure(GPIO_PB1_U1TX);GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0);GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_1);UARTConfigSetExpClk(UART1_BASE, SysCtlClockGet(), 115200, UART_CONFIG_WLEN_8|UART_CONFIG_STOP_ONE|UART_CONFIG_PAR_NONE);UARTFIFOEnable(UART1_BASE);UARTFIFOLevelSet(UART1_BASE, UART_FIFO_TX2_8, UART_FIFO_RX2_8);UARTIntEnable(UART1_BASE, UART_INT_RX|UART_INT_RT);void imu_handler(void);UARTIntRegister(UART1_BASE, imu_handler);IntPrioritySet(INT_UART1, USER_INT2);IntEnable(INT_UART1);IntMasterEnable();UARTEnable(UART1_BASE);
}static uint8_t get_verify_code()
{uint32_t sum = 0;for (uint8_t i = 0; i < 10; ++i) {sum += buffer[i];}return sum&0xff;
}int32_t k = 0;
void imu_analysis()
{static float last_angle_z = 0, angle_z = 0;switch (buffer[1]) {case 0x51:acceleration.x = (float )((int16_t)(buffer[2]|(buffer[3]<<8)))/32768*16;acceleration.y = (float )((int16_t)(buffer[4]|(buffer[5]<<8)))/32768*16;acceleration.z = (float )((int16_t)(buffer[6]|(buffer[7]<<8)))/32768*16;break;case 0x52:gyroscope.x = (float )((int16_t)(buffer[2]|(buffer[3]<<8)))/32768*2000;gyroscope.y = (float )((int16_t)(buffer[4]|(buffer[5]<<8)))/32768*2000;gyroscope.z = (float )((int16_t)(buffer[6]|(buffer[7]<<8)))/32768*2000;break;case 0x53:angle.x = (float )((int16_t)(buffer[2]|(buffer[3]<<8)))/32768*180;angle.y = (float )((int16_t)(buffer[4]|(buffer[5]<<8)))/32768*180;angle_z = (float )((int16_t)(buffer[6]|(buffer[7]<<8)))/32768*180;break;}if (last_angle_z < -90 && angle_z > 90)k --;if (last_angle_z > 90 && angle_z < -90)k ++;last_angle_z = angle_z;
//    printf("k:%ld\n", k);angle.z = angle_z + (float )k*360;
}#define ERROR   0
#define DOING   1
#define SUCCESS 2
static uint8_t n = 0, state = 0;
void imu_handler()
{uint32_t data;uint32_t status=UARTIntStatus(UART1_BASE, true);UARTIntClear(UART1_BASE, status);while(UARTCharsAvail(UART1_BASE)){data = UARTCharGetNonBlocking(UART1_BASE)&0xff;//	data = UARTCharGet(UART1_BASE)&0xff;//	UARTCharPutNonBlocking(UART0_BASE, data);//	printf("data:%d\n", data);if (state == ERROR){n = 0;}buffer[n] = (uint8_t)data;if (n == 0){if (buffer[0] == 0x55){state = DOING;} else{state = ERROR;}} else if (n == 10){if (buffer[10] == get_verify_code()){state = SUCCESS;} else{state = ERROR;}}n += 1;if (state == SUCCESS){
//			printf("OK\n");imu_analysis();state = ERROR;}}
}

imu.h

//
// Created by 麦克斯科技.
//
#ifndef IMU_H
#define IMU_Htypedef struct {float x;float y;float z;
}imu_data_t;void imu_init(void);
extern imu_data_t acceleration, gyroscope, angle;
#endif /* IMU_H */

STM32F103的JY62底层程序

mt_jy62.c

//
// Created by 麦克斯科技.
//
#include "mt_jy62.h"
#include <string.h>
#include <stdio.h>
#include "hal_usart.h"
#include "mt_pid.h"static int32_t n = 0 ;
int32_t state = 0;
static uint8_t buffer[11];
imu_data_t acceleration, gyroscope, angle; 
int32_t k = 0;
char analysis_flag = 0;
void imu_analysis(void)
{static float last_angle_z = 0, angle_z = 0;switch (buffer[1]) {case 0x51:acceleration.x = (float )((int16_t)(buffer[2]|(buffer[3]<<8)))/32768*16;acceleration.y = (float )((int16_t)(buffer[4]|(buffer[5]<<8)))/32768*16;acceleration.z = (float )((int16_t)(buffer[6]|(buffer[7]<<8)))/32768*16;break;case 0x52:gyroscope.x = (float )((int16_t)(buffer[2]|(buffer[3]<<8)))/32768*2000;gyroscope.y = (float )((int16_t)(buffer[4]|(buffer[5]<<8)))/32768*2000;gyroscope.z = (float )((int16_t)(buffer[6]|(buffer[7]<<8)))/32768*2000;break;case 0x53:angle.x = (float )((int16_t)(buffer[2]|(buffer[3]<<8)))/32768*180;angle.y = (float )((int16_t)(buffer[4]|(buffer[5]<<8)))/32768*180;angle_z = (float )((int16_t)(buffer[6]|(buffer[7]<<8)))/32768*180;break;}if (last_angle_z < -90 && angle_z > 90){//	k = -1;k--;}if (last_angle_z > 90 && angle_z < -90){ //	k = 1;k++;}last_angle_z = angle_z;angle.z = angle_z + k*360;}static uint8_t get_verify_code()
{uint32_t sum = 0;for (uint8_t i = 0; i < 10; ++i) {sum += buffer[i];}return sum&0xff;
}
void USART1_IRQHandler(void)                  //串口3中断服务程序
{uint32_t data;if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET){							data =  USART_ReceiveData(USART1)&0xff;if (state == ERROR){n = 0;}buffer[n] = (uint8_t)data;if (n == 0){if (buffer[0] == 0x55){state = DOING;} else{state = ERROR;}}else if (n == 10){if (buffer[10] == get_verify_code()){state = SUCCESS;} else{state = ERROR;}}
//		else
//		{
//			state = ERROR;
//		}n += 1;if (state == SUCCESS){imu_analysis();//analysis_flag = 1;state = ERROR;}else{analysis_flag = 0;}USART_ClearITPendingBit(USART1,USART_IT_RXNE);}	}

mt_jy62.h

//
// Created by 麦克斯科技.
//
#ifndef _MT_JY62_H
#define _MT_JY62_H#include "stm32f10x.h"
//**************************************************
typedef struct {int x;int y;int z;
}imu_data_t;#define ERROR   0
#define DOING   1
#define SUCCESS 2void imu_init(void);
void imu_analysis(void);
extern imu_data_t acceleration, gyroscope, angle;
//extern int32_t state;
extern char analysis_flag;#endif

代码分析

按函数分析

void imu_init(); //imu初始化

陀螺仪的初始化,初始化引脚,注册串口中断函数,打开中断。

void imu_init()
{SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);GPIOPinConfigure(GPIO_PB0_U1RX);GPIOPinConfigure(GPIO_PB1_U1TX);GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0);GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_1);UARTConfigSetExpClk(UART1_BASE, SysCtlClockGet(), 115200, UART_CONFIG_WLEN_8|UART_CONFIG_STOP_ONE|UART_CONFIG_PAR_NONE);UARTFIFOEnable(UART1_BASE);UARTFIFOLevelSet(UART1_BASE, UART_FIFO_TX2_8, UART_FIFO_RX2_8);UARTIntEnable(UART1_BASE, UART_INT_RX|UART_INT_RT);void imu_handler(void);UARTIntRegister(UART1_BASE, imu_handler);IntPrioritySet(INT_UART1, USER_INT2);IntEnable(INT_UART1);IntMasterEnable();UARTEnable(UART1_BASE);
}
static uint8_t get_verify_code();//数据校准

10个为一组,对串口获取到的 buffer[i]数据进行求和。

static uint8_t get_verify_code()
{uint32_t sum = 0;for (uint8_t i = 0; i < 10; ++i) {sum += buffer[i];}return sum&0xff;
}
void imu_analysis(); //数据分析

对陀螺仪获取到的数据进行处理,得到角速度和角度。

其中有一个对角度的巧妙处理,是的偏航角以z轴作为0度分界,解决陀螺仪自身得到角度的不连续性。

    if (last_angle_z < -90 && angle_z > 90)k --;if (last_angle_z > 90 && angle_z < -90)k ++;last_angle_z = angle_z;
//    printf("k:%ld\n", k);angle.z = angle_z + (float )k*360;
int32_t k = 0;
void imu_analysis()
{static float last_angle_z = 0, angle_z = 0;switch (buffer[1]) {case 0x51:acceleration.x = (float )((int16_t)(buffer[2]|(buffer[3]<<8)))/32768*16;acceleration.y = (float )((int16_t)(buffer[4]|(buffer[5]<<8)))/32768*16;acceleration.z = (float )((int16_t)(buffer[6]|(buffer[7]<<8)))/32768*16;break;case 0x52:gyroscope.x = (float )((int16_t)(buffer[2]|(buffer[3]<<8)))/32768*2000;gyroscope.y = (float )((int16_t)(buffer[4]|(buffer[5]<<8)))/32768*2000;gyroscope.z = (float )((int16_t)(buffer[6]|(buffer[7]<<8)))/32768*2000;break;case 0x53:angle.x = (float )((int16_t)(buffer[2]|(buffer[3]<<8)))/32768*180;angle.y = (float )((int16_t)(buffer[4]|(buffer[5]<<8)))/32768*180;angle_z = (float )((int16_t)(buffer[6]|(buffer[7]<<8)))/32768*180;break;}if (last_angle_z < -90 && angle_z > 90)k --;if (last_angle_z > 90 && angle_z < -90)k ++;last_angle_z = angle_z;
//    printf("k:%ld\n", k);angle.z = angle_z + (float )k*360;
}
void imu_handler(); //中断回调函数

处理中断工作。在这里面调用imu_analysis()函数。

#define ERROR   0
#define DOING   1
#define SUCCESS 2
static uint8_t n = 0, state = 0;
void imu_handler()
{uint32_t data;uint32_t status=UARTIntStatus(UART1_BASE, true);UARTIntClear(UART1_BASE, status);while(UARTCharsAvail(UART1_BASE)){data = UARTCharGetNonBlocking(UART1_BASE)&0xff;//	data = UARTCharGet(UART1_BASE)&0xff;//	UARTCharPutNonBlocking(UART0_BASE, data);//	printf("data:%d\n", data);if (state == ERROR){n = 0;}buffer[n] = (uint8_t)data;if (n == 0){if (buffer[0] == 0x55){state = DOING;} else{state = ERROR;}} else if (n == 10){if (buffer[10] == get_verify_code()){state = SUCCESS;} else{state = ERROR;}}n += 1;if (state == SUCCESS){
//			printf("OK\n");imu_analysis();state = ERROR;}}
}

这篇关于两轮平衡小车制作保姆式教程(2-1)——软件模块:JY62的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根

CnPlugin是PL/SQL Developer工具插件使用教程

《CnPlugin是PL/SQLDeveloper工具插件使用教程》:本文主要介绍CnPlugin是PL/SQLDeveloper工具插件使用教程,具有很好的参考价值,希望对大家有所帮助,如有错... 目录PL/SQL Developer工具插件使用安装拷贝文件配置总结PL/SQL Developer工具插

安装centos8设置基础软件仓库时出错的解决方案

《安装centos8设置基础软件仓库时出错的解决方案》:本文主要介绍安装centos8设置基础软件仓库时出错的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录安装Centos8设置基础软件仓库时出错版本 8版本 8.2.200android4版本 javas

Java中的登录技术保姆级详细教程

《Java中的登录技术保姆级详细教程》:本文主要介绍Java中登录技术保姆级详细教程的相关资料,在Java中我们可以使用各种技术和框架来实现这些功能,文中通过代码介绍的非常详细,需要的朋友可以参考... 目录1.登录思路2.登录标记1.会话技术2.会话跟踪1.Cookie技术2.Session技术3.令牌技

Python使用Code2flow将代码转化为流程图的操作教程

《Python使用Code2flow将代码转化为流程图的操作教程》Code2flow是一款开源工具,能够将代码自动转换为流程图,该工具对于代码审查、调试和理解大型代码库非常有用,在这篇博客中,我们将深... 目录引言1nVflRA、为什么选择 Code2flow?2、安装 Code2flow3、基本功能演示

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

Java Spring 中的监听器Listener详解与实战教程

《JavaSpring中的监听器Listener详解与实战教程》Spring提供了多种监听器机制,可以用于监听应用生命周期、会话生命周期和请求处理过程中的事件,:本文主要介绍JavaSprin... 目录一、监听器的作用1.1 应用生命周期管理1.2 会话管理1.3 请求处理监控二、创建监听器2.1 Ser

MySQL 安装配置超完整教程

《MySQL安装配置超完整教程》MySQL是一款广泛使用的开源关系型数据库管理系统(RDBMS),由瑞典MySQLAB公司开发,目前属于Oracle公司旗下产品,:本文主要介绍MySQL安装配置... 目录一、mysql 简介二、下载 MySQL三、安装 MySQL四、配置环境变量五、配置 MySQL5.1

MQTT SpringBoot整合实战教程

《MQTTSpringBoot整合实战教程》:本文主要介绍MQTTSpringBoot整合实战教程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录MQTT-SpringBoot创建简单 SpringBoot 项目导入必须依赖增加MQTT相关配置编写