一、第一个难点在于使用mspm0作为主控芯片
不像历年来使用的msp430或者msp432,我们是直接使用的b站up主我的代码没问题的库,这个up主封装了自己的ml库,帮助我们封装好了寄存器,提供了上层接口,单片机外设的常用函数都可以很方便的直接调用。
2024电赛小白入门 手把手教你做一辆电赛小车|STM32|MSP432|PID|MPU6050_哔哩哔哩_bilibili
关于ml库的bug问题:当时遇到的是程序编译过了,下载不进去,最离谱的是删掉一行程序就能下载进去,加上一行程序就下不进去了,当时想了很多办法,最后竟然是keil版本的问题,更新了keil版本之后就没遇到这种问题了,更新之后的版本是5.39。
二、这个题第二个难点是陀螺仪传感器的问题
1.使用g3507芯片解算mpu6050传感器会影响编码器的测速,因为不管使用定时器中断还是使用外部中断(mpu6050的int引脚)去解算数据,因为解算数据会占用长时间的cpu,而这个长时间占用cpu会导致定时器中断那里来不及清零数据,导致速度计算出问题,从而无法使用速度环pid去调整正确的占空比。
2.使用mpu6050传感器会产生误差,比如上电之后规定一个方向为0,旋转传感器一圈之后他会有几度的飘逸,这会产生累计误差,影响到第四问的跑四圈。产生误差的原因有温度的影响,网上流传的解决方案是使用5883磁力计,并融合卡尔曼滤波,来进行补偿。因为涉及到一些深度算法,对于没有准备过得队伍,四天三夜的时间比较紧张。
所以我们使用的是维特的陀螺仪维特智能六轴加速度计电子陀螺仪模块姿态角度传感器高精度JY61P-tmall.com天猫
这款陀螺仪自带mcu解算,数据特别精准,而且误差 特别小,并且使用串口传递数据,通信比较简单,关于jy61的解算,可以使用串口中断来解包,依靠的这个表:
三、有关小车尺寸和传感器排布。限制宽度15cm,长度25cm,要把小车做的尽量宽,可以排布巡线传感器尽量宽,我们当时使用了一个八路巡线,旁边加了两个单路巡线,总共十路巡线。其实可以十二路巡线。巡线越宽,第三问斜着走的时候越容易识别到黑线。而且,每个巡线传感器之间的间隔必须离得近,再走弯道的时候,不会出现传感器都识别不到黑线的情况,这样会大大减少代码检测的难度,直接检测不到黑线就代表出巡线区域了,不用结合定时器再来判断是否出巡线区域。巡线传感器必须用灰度传感器,红外传感器一是需要调节,二是对于红外传感器哑光布不一定能识别出来。
八路灰度传感器 白黑红黄蓝绿线循迹模块 光电传感器 感为科技-淘宝网 (taobao.com)
智能小车灰度巡线传感器可见白光非红外 支持arduino0 1路模拟输-淘宝网 (taobao.com)
四、代码部分
使用状态机,仅仅使用一个标志位就能完成每个状态的转换,附上第三问shi山代码,使用一个标志位step1的不同数值,来完成状态之间的切换,大概就是这样的思路
#define middle 16500
#define error1 3000
void track_mode3()
{
oled_printf(4,1,"yaw%.4f",yaw);
gray=track_read();
if(step1==0)//a->c矫正
{
if((yaw > 324 && yaw < 360) || (yaw > 0 && yaw < 30) )// ,第一步a-》c矫正修正yaw=321斜线预备角, 偏移时提供PWM
{
motorA_dir=1;
motorB_dir=0;
motorA_duty(sp);
motorB_duty(sp+2000);
}
else if(yaw > 315 && yaw <= 324)
{
step1=1;// 角度修正完成 ,进入第二步
}
else if(yaw > 30 && yaw <= 324)
{
motorA_dir=0;
motorB_dir=1;
motorA_duty(sp+2000);
motorB_duty(sp); }
}
if(step1==1) // 约定脉冲数road_a < 1880//a-》c直走
{
gray=track_read(); //进行一次灰线传感读取
go_on(3); // go on @ mode 3
}
if((gray!=0)&&step1==1) // 到c了蜂鸣器响,并往前走
{
step1=2 ;
motorA_duty(0);
motorB_duty(0);
gpio_set(GPIOA,DL_GPIO_PIN_28,1);
gpio_set(GPIOB,DL_GPIO_PIN_8,1);
delay_ms(250);
gpio_set(GPIOB,DL_GPIO_PIN_8,0);
gpio_set(GPIOA,DL_GPIO_PIN_28,0);
delay_ms(1000);
}
if(step1==2)
{
gray=track_read();
if(gray!=0)
{step1=3;}
else
{
motorA_dir=0;
motorB_dir=1;
motorA_duty(sp+2000);
motorB_duty(sp);
}
}
if(step1==3) //矫正完成开始巡线c-》b
{
gray=track_read();
switch (gray) {
case 0:
step1 = 4;
break;
case 1:
motorA_duty(0);//20000
motorB_duty(middle+error1);//0
break;
case 2:
motorA_duty(0);//25000
motorB_duty(middle+error1);//0
break;
case 3:
motorA_duty(middle);
motorB_duty(middle);
break;
case 4:
motorA_duty(middle+error1);//25500
motorB_duty(0);//25500
break;
case 5:
motorA_duty(middle);//21500
motorB_duty(middle);//12500
break;
case 6:
motorA_duty(middle);
motorB_duty(middle);
break;
case 7:
motorA_duty(middle);
motorB_duty(middle);
break;
case 8:
motorA_duty(middle+error1);
motorB_duty(0);
break;
case 9:
motorA_duty(middle+error1);
motorB_duty(0);
break;
case 10:
motorA_duty(middle+error1);
motorB_duty(0);
break;
default:
motorA_duty(16000);
motorB_duty(16000);
break;
}//switch
}
if(step1==4)//蜂鸣器和led
{
step1=5;
motorA_duty(0);//小车停止
motorB_duty(0);
gpio_set(GPIOA,DL_GPIO_PIN_28,1);
gpio_set(GPIOB,DL_GPIO_PIN_8,1);
delay_ms(1000);
gpio_set(GPIOB,DL_GPIO_PIN_8,0);
gpio_set(GPIOA,DL_GPIO_PIN_28,0);
}
if(step1==5)//到b->d矫正角度并直走,中心角度219
{
if(yaw>single+2) // ,第一步a->c矫正修正yaw=219斜线预备角, 偏移时提供PWM @ duty cycle = sp
{
motorA_dir=1;//小车左转
motorB_dir=0;
motorA_duty(17000-2000);
motorB_duty(17000);
}
else if(yaw<single)
{
oled_printf(2,1,"yaw=%d",yaw);
motorA_dir=0;//小车右转
motorB_dir=1;
motorA_duty(17000);
motorB_duty(17000-2000);
}
else
{
motorA_duty(0);
motorB_duty(0);
step1=6;//矫正完成
}
}
if(step1==6)
{
gray=track_read();
if(gray==0)
{
go_on(4);
}
else
step1=7;//找到黑线,直走结束
}
if(step1==7)
{ motorA_duty(0);
motorB_duty(0);
gpio_set(GPIOA,DL_GPIO_PIN_28,1);
gpio_set(GPIOB,DL_GPIO_PIN_8,1);
delay_ms(1000);
gpio_set(GPIOA,DL_GPIO_PIN_28,0);
gpio_set(GPIOB,DL_GPIO_PIN_8,0);
step1=8;
}
if(step1==8)//完成最后巡线
{
#define middle2 14000
gray=track_read();
switch (gray) {
case 0:
step1 = 10;
break;
case 1:
motorA_duty(0);//20000
motorB_duty(20000);//0
break;
case 2:
motorA_duty(0);//25000
motorB_duty(middle2+error1);//0
break;
case 3:
motorA_duty(0);
motorB_duty(middle2+error1);
break;
case 4:
motorA_duty(middle2);//25500
motorB_duty(middle2);//25500
break;
case 5:
motorA_duty(middle2+error1);
motorB_duty(0);
break;
case 6:
motorA_duty(middle2+error1);
motorB_duty(0);
break;
case 7:
motorA_duty(middle2+error1);
motorB_duty(0);
break;
case 8:
motorA_duty(middle2+error1);
motorB_duty(0);
break;
case 9:
motorA_duty(middle2+error1);
motorB_duty(0);
break;
case 10:
motorA_duty(middle2+error1);
motorB_duty(0);
break;
default:
motorA_duty(middle2+error1);
motorB_duty(0);
break;
}
if(step1==10)//到d点停止
{
gpio_set(GPIOA,DL_GPIO_PIN_28,1);//蜂鸣器和led
gpio_set(GPIOB,DL_GPIO_PIN_8,1);
motorA_duty(0);//小车停止
motorB_duty(0);
delay_ms(1000);
gpio_set(GPIOA,DL_GPIO_PIN_28,0);
gpio_set(GPIOB,DL_GPIO_PIN_8,0);
}
}
}