NXP智能车竞赛笔记(室外电磁组)

一、概要

比赛规则与赛道:
比赛没有赛道,只有电磁线。但赛道元素包括有直道、弯道、坡道、十字路口以及横断路障。室外电磁组原则上选择室外的马路、草坪、体育场组织比赛,场地内可能会存在高度不大于 2 厘米的硬质路坎、沙坑、深度不超过 2 厘米的水坑等。
选手制作的车模完成赛道运行一周。比赛时间从车模冲过起跑线到重新回到起跑线为止。

越野车外形
NXP智能车竞赛笔记(室外电磁组)_第1张图片
车的功能与实现:
NXP智能车竞赛笔记(室外电磁组)_第2张图片
本文脉络
NXP智能车竞赛笔记(室外电磁组)_第3张图片

二、硬件部分:

1.主控板

(1)原理图:

K60引脚分配:
引脚通过查K60引脚功能来分配,除去特殊功能引脚外,其余引脚为普通I/O口
特殊引脚:
I2C通信:SDA,SCL
FTM(PWM输出):PWMA,DPWM
AD(模数转换):AD1~AD6
串口通信:TX2,RX2
NXP智能车竞赛笔记(室外电磁组)_第4张图片
电源部分及笔记:(7~8v输入,5v和3.3v输出)

NXP智能车竞赛笔记(室外电磁组)_第5张图片
以下为原理笔记:
NXP智能车竞赛笔记(室外电磁组)_第6张图片
NXP智能车竞赛笔记(室外电磁组)_第7张图片
按键模块:(SW2为4并排按键,用于设置车的模式)
NXP智能车竞赛笔记(室外电磁组)_第8张图片

在这里插入图片描述
电机输出(为排针插座,接驱动板,DIRA为电机方向控制,PWMA为速度控制):

NXP智能车竞赛笔记(室外电磁组)_第9张图片
舵机输出(为排针插座,5v供电电压,DPWM为脉冲输出,以控制舵机转角):
NXP智能车竞赛笔记(室外电磁组)_第10张图片
AD输入(为排针插座,接传感器板,6路电感值输入):
NXP智能车竞赛笔记(室外电磁组)_第11张图片
普通IO口:
NXP智能车竞赛笔记(室外电磁组)_第12张图片
串口:
NXP智能车竞赛笔记(室外电磁组)_第13张图片
蜂鸣器:
NXP智能车竞赛笔记(室外电磁组)_第14张图片
(2)PCB和3D图
PCB中,logo部分和敷铜(GND)已去除,以更清晰显示电路
NXP智能车竞赛笔记(室外电磁组)_第15张图片
NXP智能车竞赛笔记(室外电磁组)_第16张图片

2.电机驱动板:用于驱动电机

(1)原理图

H桥电机驱动:
VCC直接接电池(7~8V)
NXP智能车竞赛笔记(室外电磁组)_第17张图片
H桥原理:
NXP智能车竞赛笔记(室外电磁组)_第18张图片
12v升压(用于IR2104s驱动mos管):
NXP智能车竞赛笔记(室外电磁组)_第19张图片
电源部分:
VCC是电机供电
NXP智能车竞赛笔记(室外电磁组)_第20张图片
12V(用于IR2104s驱动MOS)和3.3v(逻辑芯片供电):

NXP智能车竞赛笔记(室外电磁组)_第21张图片
NXP智能车竞赛笔记(室外电磁组)_第22张图片
调速及转向:
Led显示电机方向及速度大小(速度越大越亮):
NXP智能车竞赛笔记(室外电磁组)_第23张图片
排针插座信号输入,3.3v用于逻辑芯片供电:
NXP智能车竞赛笔记(室外电磁组)_第24张图片
逻辑非和逻辑与芯片:
NXP智能车竞赛笔记(室外电磁组)_第25张图片
NXP智能车竞赛笔记(室外电磁组)_第26张图片
原理笔记:

NXP智能车竞赛笔记(室外电磁组)_第27张图片
(2)PCB(GND敷铜已去)和3D图
NXP智能车竞赛笔记(室外电磁组)_第28张图片
NXP智能车竞赛笔记(室外电磁组)_第29张图片

3.传感器板:处理电感数据

(1)原理图

电源部分:
NXP智能车竞赛笔记(室外电磁组)_第30张图片
信号放大:(opa2350为运放,根据电阻,放大倍数最大50倍,输入输出为正弦波,共6路)
NXP智能车竞赛笔记(室外电磁组)_第31张图片
信号整流(经实验,连接AD输出和GND的电容会严重削弱信号,故去除):
NXP智能车竞赛笔记(室外电磁组)_第32张图片
信号输入输出(为插座):
NXP智能车竞赛笔记(室外电磁组)_第33张图片

(2)PCB(GND敷铜已去除)和3D图
NXP智能车竞赛笔记(室外电磁组)_第34张图片
NXP智能车竞赛笔记(室外电磁组)_第35张图片

4.电磁探测板:探测电磁线信号

(1)原理图

谐振部分:谐振可以很好放大信号,电感电容值根据20K频率谐振计算。
NXP智能车竞赛笔记(室外电磁组)_第36张图片
其他部分(LED和排针插座):
NXP智能车竞赛笔记(室外电磁组)_第37张图片

(2)PCB(GND敷铜已去除)和3D图

在这里插入图片描述
在这里插入图片描述
电感与电磁线垂直时信号最强,故六路电感位置摆放:
NXP智能车竞赛笔记(室外电磁组)_第38张图片
这样放置电感,可以满足在多方位的检测需求。

三、软件部分

智能车主要用到的几样硬件需要软件驱动,包括电机,舵机,编码器,ADC采集和超声波模块;还有一些调车的辅助模块,如OLED,蓝牙,串口,这些部分都采用了相应的例程做了需要的修改。

1.电机和舵机

(1).电机
电机部分需要主控芯片输出PWM波控制电机转速,编写了电机初始化及控制函数,包括了电机正反转的设置。

void Motor_Init()    
{
	GPIO_Init(PORTA,7,1,1);//GPIO初始化
	FTM_PWM_Init(FTM0, FTM_CH2, 0,0);//PWM初始化
	Motor_Control(0,0);
}

void Motor_Control(int16 PWM,int DIR)//PWM为速度参数,DIR为正反转
{
  if(DIR==0)
  {
    GPIO_Ctrl(PORTA,7,0);
  }
  else
  {
    GPIO_Ctrl(PORTA,7,1);
  }
  FTM_PWM_Duty(FTM0,FTM_CH2,PWM);//PWM最大1000
}

(2).舵机

舵机正常工作需要的50hz的PWM波来控制转角,通过控制占空比在5%到15%之间,可以实现舵机180度范围的旋转。在前期的调试过程中确定了舵机状态处于中点的占空比值,在这一值的基础上直接加减实现舵机控制左右转。
测试代码:使轮子到达两个最大转向角

     FTM_PWM_Duty(FTM2,FTM_CH0,730);
     time_delay_ms(2000);
     FTM_PWM_Duty(FTM2,FTM_CH0,835);
     time_delay_ms(2000);

2、传感器(电感,编码器和超声波)

越野组采用电感电容谐振来感应电磁引导线的磁场信号,信号经过谐振放大以及运放放大后通过芯片的ADC模块采集。由于采集的信号可能存在较大波动,采用了均值滤波的方式,选取四次采样平均值作为实际使用的数据。考虑到车前的三组电感相对电磁线的位置有区别,为了使收集到的数据尽量趋于线性变化,对数据做了线性化处理,根据三组电感的位置乘上了参数用作矫正。

void ADC_6()
{
  int i;
  volt[0]=ADC_Ave(ADC1,ADC1_SE14,ADC_16bit,4);//均值滤波
  volt[1]=ADC_Ave(ADC1,ADC1_SE15,ADC_16bit,4);
  volt[2]=ADC_Ave(ADC1,ADC1_SE12,ADC_16bit,4);
  volt[3]=ADC_Ave(ADC1,ADC1_SE13,ADC_16bit,4);
  volt[4]=ADC_Ave(ADC1,ADC1_SE10,ADC_16bit,4);
  volt[5]=ADC_Ave(ADC1,ADC1_SE11,ADC_16bit,4);
  sprintf(txt,"0%06d",volt[0]);
  LCD_P6x8Str(5,1,(uint8 *)txt); //LCD屏显示
  sprintf(txt,"1%06d",volt[1]);
  LCD_P6x8Str(5,2,(uint8 *)txt);
  sprintf(txt,"4%06d",volt[4]);
  LCD_P6x8Str(5,3,(uint8 *)txt);
  sprintf(txt,"5%06d",volt[5]);
  LCD_P6x8Str(5,4,(uint8 *)txt);
  sprintf(txt,"2%06d",volt[2]);
  LCD_P6x8Str(54,1,(uint8 *)txt);
  sprintf(txt,"3%06d",volt[3]);
  LCD_P6x8Str(54,2,(uint8 *)txt);
}

均值和终值滤波代码:

u16 ADC_Ave(ADCn_e adc_n,ADCn_Ch_e adc_ch,ADC_nbit bit,u16 N) //均值滤波
{
    u32 tmp = 0;
    u8  i;
    for(i = 0; i < N; i++)
       tmp += ADC_Mid(adc_n,adc_ch,bit); 
    tmp = tmp / N; 
    return (u16)tmp;
}
u16 ADC_Mid(ADCn_e adc_n,ADCn_Ch_e adc_ch,ADC_nbit bit) //中值滤波
{
    u16 i,j,k,tmp;
    //1.取3次A/D转换结果
    i = ADC_Once(adc_n,adc_ch,bit); 
    j = ADC_Once(adc_n,adc_ch,bit); 
    k = ADC_Once(adc_n,adc_ch,bit); 
        //2.取中值
        if (i > j)
        {
          tmp = i; i = j; j = tmp;
         }
         if (k > j) 
           tmp = j;
         else if(k > i) 
           tmp = k; 
         else 
          tmp = i;
     return tmp;
}

(2)编码器

实物图
NXP智能车竞赛笔记(室外电磁组)_第39张图片
AB相增量式编码器原理:
NXP智能车竞赛笔记(室外电磁组)_第40张图片
NXP智能车竞赛笔记(室外电磁组)_第41张图片
发光二极管发射的光通过光栅到达光敏管,引起电平变化。如果正转,A相输出超前B相90度,如果反转A相滞后B相90度。
AB相正交解码原理:
NXP智能车竞赛笔记(室外电磁组)_第42张图片
CNT寄存器:寄存器通过正解解码的得到的脉冲值,最后只要读取CNT的值就可以得到编码器转数(正值为正转,负值为反转)。
CNTIT寄存器:CNT计数的初始值。
AB相的电平和跳变沿决定了CNT的加数和减数。
CNT增计数时:
A上升沿,B逻辑低
B上升沿,A逻辑高
B下降沿,A逻辑低
A下降沿,B逻辑高
CNT减计数是:
A下降沿,B逻辑低
B下降沿,A逻辑高
B上升沿,A逻辑低
A上升沿,B逻辑高

编码器数值的读取我们使用了k60芯片的FTM模块中的正交解码功能来实现,直接调用库中的正交解码函数就可以获得脉冲数,通过比例换算可以获得当前速度。

SPEED=FTM_AB_Get(FTM1);    //读取正交解码数值

获取FTM正交解码脉冲数的函数:

int16 FTM_AB_Get(FTMn_e ftmn)
{
    uint32 val;
    val = FTM_CNT_REG(FTMN[ftmn]);// 计数器,只有低16位可用(写任何值到此寄存器,都会加载 CNTIN 的值)
    FTM_CNT_REG(FTMN[ftmn]) = 0;             
    return val;
}

(3).超声波
超声波模块的使用主要根据模块的测距原理编写,首先使Trig口输出不少于的10us的高电平信号,随后通过k60低功耗计时器(lptmr)计算Echo端高电平持续时间,即超声波从发送到接收的时间,最后用时间计算出距离。

void US_Init()
{
  GPIO_Init(PORTA,27,1,0);
  GPIO_Init(PORTA,29,0,0);
}

void Distance_Get()
{
  i=0;
  char txt[20]=' ';
  GPIO_Ctrl(PORTA,27,1);
  LPTMR_delay_us(20);
  GPIO_Ctrl(PORTA,27,0);
  while(GPIO_Get(PTA29)==0);
  LPTMR_time_start_us();
  while(GPIO_Get(PTA29)==1);
  i = LPTMR_time_get_us();
  if(i > 65535)
  {
    d=10000;
  }
  else
  {
    d=(int)(i*0.2);
  }
  sprintf(txt,"dis= %06dmm",d);
  UART_Put_Str(UART4,txt); //串口输出
  LCD_P6x8Str(28,7,(uint8 *)txt); //LCD输出
}

3、控制部分:舵机和电机

(1)PID代码
智能车的控制主要采用了经典的PID控制算法,分为电机速度控制和舵机方向控制。

舵机的控制是最重要的部分,是巡线的关键。通过ADC采集的三组电感的电压值来判断当前车身的状态,将当前值与期望值比较得到误差,代入增量式PID,调节出合适的参数,从而能够输出调整量使车能够始终巡线运行。

电机控制要求精度不高,只采用了PI控制,保证车速相对稳定,不至于产生太大波动,主要为了应对粗糙路面以及上下坡的情况。通过编码器传回的速度值判断当前车速,调整至稳定值。主要应用于上坡时,通过PID增大电机电流。

PID及其参数特点:
NXP智能车竞赛笔记(室外电磁组)_第43张图片
增量式PID介绍:
NXP智能车竞赛笔记(室外电磁组)_第44张图片
实现代码:

typedef struct //把PID定义为结构体形式
{
  float Kp,Ki,Kd;
  float Feedback;
  float Target;
  float error0,error1,error2;
  float Output;
  float Range; //控制输出范围,防止输出过大
}Type_PID;

void PID(Type_PID* PID)
{
 PID->error0 = (PID->Target) - (PID->Feedback);
PID->Output = (PID->Kp)*(PID->error0)+PID->Kd*(PID->error0-2*PID->error1+PID->error2)+PID->Ki*(PID->error0+PID->error2); 
	//更新偏差
	PID->error2 = PID->error1;
	PID->error1 = PID->error0;
	//对PID死区控制,因输出电流太小不足以驱动电机
	if (abs(PID->Output) < 20)
		PID->Output = 0;
	PID->Output = limit(PID->Output, PID->Range, -PID->Range);//把output限制在+-range之内
}

(2)主函数中PID代码

//pid初始设置
pid=(Type_PID *)malloc(sizeof(Type_PID));
   memset(pid,0,sizeof(Type_PID));
   pid_speed=(Type_PID *)malloc(sizeof(Type_PID));
   memset(pid_speed,0,sizeof(Type_PID));
   //电机速度PID
   pid_speed->Kp=1;
   pid_speed->Ki=4;
   pid_speed->Range=700;
   //舵机转角PID
   pid->Kp=1.5;
   pid->Ki=0.7;
   pid->Kd=7.5;
   pid->Range=142;

4.显示部分

(1)串口与蓝牙
蓝牙模块用的是HC-05,可以与串口共用。
下面给出库中的串口发送字符串函数,不赘述。

//例子:uart_putchar (UART4, "123456789");实际发送9个字节
void UART_Put_Str (UARTn_e uratn, char *str) //参数: uratn:模块名如:UART0 ,str: 发送的地址   
{
    while(*str)
    {
        UART_Put_Char(uratn, *str++);
    }
}

(2)LCD屏
列出库中函数,具体实现不赘述。

LCD_P6x8Str(unsigned char x,unsigned char y,unsigned char *p)// 写入一组标准ASCII字符串, 显示的位置(x,y),y为页范围0~7,要显示的字符串
void LCD_P14x16Str(unsigned char x,unsigned char y,unsigned char ch[])  //输出汉字字符串

你可能感兴趣的:(NXP智能车竞赛笔记(室外电磁组))