一、硬件选择

这里不是打广告

(一)电机驱动

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日编写完成

    作者:fyphauhs

    物联沃分享整理
    物联沃-IOTWORD物联网 » 2024年电赛H题解析

    发表回复