2024年电赛H题解析

一、硬件选择

这里不是打广告

(一)电机驱动

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 || 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  = Value[2] + 180;
        }
        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 <=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);
        }
        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 && car_state == 'D' && (Value[2] >= -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 || 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 <=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);
        }

        DL_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E1_AIN2_PIN);
        DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E1_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] >= -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 && 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] <= -70.0f)//如果小车偏航角为[-70,-80],则小车进入‘a’状态 
         {
             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’ ,向-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;//小车上一刻的左轮计数值
 ​
         if(E1.Left_Wheel_Vertical_displacement_Value> 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 || 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 <=5)
         {
             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_GPIO_setPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E1_AIN2_PIN);
         DL_GPIO_clearPins(GPIO_Motor_PORT,GPIO_Motor_PIN_E1_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] >= -110.0f  && Value[2] <= -100.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’点 向-105度行驶,如果小车左轮竖直方向计数值大于1170,则小车进入到‘G’状态
     {
         PID_Yaw = 105 + Value[2] ;  
         //进行小车竖直位移的测量
         E1.Left_Wheel_Vertical_displacement_Value = E1.Left_Wheel_Vertical_displacement_Value + fabs((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.0f + Value[2] - 180.0f) * (M_PI / 180.00f);
       
         E1.Left_Wheel_Value_old = E1.Left_Wheel_Value; 
 ​
         if(E1.Left_Wheel_Vertical_displacement_Value> 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 || 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  = Value[2] + 180;
         }
         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  && 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日编写完成

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值