> 技术文档 > 2024年电赛H题解析_电赛循迹带mcu

2024年电赛H题解析_电赛循迹带mcu


一、硬件选择

这里不是打广告

(一)电机驱动

TB6612双路驱动模块带稳压版接口

(二)红外循迹

幻尔机器人4路循迹传感器(GPIO通信)

(三)小车车模以及电机

R1系列三轮小车+带铰链高度角度可调相机支架+mg310电机两个

(四)陶晶驰串口屏4.3英寸

(五)角度传感器

MPU6050模块 串口6轴加速度计电子陀螺仪JY61

(六)MCU

嘉立创MSPM0G3507(咸鱼买二手)

二、硬件链接

(一)电机驱动

1.电机驱动

MCU的PA14连电机驱动的AIN1,PA13连电机驱动的AIN2,PA15连电机驱动的BIN1,PA16连电机驱动的BIN2。TB6612上的STAY直接置3.3v高电平。

MCU的PA21是左轮电机的pwm引脚连到TB6612的PWMA,PA22是右轮电机的pwm引脚连到TB6612的PWMB。

电机A是小车左边的电机,电机B是小车右边的电机

2.霍尔编码器

MCU的PB18连电机驱动的E1A,MCU的PB19连电机驱动的E1B。

3.红外循迹

红外循迹模块左2(最左边的红外管)连MCU的PA2,左1(中间靠左)连PA7,右1(中间靠右)连PA8,右2(最右边的红外管)连PA9。

4.蜂鸣器

蜂鸣器的IO口连接MCU的PB7。

5.串口

MCU的PA1连接到MPU6050的TX,PA0连接到MPU6050的RX(串口0,波特率:115200bps,注意:此串口协议为:RS485,不是常规的RS232)

MCU的PA18连接到串口屏的TX,PA17连接到串口屏的RX(串口1,波特率:115200bps)

6.其他

除此之外,还要把MCU的主频提高到80MHz,定时器每隔50ms中断,外部中断

三、软件代码编写思路

题目切换思路

  • 如果接受的串口1的数据为 \'1\' ,则进入题目1程序

  • 如果接受的串口1的数据为 \'0\' ,则继续发送有关题目1程序的小车参数,但让小车停止

  • 如果接受的串口1的数据为 \'2\' 并且已完成mpu6050角度初始化,则进入题目2程序,这里的角度初始化完成状态为 ‘N’

  • 如果接受的串口1的数据为 \'3\' ,则继续发送有关题目2程序的小车参数,但让小车停止

  • 如果接受的串口1的数据为 \'4\' 并且已完成mpu6050角度初始化,则进入题目3程序 这里的角度初始化完成状态为 ‘C’

  • 如果接受的串口1的数据为 \'5\' ,则继续发送有关题目3程序的小车参数,但让小车停止

  • 如果接受的串口1的数据为 \'6\', 小车行驶的圈数小于4圈,并且已完成mpu6050角度初始化,则进入题目3程序 这里的角度初始化完成状态为 ‘D’

  • 如果接受的串口1的数据为 \'7\' 或小车行驶的圈数大于等于4圈,则继续发送有关题目4程序的小车参数,但让小车停止

题目切换状态机图

题目一

题目一的思路很简单,就是使小车按0度行驶,当小车检测到有黑线时,则认为到达B点,题目1完成

void qustion1(void) {    if(IT.Infraed_Tracking_State == 11 && car_state == \'A\')//小车红外循迹为全白    {        PID_Control(18, 3 , 7 , Value[2] , 0 , yaw_old ,&PID_left.pwm,car_state);        PID_Control(18, 3 , 7 , 0 , Value[2] , yaw_old ,&PID_right.pwm,car_state);    }    else if(IT.Infraed_Tracking_State != 11) //小车红外循迹不为全白    {        car_state = \'B\';        PID_left.pwm = PID_right.pwm = 0;    }    if(car_state == \'B\')    {            if(Buzzer_count <=20)//蜂鸣器工作1s            {                Buzzer_count++;                DL_GPIO_setPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN);            }            else {                DL_GPIO_clearPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN);            }    }    DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);    DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); }

题目二

题目二,先让小车按0度行驶,检测到黑线就正常循迹。当小车状态为‘B’时,红外循迹模块检测为全白,判断偏航角是否大于170度或小于-170度,是的话,小车状态为‘C’,小车按+-180度行驶。当小车状态为‘C’时,红外循迹模块检测到黑线,则认为小车到达D点,再正常循迹。当小车状态为‘D’时,红外循迹模块检测为全白,判断偏航角是否处于[-10,10]区间,如是,则认为到达A点,题目二完成

void question2(void){ if(IT.Infraed_Tracking_State == 11 && car_state == \'A\')//红外循迹为全白 { PID_Control(15, 1 , 5 , Value[2] , 0 , yaw_old ,&PID_left.pwm,car_state); PID_Control(15, 1 , 5 , 0 , Value[2] , yaw_old ,&PID_right.pwm,car_state); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); yaw_old=Value[2]; } else if(IT.Infraed_Tracking_State !=11 && car_state == \'A\')//红外循迹不为全白 { car_state = \'B\'; Buzzer_count = 0; yaw_old=0; PID_left.pwm = PID_right.pwm=0; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); } else if(car_state == \'B\')//小车进入红外循迹 { Judge_pwm_duty_difference(IT.Infraed_Tracking_State,&pwm_duty_difference); PID_left.pwm = 520 + (pwm_duty_difference * 40); PID_right.pwm = 520 - (pwm_duty_difference * 40); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm , DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm , DL_TIMER_CC_1_INDEX); if(Buzzer_count <=20) { Buzzer_count++; DL_GPIO_setPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } else { DL_GPIO_clearPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } if(IT.Infraed_Tracking_State == 11 && car_state == \'B\' && (Value[2] = 170))//如果红外循迹为全白,小车偏航角大于170度小于-170,则认为小车进入C点 { car_state = \'C\'; Buzzer_count = 0; pwm_duty_difference = 0; PID_left.pwm = PID_right.pwm=0; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); } } else if(car_state == \'C\') { if(Buzzer_count <=25) { Buzzer_count++; DL_GPIO_setPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } else { DL_GPIO_clearPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } if(Value[2] = 0) { PID_Yaw = -180 + Value[2]; } PID_Control(15, 2 , 0 , PID_Yaw , 0 , 0,&PID_left.pwm,car_state); PID_Control(15, 2 , 0 , 0 , PID_Yaw , 0 ,&PID_right.pwm,car_state); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm , DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm , DL_TIMER_CC_1_INDEX); yaw_old=PID_Yaw; if(IT.Infraed_Tracking_State !=11 && car_state == \'C\')//红外循迹不为全白 ,则小车到达D点 { car_state = \'D\'; Buzzer_count = 0; yaw_old=0; PID_left.pwm = PID_right.pwm=0; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); } } else if(car_state == \'D\') { if(Buzzer_count = -15 && Value[2] <= 15))//红外循迹为全白,小车偏航角为[-15,15],小车进入\'E\'状态 { car_state = \'E\'; Buzzer_count = 0; pwm_duty_difference = 0; PID_left.pwm = PID_right.pwm = 0; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm , DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm , DL_TIMER_CC_1_INDEX); } } else if(car_state == \'E\') { if(Buzzer_count <=25) { Buzzer_count++; DL_GPIO_setPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } else { DL_GPIO_clearPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } }}

题目三

小车在A点,原地向右转,当偏航角为[-30,-40]时,小车进入 ‘a’状态。

  • 小车为 ‘a’状态,向-37度行驶,当小车循迹状态不为全白时,小车进入C点。

  • 小车进入C点,开始红外循迹 , 当循迹状态为全白并且(偏航角大于170度或小于-170度) ,小车到达B点。

  • 小车进入B点,原地向左转,当偏航角为[-130,-150]时,小车进入\'b\'状态。

  • 小车进入\'b\'状态,当红外循迹状态不为全白,小车进入\'D\'点。

  • 小车进入\'D\'点,当红外循迹状态为全白并且偏航角为[-10,10],小车状态为 \'E\',题目三完成。

  • 题目三状态机图

 
void question3(void){ if(car_state == \'A\')//小车在A点,原地向右转,当偏航角为[-30,-40]时,小车进入 ‘a’状态 { DL_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN2_PIN); DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN1_PIN); PID_left.pwm = 450; PID_right.pwm = 400; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); if(Value[2] >= -40.0f && Value[2] <= -30.0f) { car_state = \'a\'; PID_left.pwm = PID_right.pwm = 0; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); DL_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN1_PIN); DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN2_PIN); } } else if(car_state == \'a\')//小车为 ‘a’状态,向-37度行驶,当小车循迹状态不为全白时,小车进入C点 { PID_Yaw = 37 + Value[2];  PID_Control(18, 3 , 2 , PID_Yaw , 0 , 0,&PID_left.pwm,car_state); PID_Control(18, 3 , 2 , 0 , PID_Yaw , 0 ,&PID_right.pwm,car_state); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm , DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm , DL_TIMER_CC_1_INDEX); yaw_old = PID_Yaw; if(IT.Infraed_Tracking_State != 11) { car_state = \'C\'; Buzzer_count = 0; yaw_old =0; PID_left.pwm = PID_right.pwm = 0; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); } } else if(car_state == \'C\')//小车进入C点 开始红外循迹 , 当循迹状态为全白并且(偏航角大于170度或小于-170度) ,小车到达B点 { if(Buzzer_count <=10) { Buzzer_count++; DL_GPIO_setPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } else { DL_GPIO_clearPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } Judge_pwm_duty_difference(IT.Infraed_Tracking_State,&pwm_duty_difference); PID_left.pwm = 520 + (pwm_duty_difference * 40); PID_right.pwm = 520 - (pwm_duty_difference * 40); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm , DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm , DL_TIMER_CC_1_INDEX); if(IT.Infraed_Tracking_State == 11 && (Value[2] = 170)) { car_state = \'B\'; Buzzer_count = 0; pwm_duty_difference = 0; PID_left.pwm = PID_right.pwm=0; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); } } else if(car_state == \'B\')//小车进入B点 原地向左转 , 当偏航角为[-130,-150]时,小车进入\'b\'状态 { if(Buzzer_count = -150.0f && Value[2] <= -130.0f) { car_state = \'b\'; PID_left.pwm = PID_right.pwm = 0; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); DL_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E1_AIN1_PIN); DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E1_AIN2_PIN); } } else if(car_state == \'b\')//小车进入\'b\'状态,当红外循迹状态不为全白,小车进入\'D\'点 { PID_Yaw = 144 + Value[2];  PID_Control(18, 3 , 2 , PID_Yaw , 0 , 0,&PID_left.pwm,car_state); PID_Control(18, 3 , 2 , 0 , PID_Yaw , 0 ,&PID_right.pwm,car_state); yaw_old = PID_Yaw; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm , DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm , DL_TIMER_CC_1_INDEX); if(IT.Infraed_Tracking_State != 11) { car_state = \'D\'; Buzzer_count = 0; yaw_old = 0; PID_left.pwm = PID_right.pwm = 0; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); } } else if(car_state == \'D\')//小车进入\'D\'点 ,当红外循迹状态为全白并且偏航角为[-10,10],小车状态为 \'E\' { if(Buzzer_count <=10) { Buzzer_count++; DL_GPIO_setPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } else { DL_GPIO_clearPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } Judge_pwm_duty_difference(IT.Infraed_Tracking_State,&pwm_duty_difference); PID_left.pwm = 520 + (pwm_duty_difference * 40); PID_right.pwm = 520 - (pwm_duty_difference * 40); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm , DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm , DL_TIMER_CC_1_INDEX); if(IT.Infraed_Tracking_State == 11 && Value[2] = -10) { car_state = \'E\'; Buzzer_count = 0; pwm_duty_difference = 0; PID_left.pwm = PID_right.pwm=0; DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX); DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); } } else if(car_state == \'E\')//蜂鸣器工作 { if(Buzzer_count <=10) { Buzzer_count++; DL_GPIO_setPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } else { DL_GPIO_clearPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN); } }}

题目四

若小车在状态‘E’到C点偏右,就加上Value_yaw_old1,若偏左,则减去Value_yaw_old1。

 
/*因为mpu6050有累积误差,在小车在每次一圈结束时记录最后的偏航角,让新的偏航角减去这个乘个系数的最后的偏航角 一般最后一题在这调参*/    Value[2] = Value[2] + Value_yaw_old1 * 0.12f;

小车状态为 ‘A’ ,让原地向右转。如果小车偏航角为[-70,-80],则小车进入‘a’状态 。

小车状态为 ‘a’ ,向-75度行驶。小车左轮的竖直位移的计数值大于1170,进入到 \'E\'状态。在此状态下,进行对小车的左轮编码器计数求竖直方向的位移

因为减小角度误差对竖直位移计算的影响,小车要按-75度行驶,竖直位移计算公式为 :

左轮总竖直位移 = 左轮上一时刻的总竖直位移 + (左轮位移 - 上一刻左轮位移) * cos(偏航角)

cos(X)在+-90度附近的导数(-sin(X))较小,能减小角度误差对竖直位移计算的影响,故小车向-75度行驶。

 if(car_state == \'a\')//小车状态为 ‘a’ ,向-75度行驶 {        PID_Yaw = 75 + Value[2]; ​        //进行小车竖直位移的测量        E1.Left_Wheel_Vertical_displacement_Value = E1.Left_Wheel_Vertical_displacement_Value + (E1.Left_Wheel_Value - E1.Left_Wheel_Value_old) * cos(Value_yaw_old) ;               PID_Control(20, 3 , 2 , PID_Yaw , 0 , 0,&PID_left.pwm,car_state);        PID_Control(20, 3 , 2 , 0 , PID_Yaw , 0 ,&PID_right.pwm,car_state); ​        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm , DL_TIMER_CC_0_INDEX);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm , DL_TIMER_CC_1_INDEX);        yaw_old = PID_Yaw;        Value_yaw_old = (-90 - Value[2] ) * (M_PI / 180.00f);//小车上一刻的偏航角                 E1.Left_Wheel_Value_old = E1.Left_Wheel_Value;//小车上一刻的左轮计数值  }

小车进入到‘E’状态 进行转向,如果偏航角为(-3,3) ,小车进入‘F’状态。

小车进入到‘F’状态 向0度行驶,如果小车循迹状态不为全白,则小车到C点。

小车进入到‘C’状态,进行黑线循迹。如果小车循迹状态为全白并且(偏航角大于172 或小于-172),则认为小车到了B点。

小车进入到‘B’点,原地向左转,如果小车偏航角为[-100,-110],则小车为‘b’状态。

小车进入到‘b’状态,向-105度行驶,如果小车左轮竖直方向计数值大于1170,则小车进入到‘G’状态。向-105度行驶的原因与状态‘a’的小车向-75度行驶的原因相同,故不做解释。

小车进入到‘G’状态 原地向右转向,如果小车偏航角大于-175度或小于175度,则进入到H状态。

小车进入到‘H’状态 向+-180度行驶,如果小车循迹状态不为全白,则进入到D点。

小车进入到‘D’状态 进行红外循迹,如果小车循迹状态为全白并且偏航角为[-10,10],小车进入到‘I’状态。

小车进入到‘I’状态 等蜂鸣器工作0.5s之后,再跳转到‘A’状态,小车行驶圈数自加1。若小车行驶圈数大于等于4圈(初始圈数为0),则题目4完成

题目四状态机图

 
void question4(void) {    /*因为mpu6050有累积误差,在小车在每次一圈结束时记录最后的偏航角,让新的偏航角减去这个乘个系数的最后的偏航角 一般最后一题在这调参*/    Value[2] = Value[2] + Value_yaw_old1 * 0.12f; ​    if(car_state == \'A\')//小车状态为 ‘A’ ,让原地向右转    {        DL_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN2_PIN);        DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN1_PIN); ​        PID_left.pwm = 550;        PID_right.pwm = 450;        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX); ​        if(Value[2] >= -80.0f && Value[2]  1170 ) //小车左轮的竖直位移的计数值大于1170,进入到 \'E\'状态        {            Buzzer_count = 0;            yaw_old =0;            PID_left.pwm = 0;            PID_right.pwm = 0;            E1.Left_Wheel_Vertical_displacement_Value =0; E1.Left_Wheel_Value_old = 0;            E1.Left_Wheel_Value = 0;            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);            DL_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E1_AIN2_PIN);            DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E1_AIN1_PIN);            car_state = \'E\';        }             }    else if(car_state == \'C\')//小车进入到‘C’状态 进行黑线循迹    {        if(Buzzer_count <=10)        {            Buzzer_count++;            DL_GPIO_setPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN);        }        else {            DL_GPIO_clearPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN);        } ​        Judge_pwm_duty_difference(IT.Infraed_Tracking_State,&pwm_duty_difference);//根据小车循迹状态 给出小车的左右轮pwm差值        PID_left.pwm = 470 + (pwm_duty_difference * 40);        PID_right.pwm = 470 - (pwm_duty_difference * 40);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm , DL_TIMER_CC_0_INDEX);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm , DL_TIMER_CC_1_INDEX);                 if(IT.Infraed_Tracking_State == 11 && (Value[2] = 172))//如果小车循迹状态为全白并且(偏航角大于172 或小于-172),则认为小车到了B点        {            car_state = \'B\';            Buzzer_count = 0;            pwm_duty_difference = 0;            PID_left.pwm = PID_right.pwm=0;            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);        }    }    else if(car_state == \'E\') //小车进入到‘E’状态 进行转向,如果偏航角为(-3,3) ,小车进入‘F’状态    {        PID_left.pwm = 550;        PID_right.pwm = 450;        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);        if(Value[2] > -3 && Value[2] < 3)        {            car_state = \'F\';            PID_left.pwm = 0;            PID_right.pwm = 0;            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);            DL_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E1_AIN1_PIN);            DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E1_AIN2_PIN);                     }            }    else if(car_state == \'F\')//小车进入到‘F’状态 向0度行驶,如果小车循迹状态不为全白,则小车到C点    {        PID_Control(20, 1 , 8 , Value[2] , 0 , yaw_old ,&PID_left.pwm,car_state);        PID_Control(20, 1 , 8 , 0 , Value[2] , yaw_old ,&PID_right.pwm,car_state);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);        yaw_old = Value[2]; ​        if(IT.Infraed_Tracking_State != 11)        {            car_state = \'C\';            yaw_old =0;            PID_left.pwm = PID_right.pwm = 0;            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);        }             }         else if(car_state == \'B\')//小车进入到‘B’点 原地向左转,如果小车偏航角为[-100,-110],则小车为‘b’状态    {        if(Buzzer_count = -110.0f && Value[2]  1170 )        {            Buzzer_count = 0;            yaw_old =0;            PID_left.pwm = 0;            PID_right.pwm = 0;            E1.Left_Wheel_Vertical_displacement_Value = 0;E1.Left_Wheel_Value_old = 0;             E1.Left_Wheel_Value =0;            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);            DL_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN2_PIN);            DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN1_PIN);            car_state = \'G\';        } ​             }    else if(car_state == \'G\')//小车进入到‘G’状态 原地向右转向,如果小车偏航角大于-175度或小于175度,则进入到H状态    {        PID_left.pwm = 550;        PID_right.pwm = 450;        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);        if(Value[2]  175)        {            car_state = \'H\';            PID_left.pwm = 0;            PID_right.pwm = 0;            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);            DL_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN1_PIN);            DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN2_PIN);                     }    }    else if(car_state == \'H\')//小车进入到‘H’状态 向+-180度行驶,如果小车循迹状态不为全白,则进入到D点    {        if(Value[2] = 0)        {            PID_Yaw = -180 + Value[2];          }        PID_Control(20, 3 , 8 , PID_Yaw , 0 , 0,&PID_left.pwm,car_state);        PID_Control(20, 3 , 8 , 0 , PID_Yaw , 0 ,&PID_right.pwm,car_state); ​        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);        yaw_old=PID_Yaw; ​        if(IT.Infraed_Tracking_State != 11)        {            car_state = \'D\';            yaw_old =0;            DL_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN1_PIN);            DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E2_AIN2_PIN);            PID_left.pwm = PID_right.pwm = 0;            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);        }    }    else if(car_state == \'D\')//小车进入到‘D’状态 进行红外循迹,如果小车循迹状态为全白并且偏航角为[-10,10],小车进入到‘I’状态    {        if(Buzzer_count <=10)        {            Buzzer_count++;            DL_GPIO_setPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN);        }        else {            DL_GPIO_clearPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN);        } ​        Judge_pwm_duty_difference(IT.Infraed_Tracking_State,&pwm_duty_difference);        PID_left.pwm = 470 + (pwm_duty_difference * 40);        PID_right.pwm = 470 - (pwm_duty_difference * 40);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm , DL_TIMER_CC_0_INDEX);        DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm , DL_TIMER_CC_1_INDEX);                 if(IT.Infraed_Tracking_State == 11 && Value[2]   = -10 )        {            car_state = \'I\';            Buzzer_count = 0;            pwm_duty_difference = 0;            PID_left.pwm = PID_right.pwm=0;            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_left.pwm, DL_TIMER_CC_0_INDEX);            DL_TimerG_setCaptureCompareValue(PWM_0_INST, PID_right.pwm, DL_TIMER_CC_1_INDEX);        }    }    else if(car_state == \'I\')//小车进入到‘I’状态 等蜂鸣器工作之后 再跳转到‘A’状态,小车行驶圈数自加1    {        Value_yaw_old1 = Value[2];        if(Buzzer_count <=10)        {            Buzzer_count++;            DL_GPIO_setPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN);        }        else {            DL_GPIO_clearPins(GPIO_Buzzer_PORT,GPIO_Buzzer_PIN_0_PIN);                         car_state = \'A\';            laps_number++;        }    }    }

四、代码文件

通过百度网盘分享的文件:empty_LP…
链接:https://pan.baidu.com/s/1N5vi2J0HFzZ_0mV7JbqbyQ?pwd=98zd 
提取码:98zd
复制这段内容打开「百度网盘APP 即可获取

五、总结

填补在电赛的遗憾,就重做24年电赛题, 从2024年十月初到10月30日,耗时一个月完成(挤出课余时间,其实不是每天都写代码),除了MPU6050串口接收的部分代码是商家资料提供,其他均是本人所写。由于本人才疏学浅,代码和解析的不足挺多的,比如多余的变量,中断服务函数代码过多,状态机图有些状态转换没画出以及部分文字口语化等。作者已经大三了,留给我的大学生活时间已经不多,接下来我要学FPGA(因为我是集成专业的)和一些未来的打算。在此,特别鸣谢帮助我的同学和老师(特别鸣谢高老师)。最后希望读者都有充实的大学生活。与君共勉。

作者于2024年10月31日编写完成