4965 字
25 分钟
【电赛】02 - 2024H题自动行驶小车

注意:CCS Theia编译可能无法找到报错位置,建议每次小幅修改后就立即编译

主要问题:

  • 如何进行调参?

  • 如何设计一个完整的系统?

  • 小车如何走直线?

    • PID速度环
    • 陀螺仪
  • 小车在循迹时如何保证沿中线行驶?

  • 如何解决陀螺仪漂移的问题

    • 滤波算法
  • 如何避免/减少场地干扰?

  • 如何提高速度的同时保证行驶稳定?

程序结构-底层驱动#

一、基础电机控制#

源文件

#include "motor.h"
#include <iso646.h>
/**
* @brief 电机启动
* @param None
* @retval None
*/
void Motor_On(void)
{
DL_GPIO_setPins(GPIO_MOTOR_PIN_FSTBY_PORT, GPIO_MOTOR_PIN_FSTBY_PIN);//置位对应端口->引脚电平,STBY
}
/**
* @brief 电机关闭
* @param None
* @retval None
*/
void Motor_Off(void)
{
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FSTBY_PORT, GPIO_MOTOR_PIN_FSTBY_PIN);//清除对应端口->引脚电平,STBY
//逻辑口电平清除
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL1_PORT, GPIO_MOTOR_PIN_FL1_PIN);
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL2_PORT, GPIO_MOTOR_PIN_FL2_PIN);
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR1_PORT, GPIO_MOTOR_PIN_FR1_PIN);
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR2_PORT, GPIO_MOTOR_PIN_FR2_PIN);
}
/**
* @brief 速度设置
* @param 左右轮占空比(百分值)
* @retval None
*/
void Set_Speed(float duty1,float duty2)
{
uint32_t compareValue = 0;//比较值最大为3199,最小值为0
if(duty1 < 0)
{
//PWM定时器向下计数,比较值计算
compareValue = 3199 - 3199 * (-duty1/100.0);
//比较值设置
DL_TimerA_setCaptureCompareValue(PWM_MOTOR_INST, compareValue, DL_TIMER_CC_0_INDEX);
//电机逻辑引脚设置
DL_GPIO_setPins(GPIO_MOTOR_PIN_FL2_PORT, GPIO_MOTOR_PIN_FL2_PIN);
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL1_PORT, GPIO_MOTOR_PIN_FL1_PIN);
}
else if(duty1 > 0)
{
compareValue = 3199 - 3199 * (duty1/100.0);
DL_TimerA_setCaptureCompareValue(PWM_MOTOR_INST, compareValue, DL_TIMER_CC_0_INDEX);
DL_GPIO_setPins(GPIO_MOTOR_PIN_FL1_PORT, GPIO_MOTOR_PIN_FL1_PIN);
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL2_PORT, GPIO_MOTOR_PIN_FL2_PIN);
}
else
{
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL1_PORT, GPIO_MOTOR_PIN_FL1_PIN);
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL2_PORT, GPIO_MOTOR_PIN_FL2_PIN);
}
if(duty2 < 0)
{
compareValue = 3199 - 3199 * (-duty2/100.0);
DL_TimerA_setCaptureCompareValue(PWM_MOTOR_INST, compareValue, DL_TIMER_CC_1_INDEX);
DL_GPIO_setPins(GPIO_MOTOR_PIN_FR2_PORT, GPIO_MOTOR_PIN_FR2_PIN);
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR1_PORT, GPIO_MOTOR_PIN_FR1_PIN);
}
else if(duty2 > 0)
{
compareValue = 3199 - 3199 * (duty2/100.0);
DL_TimerA_setCaptureCompareValue(PWM_MOTOR_INST, compareValue, DL_TIMER_CC_1_INDEX);
DL_GPIO_setPins(GPIO_MOTOR_PIN_FR1_PORT, GPIO_MOTOR_PIN_FR1_PIN);
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR2_PORT, GPIO_MOTOR_PIN_FR2_PIN);
}
else
{
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR1_PORT, GPIO_MOTOR_PIN_FR1_PIN);
DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR2_PORT, GPIO_MOTOR_PIN_FR2_PIN);
}
}

头文件

#include "ti_msp_dl_config.h"
//宏定义简化写法
#define AIN1(x) x?DL_GPIO_setPins(GPIO_MOTOR_PIN_FL1_PORT, GPIO_MOTOR_PIN_FL1_PIN):DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL1_PORT, GPIO_MOTOR_PIN_FL1_PIN)
#define AIN2(x) x?DL_GPIO_setPins(GPIO_MOTOR_PIN_FL2_PORT, GPIO_MOTOR_PIN_FL2_PIN):DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL2_PORT, GPIO_MOTOR_PIN_FL2_PIN)
#define BIN1(x) x?DL_GPIO_setPins(GPIO_MOTOR_PIN_FR1_PORT, GPIO_MOTOR_PIN_FR1_PIN):DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR1_PORT, GPIO_MOTOR_PIN_FR1_PIN)
#define BIN2(x) x?DL_GPIO_setPins(GPIO_MOTOR_PIN_FR2_PORT, GPIO_MOTOR_PIN_FR2_PIN):DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR2_PORT, GPIO_MOTOR_PIN_FR2_PIN)
void Motor_On(void);
void Motor_Off(void);
void Set_Speed(float duty1,float duty2);

二、PID控制算法#

参数定义#

#include "PID.h"
#include "Serial.h"
#include "main.h"
#include "math.h"
#include "ti_msp_dl_config.h"
uint8_t Trace_Byte;//循迹总状态
uint8_t Angle_PID_Flag =0;//角度环开启标志位
uint8_t CV_flag=0;//视觉循迹开启标志位
uint8_t Test_pid_flag=0;//PID调试标志位
float K_trace = 0.0615;//减速系数
float Speed_midset = 30;//预设直线速度
/*灰度GPIO口宏定义*/
#define Read_Huidu_IO1 ((DL_GPIO_readPins(GPIO_TRACE_PIN_TRACE_0_PORT,GPIO_TRACE_PIN_TRACE_0_PIN)

结构体类型

创建结构体类型的方法,方便进行同类型变量元素组的创建,减少代码重复度。

这里定义了PID类型结构体,在之后新建其他用于PID控制的变量组时,只要用PID类型定义变量即可、

/*结构体类型定义*/
typedef struct
{
float Kp;
float Ki;
float Kd;
float error;
float last_error;
float error_sum;
float error_difference;
float velocity_sum;
}PID;

PID初始化相关函数

/*PID类型变量声明*/
PID Velocity;
PID Velocity_L;
PID trace_hd;
/*速度环PID*/
void Velocity_PID_Init()
{
Velocity.Kp = -1.33;
Velocity.Kd = -0.22;
Velocity.Ki = -0.012;
}
void Velocity_L_PID_Init()
{
Velocity_L.Kp = -1.34;
Velocity_L.Kd = -0.22;
Velocity_L.Ki = -0.012;
}
/*循迹环PID*/
void trace_hd_PID_Init()
{
trace_hd.Kp = -1.75;
trace_hd.Kd = -0.65;
trace_hd.Ki = 0;
}
/*PID初始化*/
void PID_Init()
{
Velocity_PID_Init();
Velocity_L_PID_Init();
trace_hd_PID_Init();
}
/*限幅函数*/
void I_amplitude_limiting(float number,float *Error_sum)
{
if(*Error_sum > number)
{
*Error_sum = number;
}
if(*Error_sum <- number)
{
*Error_sum = -number;
}
}

辅助函数

/*限幅函数*/
void I_amplitude_limiting(float number,float *Error_sum)
{
if(*Error_sum > number)
{
*Error_sum = number;
}
if(*Error_sum <- number)
{
*Error_sum = -number;
}
}
/**
* @brief 获取灰度巡线路数
* @param
* @retval 识别路数
*/
char Huidu_Counter()
{
uint8_t hd_sum = 0;
for(int i=0;i<7;i++)//灰度循迹个数统计
{
if(((~Trace_Byte)>>i)&0x01) hd_sum++;
}
return hd_sum;
}
/**
* @brief 灰度状态读取函数
* @param
* @retval
*/
void Get_TraceData()
{
Trace_Byte = (Read_Huidu_IO1<<7) + (Read_Huidu_IO2 << 6) + (Read_Huidu_IO3 << 5) + (Read_Huidu_IO4 <<4)
+ (Read_Huidu_IO5 << 3) +(Read_Huidu_IO6 <<2) +(Read_Huidu_IO7 <<1) + Read_Huidu_IO8;//8路灰度循迹状态
}

1.循迹控制(PD控制+自适应曲线减速)#

此函数包含:

  • 循迹路数统计:可用于判断小车是否脱线、循线、特征值检测
  • 适用于圆弧的循迹状态穷举
  • 自适应的曲线减速函数,提高循迹的稳定性
  • PD环控制,提高循迹的抗干扰能力与拟合程度
/*八路循迹环PID控制器*/
float Turn_hd_PID()
{
uint8_t temp_hd_sum = 0;
temp_hd_sum = Huidu_Counter();
if(temp_hd_sum <=2)//差速循迹
{
switch(Trace_Byte)
{
case 0xE7: // 1110 0111
case 0xC3: // 1100 0011
trace_hd.error = 0;
break;
case 0x00: // 0000 0000
case 0x0F: // 0000 1111
case 0x07: // 0000 0111
trace_hd.error = -9;
break;
case 0xF0: // 1111 0000
case 0xE0: // 1110 0000
trace_hd.error = 9;
break;
case 0xE3: // 1110 0011
case 0xF7: // 1111 0111
trace_hd.error = 2;
break;
case 0xC1: // 1100 0001
trace_hd.error = 1;
break;
case 0xF3: // 1111 0011
trace_hd.error = 4;
break;
case 0xF1: // 1111 0001
case 0xFB: // 1111 1011
trace_hd.error = 6;
break;
case 0xF9: // 1111 1001
case 0xFD: // 1111 1101
trace_hd.error = 8;
break;
case 0xF8: // 1111 1000
trace_hd.error = 10;
break;
case 0xFC: // 1111 1100
trace_hd.error = 12;
break;
case 0xFE: // 1111 1110
trace_hd.error = 14;
break;
case 0x87: // 1000 0111
trace_hd.error = -2;
break;
case 0xC7: // 1100 0111
trace_hd.error = -1;
break;
case 0xEF: // 1110 1111
trace_hd.error = -2;
break;
case 0xCF: // 1100 1111
trace_hd.error = -4;
break;
case 0x8F: // 1000 1111
case 0xDF: // 1101 1111
trace_hd.error = -6;
break;
case 0x9F: // 1001 1111
case 0xBF: // 1011 1111
trace_hd.error = -8;
break;
case 0x1F: // 0001 1111
trace_hd.error = -10;
break;
case 0x3F: // 0011 1111
trace_hd.error = -12;
break;
case 0x7F: // 0111 1111
trace_hd.error = -14;
break;
case 0xFF: // 1111 1111
trace_hd.error = trace_hd.last_error > 0 ? 16 : -16;
break;
default:
trace_hd.error = 0;
break;
}
}
else if(temp_hd_sum >= 6 && temp_hd_sum <= 8)//掉头
{
//Angle_PID_Flag = 1;
}
else//停车
{
}
trace_hd.error_difference = trace_hd.error - trace_hd.last_error;
trace_hd.error_sum += trace_hd.error;//误差累加量
trace_hd.last_error = trace_hd.error;
I_amplitude_limiting(1000,&trace_hd.error_sum);//误差累加量限幅
K_trace = 1/16.0 * pow((1-(20/Speed_midset)),0.5);//弯道减速系数
MID_Speed = Speed_midset * (1 - (uint8_t)(trace_hd.error)*K_trace) * (1 + (uint8_t)(trace_hd.error)*K_trace);//基准速度变换
return trace_hd.error*trace_hd.Kp + trace_hd.error_difference * trace_hd.Kd;//PD环循迹,比例+积分
}

2.陀螺仪角度环(小车姿态控制)#

此函数功能:

  • 输入陀螺仪传感器测量的姿态,进行PID解算
  • PD环控制,确保小车转向迅速并且稳定。
/*转向环PID控制器*/
float Turn_imu_PID(int yaw, int caclu_yaw)
{
float Kp = -1.35;
float Kd = -9.5;
float Ki = 0;
static float error ;
static float last_error;
static float error_diff;
static float error_sum;
error = yaw -caclu_yaw;
error_sum += error;
I_amplitude_limiting(1000,&error_sum);//误差累加量限幅
error_diff = error-last_error;
last_error = error;
if (error > 180) // 防止小车转到180度时一直旋转的问题
error = error - 360;
if (error < -180)
error = error + 360;
return Kp * error + Kd * error_diff + Ki*error_sum;
}

PID头文件

#include"ti_msp_dl_config.h"
extern uint8_t Trace_Byte;
extern uint8_t Angle_PID_Flag;
extern uint8_t Test_pid_flag;
extern float Speed_midset;//预设直线速度
float Turn_cv_PID(int measure, int caclu);
float Turn_hd_PID();
float Turn_hd_PID_Seven();
float Velocity_PID_L(float velocity,float velocity_calcu);
float Velocity_PID_R(float velocity,float velocity_calcu);
void PID_Init();
void Get_TraceData();
float Turn_imu_PID(int yaw, int caclu_yaw);
char Huidu_Counter();

三、陀螺仪串口通信#

#include "ti_msp_dl_config.h"
#include "Delay.h"
// 定义接收变量
uint8_t RollL, RollH, PitchL, PitchH, YawL, YawH, VL, VH, SUM;
float Pitch,Roll,Yaw;
// 串口接收状态标识
#define WAIT_HEADER1 0
#define WAIT_HEADER2 1
#define RECEIVE_DATA 2
uint8_t RxState_JY = WAIT_HEADER1;
uint8_t receivedData[9];
uint8_t dataIndex = 0;
//发送置偏航角置零命令
void Serial_JY61P_Zero_Yaw(void){
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XFF);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XAA);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X69);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X88);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XB5);
delay_ms(100);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XFF);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XAA);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X01);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X04);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X00);
delay_ms(100);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XFF);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XAA);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X00);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X00);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X00);
}

头文件

#ifndef __JY61P_H
#define __JY61P_H
void Serial_JY61P_Zero_Yaw(void);
void UART_JY61P_INST_IRQHandler(void);
extern float Pitch,Roll,Yaw;
#endif

四、常规外设串口通信#

1. 变量声明#

#include "stdio.h"
#include "string.h"
#include "ti_msp_dl_config.h"
#include "main.h"
#define BUFFER_SIZE 256 // 定义缓冲区大小
uint8_t Serial_RxPacket[100];
/*PID调试*/
float Test_Kp;//比例
float Test_Ki;//积分
float Test_Kd;//微分
float Test_Ks;//目标速度
/*系统调试串口变量*/
uint8_t Serial_RxFlag;
uint8_t RxState = 0;
uint8_t pRxState;//表示当前接收的是第几个变量
uint8_t RxData_type;
/*上位机串口变量*/
uint8_t Soc_RxFlag;
uint8_t RxState_SOC = 0;
uint8_t SOC_RxData_type;
uint8_t SOC_pRxState;//串口接收数据索引号
/*串口屏串口变量*/
uint8_t Screen_RxFlag;
uint8_t RxState_Screen;
uint8_t Screen_RxData_type;
uint8_t Screen_pRxState;//串口接收数据索引号
uint8_t Serial_RxPacket[100];

2. 辅助函数#

//系统串口初始化
void SYS_UART0_Init(void)
{
NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN);
NVIC_EnableIRQ(UART_0_INST_INT_IRQN);
DL_UART_clearInterruptStatus(UART_0_INST,DL_UART_INTERRUPT_RX);//清除中断标志位
}
//SOC通信串口初始化
void SOC_UART1_Init(void)
{
NVIC_ClearPendingIRQ(UART_SOC_INST_INT_IRQN);
NVIC_EnableIRQ(UART_SOC_INST_INT_IRQN);
DL_UART_clearInterruptStatus(UART_SOC_INST,DL_UART_INTERRUPT_RX);//清除中断标志位
}
//发送字符串给SOC
void SOC_SendString(char *str)
{
while(*str != '\0')
{
DL_UART_Main_transmitDataBlocking(UART_SOC_INST, *str++);
}
}
//串口屏通信串口初始化
void Screen_UART2_Init(void)
{
NVIC_ClearPendingIRQ(UART_Screen_INST_INT_IRQN);
NVIC_EnableIRQ(UART_Screen_INST_INT_IRQN);
DL_UART_clearInterruptStatus(UART_Screen_INST,DL_UART_INTERRUPT_RX);//清除中断标志位
}
//发送字符串给串口屏
void Screen_SendString(char *str)
{
while(*str != '\0')
{
DL_UART_Main_transmitDataBlocking(UART_Screen_INST, *str++);
}
}
void int_to_binary_string(uint32_t value, char *binary_str, int max_bits)
{
// 生成二进制字符串
for (int i = max_bits - 1; i >= 0; --i)
{
binary_str[i] = (value & (1U << i)) ? '1' : '0';
}
binary_str[max_bits] = '\0'; // 确保字符串以 null 结尾
}
// 将浮点数转换为字符串
void float_to_string(float value, char *str, size_t size)
{
snprintf(str, size, "%.2f", value); // 格式化为两位小数
}
void HMI_send_string(char *name, char *showdata)
{
char buffer[BUFFER_SIZE];
int length;
// 构造要发送的字符串,确保缓冲区足够大
length = snprintf(buffer, sizeof(buffer), "%s=\"%s\"\xff\xff\xff", name, showdata);
// 检查是否发生了缓冲区溢出
if (length >= sizeof(buffer))
{
// 缓冲区溢出处理,例如可以通过截断字符串或者增加缓冲区大小来解决
// 这里只是简单地截断字符串以确保不会发送超出缓冲区的内容
buffer[sizeof(buffer) - 1] = '\0'; // 确保字符串以 null 结尾
}
// 使用 Screen_SendString 发送构造好的字符串
Screen_SendString(buffer);
}
void HMI_send_number(char* name, int num)
{
char buffer[BUFFER_SIZE];
int length = snprintf(buffer, sizeof(buffer), "%s=%d\xff\xff\xff", name, num);
if (length >= BUFFER_SIZE)
{
// 缓冲区溢出处理
}
Screen_SendString(buffer);
}
void HMI_send_float(char* name, float num)
{
char buffer[BUFFER_SIZE];
int num_int = (int)(num * 100);
int length = snprintf(buffer, sizeof(buffer), "%s=%d\xff\xff\xff", name, num_int);
if (length >= BUFFER_SIZE)
{
// 缓冲区溢出处理
}
Screen_SendString(buffer);
}
void HMI_Wave(char* name, int ch, int val)
{
char buffer[BUFFER_SIZE];
int length = snprintf(buffer, sizeof(buffer), "add %s,%d,%d\xff\xff\xff", name, ch, val);
if (length >= BUFFER_SIZE)
{
// 缓冲区溢出处理
}
Screen_SendString(buffer);
}
void HMI_Wave_Fast(char* name, int ch, int count, int* show_data)
{
char buffer[BUFFER_SIZE];
int length = snprintf(buffer, sizeof(buffer), "addt %s,%d,%d\xff\xff\xff", name, ch, count);
if (length >= BUFFER_SIZE)
{
// 缓冲区溢出处理
}
Screen_SendString(buffer);
delay_ms(100);
for (int i = 0; i < count; i++)
{
// 发送每个字符
DL_UART_Main_transmitDataBlocking(UART_Screen_INST, (char)show_data[i]);
}
// 发送结束标志
Screen_SendString("\xff\xff\xff");
}
void HMI_Wave_Clear(char* name, int ch)
{
char buffer[BUFFER_SIZE];
int length = snprintf(buffer, sizeof(buffer), "cle %s,%d\xff\xff\xff", name, ch);
if (length >= BUFFER_SIZE)
{
// 缓冲区溢出处理
}
Screen_SendString(buffer);
}

程序结构-中断服务函数#

1.常规串口中断#

  • Uart0: 系统串口,用作与计算机通信调试
  • Uart_Screen:串口屏串口,用于和串口屏进行通信调试,串口屏可以直接控制小车,也可以显示小车实时参数
void UART_0_INST_IRQHandler(void)
{
switch (DL_UART_Main_getPendingInterrupt(UART_0_INST)) {//判断中断的类型,DL_UART_Main_getPendingInterrupt(UART_0_INST)调用具有清空标志位的功能?
case DL_UART_MAIN_IIDX_RX://如果触发串口接收事件
RxData = DL_UART_Main_receiveData(UART_0_INST);
if(RxState

2. 陀螺仪串口中断函数#

用于处理从陀螺仪传感器接收到的通信数据,其中主要的部分是Roll,Pitch,Yaw角

// 串口中断处理函数
void UART_JY61P_INST_IRQHandler(void) {
uint8_t uartdata = DL_UART_Main_receiveData(UART_JY61P_INST); // 接收一个uint8_t数据
switch (RxState_JY) {
case WAIT_HEADER1:
if (uartdata

程序结构-任务进程#

在此文件中,定义各种不同的任务

#include "Process.h"
/**************************串口进程*********************************/
/*系统串口(UART1)解码进程*/
void SYS_RxPro()
{
/*PID调试*/
if(Serial_RxFlag)
{
switch(RxData_type)//判断数据帧的数据类型
{
case 1:
if(pRxState

程序结构-路径规划#

1. 路径1#

/*******************************路线进程***********************************/
//要求1
void LX_Proc_1()
{
uint8_t temp_hd_sum;
static uint8_t LX_state = 0;
temp_hd_sum = Huidu_Counter();
if(LX_state ==0)
{
Speed_midset = 30 - NEncoder.right_motor_total_cnt/8000 * 15.0;
if(temp_hd_sum >=1)
{
beep_flag = 1;
LX_state = 1;
Motor_Off();
}
}
}

2. 路径2#

//要求2
void LX_Proc_2()
{
uint8_t temp_hd_sum;
static uint8_t LX_state = 0;
static uint32_t LuChen_Counter;
temp_hd_sum = Huidu_Counter();
//LuChen_Counter = (NEncoder.left_motor_total_cnt + NEncoder.right_motor_total_cnt)/2;
if(LX_state

3. 路径3#

//要求3
void LX_Proc_3()
{
uint8_t temp_hd_sum;
static uint8_t LX_state = 0;
static uint8_t i;
temp_hd_sum = Huidu_Counter();
if(LX_state

4. 路径4#

//要求4
void LX_Proc_4()
{
uint8_t temp_hd_sum;
static uint8_t LX_state = 0;
static uint8_t i;
temp_hd_sum = Huidu_Counter();
K_ZX = 1-(20/Speed_ZX);
if(LX_state

程序结构-主程序#

1. 参数声明#

#include "main.h"
#include "OLED.h"
#include "Serial.h"
#include "nqei.h"
#include "ti/driverlib/dl_gpio.h"
#include "ti_msp_dl_config.h"
#include <stdlib.h>
#include "Path.c"
uint32_t Key_Number;//按键调试
uint8_t Key_Val,Key_Down,Key_Up,Key_Old;
//PS:PWM可调范围,0~100以内任意浮点数
float MT_L = 20.0;//左轮速度初值
float MT_R = 20.0;//右轮速度初值
uint8_t RxData;//串口接收寄存器存储变量
uint8_t MID_Speed;//基准速度
float yaw_val;//记录Yaw角
float yaw_detect;//预测yaw角
static float Velocity_IL,Velocity_IR;//左右轮速度环PID输入
static float Dif_Out;//差速环PID输出
uint8_t Motor_flag;//电机使能标志位
float M_Speed_L;//左轮测速
float M_Speed_R;//右轮测速
uint32_t Timer_Angel_Sleep;
uint8_t Timer_Angel_Sleep_flag;
//外设列表:
//1.GPIO LED
//2.PWM 定时器G0,两路PWM
//3.定时器 定时器A0
//4.串口 USART0:调试串口
//5.按键
//6.OLED 硬件IIC
//7.MPU6050 硬件IIC
//8.串口屏
//9.陀螺仪串口
uint8_t beep_flag = 0;//声光提示标志位
uint8_t beep_key_flag;//按键提示音
uint8_t beep_timer = 0;//声光提示持续时间
uint8_t flag = 0;
char hmi_speed[]="n1.txt";//测速
char hmi_yaw[]="n2.txt";//测角度
char hmi_trace[]="n3.txt";//测循迹
char hmi_totol[]="n4.txt";//测里程
char hmi_imu[]="n5.txt";//测记忆角度
char data_HMI[]="";//串口屏数据存储空间
uint8_t Key_Timer;
uint32_t Timer_1ms_counter;
uint8_t System_Mode;
uint8_t WD_Protect_Flag;
uint8_t WD_Protect_time;
uint8_t WD_Protect_err;
float K_ZX = 0;
/*初始加速函数*/
void Speed_InitPro(uint8_t x)
{
uint8_t temp;
uint8_t i;
for(i=0;i<x;i++)
{
Set_Speed(i,i);
}
}

2. 主循环#

执行系统所需要的初始化部分,注意初始化的顺序。

用于显示的部分放在主循环中。

/*初始加速函数*/
void Speed_InitPro(uint8_t x)
{
uint8_t temp;
uint8_t i;
for(i=0;i<x;i++)
{
Set_Speed(i,i);
}
}
/*开启系统时钟中断,会导致串口工作异常或者程序卡死*/
int main(void)
{
SYSCFG_DL_init();//syscfg初始化
delay_ms(100);//等待初始化稳定
OLED_Init();//OLED初始化
OLED_ShowString(16,8,"OK",8);
delay_ms(100);//等待陀螺仪稳定
Motor_Off();//初始电机关闭,等待按键控制
SYS_UART0_Init();//串口0初始化
Screen_UART2_Init();//串口2初始化
BP_Encoder_Init();//编码器初始化
PID_Init();
delay_ms(1000);//等待初始化稳定
//Speed_InitPro(Speed_midset*0.8);
//编码器中断使能
delay_ms(50);//等待初始化稳定
TIMER_1_Init();//定时器1初始化
TIMER_2_Init();
NVIC_EnableIRQ(UART_JY61P_INST_INT_IRQN);
while (1)
{
Oled_Proc();
HMI_Proc();
}
}

维特陀螺仪#

一、通信协议#

1.1 读格式#

代码实现(仅读取角度):

// 定义接收变量
uint8_t RollL, RollH, PitchL, PitchH, YawL, YawH, VL, VH, SUM;
float Pitch,Roll,Yaw;
// 串口接收状态标识
#define WAIT_HEADER1 0
#define WAIT_HEADER2 1
#define RECEIVE_DATA 2
uint8_t RxState_JY = WAIT_HEADER1;
uint8_t receivedData[9];//接收数据储存数组
uint8_t dataIndex = 0;
// 串口中断处理函数
void UART_JY61P_INST_IRQHandler(void) {
uint8_t uartdata = DL_UART_Main_receiveData(UART_JY61P_INST); // 接收一个uint8_t数据
switch (RxState_JY) {
case WAIT_HEADER1:
if (uartdata

1.2 写格式#

代码实现(Z轴置零):

//发送置偏航角置零命令
void Serial_JY61P_Zero_Yaw(void){
/*解锁指令*/
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XFF);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XAA);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X69);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X88);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XB5);
delay_ms(200);//延迟200ms
/*修改指令(Z轴置零)*/
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XFF);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XAA);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X01);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X04);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X00);
delay_ms(3000);//延迟3秒
/*保存指令*/
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XFF);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0XAA);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X00);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X00);
DL_UART_Main_transmitDataBlocking(UART_JY61P_INST,0X00);
}
【电赛】02 - 2024H题自动行驶小车
http://www.turinblog.cn/posts/电赛02---2024h题自动行驶小车/
作者
Szturin
发布于
2024-09-15
许可协议
CC BY-NC-SA 4.0