简 介: 本智能车系统MM32SPIN27PS以微控制器为核心,用编码器检测模型车的运动位置和方向。使用PID控制算法调整驱动电机的速度和角度,完成模型车运动速度和方向的闭环控制。我们使用它来完成接力任务,提高智能汽车的速度和可靠性OLED大量的底层和上层测试,如显示模块、无线模块、按键模块等。实验结果表明,系统设计方案是可行的。 : ,,**OLED **
引言
1.1 相关背景
??第十六届全国大学生智能汽车比赛如约而至。我们队是辽宁工业大学双车接力组,共有四名选手。选手均为具有正式学籍的全日制大二本科生,符合比赛要求。
??本次比赛采用组委会提供的比赛车模,采用32位智能微电子微控制器MM32SPIN27作为核心控制单元,独立构思控制方案和系统设计,包括模具机械结构设计、电路设计、传感器信号采集处理、控制算法和执行、传球接力等,最终实现智能车辆控制系统,可独立识别路线,实时输出车身状态。本文主要简要说明了车模的整体设计思路、硬件和软件设计以及车模的组装调试过程。
1.2 构成概要
??本技术报告包含六章。第一章是引言部分。主要概述了智能车模的制作情况,并阐明了报告内容的构成。第二章是系统设计部分。详细介绍智能车模系统的设计和方案选择。第三章是实现机械结构。详细介绍了模型车机械部件的安装和改造、传感器的设计和安装、系统电路板的固定和连接等。第四章是硬件电路,包括电路原理和车模基本参数。第五章是软件设计,介绍了微处理器控制软件的主要理论、算法描述和代码设计。第六章是总结。
第二章 系统设计
2.1 设计思路
??根据本次比赛规则,智能汽车系统采用智能公司32位微控制器MM32SPIN27PS智能汽车系统控制采用单片机作为核心控制单元。通过电磁运放模块放大电感采集,返回单片机,计算后作为转向控制的依据。陀螺仪加速度计返回的信号作为当前车身姿势的信号,主控输出PWM波控制电机的转速,保持车身平衡,锁定轨道。与基本四轮组不同,双车组需要使用左右轮的差速来转动。为了控制准确性和快速性,我们使用陀螺仪的z轴角速度作为返回信号来抵消转弯过程中的超调。使用编码器返回的信号可以形成闭环PID控制电机转速。双车组直立车的加减速会明显改变车身角度,影响车辆平衡,使车速无法控制。因此,调试过程是在保证车身稳定的前提下,逐步提高直立车的整体速度。
??根据上述系统方案设计,双车组包括六个模块:MM32SPIN27PS主控模块、传感器模块、电源模块、电机驱动模块、速度检测模块和辅助调试模块。各模块的作用如下:MM32SPIN27PS主控模块,作为整个车的控制中心就像人的“大脑”,将电磁传感器、陀螺仪加速度计和编码器等传感器的信号,根据赛道情况作出不同的决策进行不同的控制算法,驱动两个直流电机完成对车体的控制;传感器模块,用来检测当前赛道信息是智能汽车的“眼睛”,可以通过一定的前瞻性,提前感知前面的轨道信息,为智能汽车的大脑做出决策提供必要的基础和足够的反应时间,并使用陀螺仪加速度计算实时角度和加速度信息,以保持车辆模型的稳定运行;电源模块为整个系统提供适当稳定的电源;电机驱动模块,驱动直流电机完成智能汽车的加减速控制和转向控制;速度检测模块,用于速度闭环控制的智能车轮转速检测反馈;无线串口等辅助调试模块主要用于调试过程中对车辆采集数据的观察和监控。
2.2 方案选定
??根据比赛规则,车辆通过检测轨道中心电磁线的交变电磁场信号来控制车模沿电磁线前进。由于直立车的特殊性,车身必须进过程中必须保持平衡。根据保持车身平衡最基本的基本原理,我们需要知道当前的角度和速度。因此,在保持车身平衡方面,我们决定以加速度计为角度传感器,陀螺仪为角度传感器。此外,陀螺仪也用于车身转向控制的转向反馈。
第三章 机械结构
3.1 安装改造机械结构
3.1.1三轮车模
▲ 图3.1 三轮车模型图片
??对于重心问题,我们将整辆车的重心控制在车轮轴的附件上,这有助于转向。因此,我通过热熔胶将电路板粘在车轮附近,每个电路板通过硅胶线与杜邦线连接,并在电池前加入铁球。对于传球结构,我们通过热熔胶将切开的乒乓球粘在碳杆上,并将乒乓球切开几个间隙,以确保乒乓球在正常驾驶过程中能够夹住,并在传球过程中能够正常传球。四种电感通过热熔胶粘在碳杆上,其中两种是八字型,两种是一字型。陀螺仪几乎通过热熔胶粘在车轮轴附近,因此陀螺仪的值偏差不会太大。
3.1.2 直立车模
▲ 图3.2 直立车模图片
??为了为直立车设置更好的机械零点,使车辆的加减速更容易控制,我们将主板垂直安装在电机附近,驱动板放置在电机上方,用热熔胶和带固定硅胶线和杜邦线连接,使车辆重心基本保持在轴上;传球装置通过一对强磁铁吸附小球,使传球更简单,不易出错;巡逻使用五种电感,它们是左、中、右三个一字电感和中间两个八字电感,通过热熔胶固定在碳杆上;陀螺仪通过底板钻孔将螺钉固定在两轮中轴的位置,使汽车的姿势与陀螺仪测量的数据保持一致。
3.2模型车的主要技术参数
▲ 表3.2 车型的主要技术参数
第四章 硬件电路
4.1 设计思路
4.1.1 硬件系统框图
▲ 图2.1 硬件系统框图
4.1.2 框图说明
在上图所示智能车模的硬件系统框图中,智能车模是以MM32SPIN27单片机最小系统板为控制核心;使用电压为7.2V,容量为2AH的镍镉电池作为能量来源,分别为智能车模上各个模块供电;在PVC赛道上布置电磁线并接入信号源,车辆通过电感去采集赛道上各个元素的电感值,并将采集到的信号进行放大处理,送往单片机进行算法运算处理;单片机经过路况分析后,合理、准确地输出PWM信号控制左右电机的差值,从而很好地控制智能车模转向;单片机分析编码器采集到的脉冲数与所设定脉冲数的差值经过运算处理输出PWM信号控制电机的转速;从而快速、准确的完成比赛。
4.2 电源电路
我们所使用的各个传感器模块需要5V和3.3V供电,所以我们通过线性稳压芯片将电源电压分成5V和3.3V。
▲ 图4.2.1 5V电源
▲ 图4.2.2
为了降低干扰,我们特意把电磁运放供电部分单独拿出来。
▲ 图4.2.3 电磁运放供电
4.3电磁运放芯片
关于运放芯片,一开始采用的是LM324,但通过焊接后测试发现,该电路的性能达不到我们的需要,采集的信号经该电路放大后过于敏感,稍一抖动,电感值变化特别巨大,所以在不断尝试后,我们最终确定了使用OPA4377,该芯片有如下几个优点:
- 增益带宽乘积:5.5MHz
- 低噪声:1kHz时为7.5nV/√Hz
- 偏移电压:1mV(最大)
- 输入偏置电流:0.2pA
- 轨对轨输出
- 单位增益稳定
- EMI输入滤波
- 静态电流:0.76mA/ch
- 电源电压:2.2V至5.5V
最终通过测试,该电路符合需要。
4.4驱动电路
驱动芯片我们采用的是BTN7971,该芯片具有耐压值高,载流能力强等优点,简单来说,就是便宜好用,而且电路比较简单。电源电压直接给驱动板供电,单片机输出PWM直接驱动电机,通过逻辑芯片74HC02来控制电机转动的方向,从而完成一系列动作。在PCB板中,我们特意对7971芯片底部做了开窗,打孔等散热处理,车模在长时间运行过程中,没有出现发热现象。
▲ 图4.4.1 驱动电路原理图
▲ 图4.4.2 PCB板散热处理
软件设计
5.1 电感采集处理
▲ 图5.1赛道铺设图片
我们的车模是用纯电感运行的,对于电感采回来的值进行10次求平均值处理,使电感值不会突然出现很大的偏差。正常道路上是利用两个一字电感进行循迹,用(电感左-电感右)/(电感左+电感右)得到偏差值。
- 出库:直线行驶一段距离,这个距离由编码器积分得到,再向右打固定偏差的固定角度,这个角度由陀螺仪积分得出。
- 环岛:利用八字电感找到特征点进环;再利用四个电感的特征点判定为环内切换为一字电感运行;再利用一字电感的特征点判定为出环,用八字电感循迹;由于此时环岛对于正常直线道路仍有影响所以在循迹的一段距离手动加了偏差,这个距离利用编码器积分得到。
- 坡道:利用陀螺仪y轴的角速度判定。
- 三叉:利用中间一字电感判定,给个固定偏差向右打一个角度,这个角度由陀螺仪积分得出。
- 十字:使用左右一字电感寻迹无需处理。
- 有球接力:当三轮撞击直立时,直立车编码器产生脉冲后利用无线串口向三轮发送信息,直立启动,三轮利用编码器行驶一段距离停止。
- 无球接力:三轮进入三叉后向直立发送信息,直立启动,三轮利用编码器行驶一段距离停止;直立进入三叉后向直立发送信息,三轮启动,直立停止。
- 角速度环:位置式PID,使用了PI调节;角度环:位置式PID,使用了PD调节;
- 转向环:位置式PID,使用了PD调节,其中D的部分是陀螺仪z轴的角速度;
- 速度环:位置式PID。由于位置式PID有对历史的累加,故转向环只有PD调节。将速度环算出的值反馈给角度环,经过角度环计算后再反馈给角速度环,最后计算值为最后的电机输出值。对于直立PID参数的整定则是先角速度环I、P,再角度环P、D的方法进行。
5.2 算法说明及代码设计介绍
结论
参加“第十六届全国大学生智能车竞赛”不是一时冲动,而是“蓄谋已久”,在这项比赛中,我们队伍成员从零开始,查阅资料,设计机械结构,组装车模,程序设计,调整参数,分析问题,解决问题。
大二上学期我们完成了硬件电路设计和制作,组装车模,主控芯片的了解和学习。大二下学期我们考虑使用摄像头,但因为种种原因放弃了摄像头,采用纯电磁,而后研究算法,电机控制不断对机械结构和参数进行优化,最终使车模控制达到预期效果。过程中遇到很多问题,环岛,三叉,传球,坡道处理等等,方案一次次更改,参数一次次调试,熬了一个又一个日夜,感受了多次从满怀信心到情绪崩溃,调车的过程像极了过山车,有巅峰,有低谷,有眼泪也有欢笑。无论硬件还是软件,我们收获满满,也增进了团队之间的友谊。
在这份技术报告中,我们尽可能详细的介绍了我们车模的相关信息,不完美之处欢迎指正。 这一年的制作和调试时间中,得到了多方面的帮助。在调试过程中,老师及时指出我们的问题让我们纠正,学弟主动帮助我们制作赛道,在试验场地和经费中,我们都得到了学校和学院的大力支持,在此特别感谢一直关注和支持智能车竞赛的学校和学院的各位领导。感谢卓大大、组委会、志愿者和线上裁判的辛苦付出。你若盛开,蝴蝶自来。结果总会与付出成正比的。希望智能车竞赛越来越好!
参考文献
[1] 卓晴,黄开胜,邵贝贝,《学做智能车——挑战“飞思卡尔”杯》,北京北京航空航天大学出版社,2007 [2] 邵贝贝. 单片机嵌入式应用的在线开发方法[M].北京.清华大学出版社,2004 [3] 夏路易, 石宗义,电路原理图与电路板设计教程 Protel 99SE[M]. 北京, 北京希望电子出版社 [5]尹怡欣,陶永华,新型 PID 控制及其应用.北京:机械工业出版社,1998 年. [6]黄渊博,王潇祎,彭成,第十三届“恩智浦”杯全国大学生智能汽车竞赛河海大学常州校区 VNX 队技术报告 [7] 阎石. 数字电子电路基础. 北京, 高等教育出版社, 2005 [8] 曹丽,刘扬,刘伟.利用加速度计和陀螺仪的笔杆运动姿态的检测[M].仪器仪表学报 [9] 华成英, 童诗白. 模拟电子技术基础. 北京, 高等教育出版社, 2006
■ 附录 程序源代码
int abs(int i) //
{
/* compute absolute value of int argument */
return (i < 0 ? -i : i);
}
float *FastAtan2(float y, float x) //
{
float f, g;
float num, den;
float result;
float *nanresult = &result;
int n;
static const float a[4] = {
0, (float)PI_6, (float)PI_2, (float)PI_3};
if (x == (float)0.0)
{
if (y == (float)0.0)
{
result = 0.0;
//return result;
return nanresult;
}
result = (float)PI_2;
if (y > (float)0.0)
{
//return result;
return nanresult;
}
if (y < (float)0.0)
{
result = -result;
//return result;
return nanresult;
}
}
n = 0;
num = y;
den = x;
if (num < (float)0.0)
{
num = -num;
}
if (den < (float)0.0)
{
den = -den;
}
if (num > den)
{
f = den;
den = num;
num = f;
n = 2;
}
f = num / den;
if (f > (float)TWO_MINUS_ROOT3)
{
num = f * (float)SQRT3_MINUS_1 - 1.0f + f;
den = (float)SQRT3 + f;
f = num / den;
n = n + 1;
}
g = f;
if (g < (float)0.0)
{
g = -g;
}
if (g < (float)EPS_FLOAT)
{
result = f;
}
else
{
g = f * f;
num = (ATANP_COEF1 * g + ATANP_COEF0) * g;
den = (g + ATANQ_COEF1) * g + ATANQ_COEF0;
result = num / den;
result = result * f + f;
}
if (n > 1)
{
result = -result;
}
result = result + a[n];
if (x < (float)0.0)
{
result = PI - result;
}
if (y < (float)0.0)
{
result = -result;
}
//return result;
return nanresult;
}
void Yijie(void) //
{
// Acc_Cul = *FastAtan2(icm_acc_x,icm_acc_z)*180/3.14;
//
// GY_Cul = -icm_gyro_y; //
//
// CarAngle = k1*Acc_Cul + (1 - k1)*(CarAngle_last + GY_Cul*0.002); //K1=0.3819 CarAngleÊÇÈںϽǶÈ
// CarAngle_last = CarAngle;
// my_carangle = CarAngle_last;
Acc_Cul = *FastAtan2(icm_acc_x,icm_acc_z)*180/3.14;
GY_Cul = -icm_gyro_y/131.00; //GY_CulÊǽÇËÙ¶È
x1 = (Acc_Cul - my_carangle) * (1 - K2) * (1 - K2);
y1 = y1 + x1 * dt;
x2 = y1 + 2 * (1 - K2) * (Acc_Cul - my_carangle) + GY_Cul;
my_carangle = my_carangle + x2 * dt;
}
void AngleControl(void) //Ö±Á¢¿ØÖÆ
{
if(star==1&&my_carangle<30)
{
N_Kp=1.3;
N_Ki=0.07;
W_Kp=100;
}
else
{
star=2;
N_Kp=2.7;
N_Ki=0.29;
W_Kp=30;
}
get_icm20602_accdata_spi();
get_icm20602_gyro_spi();
Yijie();
N_prev_error = N_last_error;
N_last_error = N_current_error;
N_current_error = (int16)-(W_add + icm_gyro_y);
N_P = (int32)(N_Kp * N_current_error);
N_I += (int32)(N_Ki * N_current_error);
N_D = (int32)(N_Kd * (N_current_error - N_last_error));
if(N_I > value) N_I = 6000;
if(N_I < -value) N_I = -6000;
N_add = N_P + N_I + N_D;
balance_pwm = N_add;
motor_output();
if(speed_flag == 1)
{
speed_flag = 0;
speed_control();
}
if(angle_flag==1)
{
angle_flag = 0;
W_current_error = (int16)(current_angle - my_carangle - speed_output);
W_P = (int16)(W_Kp * W_current_error);
W_I += (int16)(W_Ki * W_current_error);
W_D = (int16)(W_Kd * (W_current_error - W_last_error));
W_add = W_P + W_I + W_D;
}
}
void turn_PID(void)
{
data_analyse();
turn_W_current_error = error;
turn_W_P = (int16)(turn_W_Kp * turn_W_current_error);
turn_W_I += (int16)(turn_W_Ki * turn_W_current_error);
turn_W_D = (int16)(turn_W_Kd * icm_gyro_z);
turn_W_add = turn_W_P + turn_W_I - turn_W_D;
turn_pwm = turn_W_add;
}
void motor_speed(int speed) //
{
V_prev_error = V_last_error; //???????
V_last_error = V_current_error; //???????
V_current_error = speed - speed_now; //???????(???????)
V_P = (int)(V_Kp * V_current_error); //P???
V_I += (int)(V_Ki * V_current_error); //I???
V_D = (int)(V_Kd * (V_current_error - V_last_error)); //D???
if(V_I > value) V_I = value; //????
if(V_I < -value) V_I = -value;
V_add = V_P + V_I + V_D;
speed_output= V_add;
speed_output = speed_output*0.7 + last_speed_output*0.3;
if(speed_output >= 10) //??????
speed_output = 10;
if(speed_output <= 0)
speed_output = 0;
last_speed_output = speed_output;
}
void motor_output(void) //
{
static unsigned int a;
if(stop_flag==1)
{
a++;
if(a>=400&&my_carangle<=0)
{
turn_pwm=0;
}
left_pwm = 0 + turn_pwm;
right_pwm = 0 - turn_pwm;
}
else
{
a=0;
left_pwm = balance_pwm + turn_pwm;
right_pwm = balance_pwm - turn_pwm;
}
if(star_flag==1)
{
if(left_pwm >= 0)
{
if(left_pwm > 9000)
left_pwm = 9000;
gpio_set(A11,0);
pwm_duty_updata(PWM_TIM, TIM_2_CH2_A12 , left_pwm);
}
if(left_pwm < 0)
{
if(left_pwm < -9000)
left_pwm = -9000;
gpio_set(A11,1);
pwm_duty_updata(PWM_TIM, TIM_2_CH2_A12 , - left_pwm);
}
if(right_pwm >= 0)
{
if(right_pwm > 9000)
right_pwm = 9000;
gpio_set(C9,0);
pwm_duty_updata(PWM_TIM, TIM_2_CH4_B11, right_pwm);
}
if(right_pwm < 0)
{
if(right_pwm < -9000)
right_pwm = -9000;
gpio_set(C9,1);
pwm_duty_updata(PWM_TIM, TIM_2_CH4_B11, - right_pwm);
}
}
}
- 图3.1 三轮车模图片
- 图3.2 直立车模图片
- 表3.2 车模主要技术参数
- 图2.1 硬件系统框图
- 图4.2.1 5V电源
- 图4.2.2
- 图4.2.3 电磁运放供电
- 图4.4.1 驱动电路原理图
- 图4.4.2 PCB板散热处理
- 图5.1赛道铺设图片