找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 13137|回复: 3
上一主题 下一主题
收起左侧

小车自动走迷宫小组工作报告

[复制链接]
跳转到指定楼层
楼主
ID:127902 发表于 2016-6-25 00:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、              综述:
a)         项目名称:小车自动走迷宫;
b)        小组成员:
                        i.              周杰:负责总体规划,及ARM编程;
                      ii.              宋大成:负责车轮驱动;
                    iii.              陈潇:负责红外驱动;
c)         小车图片:
MicroMouse615:
MicroMouse120:
二、              项目介绍:
电脑鼠走迷宫竞赛的目的是制作一个微型机器人,它能在最短的时间内穿越迷宫到达终点。参赛的机机器人称为“电脑鼠”,将电脑鼠放入迷宫并启动操作的人称为“操作员”。
电脑鼠的基本功能是从起点开始走到终点,这个过程称为一次“运行”,所花费的时间称为“运行时间”。从终点回到起点所花费的时间不计算在运行时间内。从电脑鼠的第一次激活到每次运行开始,这段期间所花费的时间称为“迷宫时间”。如果电脑鼠在比赛时需要手动辅助,这个动作称为“碰触”。竞赛使用这三个参数,从速度﹑求解迷宫的效率和电脑鼠的可靠性三个方面来进行评分。器人称为“电脑鼠”,将电脑鼠放入迷宫并启动操作的人称为“操作员”。
在G02小组的工作中,基本完成了电脑鼠的驱动部分和算法部分:电脑鼠可以进行直线行走、90度左转、90度右转和180度后转;能准确监测左前右三个方向的挡板,能准确判断左右间距是否恰当;能进行调距运动,以保持与左右挡板的距离;能简单判断通路,并计算记忆合适通路;并按照通路完成迷宫行走。
但是,由于某些原因,小车的没有取得完美的效果:由于电机转速控制不当,小车直线行走效果不佳(参看第条);左转右转不够准确,只能依靠调整函数补偿;算法不够优秀,正在探究更好的算法。这些问题都在努力克服中,我们不会因为检查完毕就放弃小车的调试。
三、              项目整体结构:
MicroMouse102 电脑老鼠,采用美国LuminaryMicro 公司生产的32 位ARM CortexM3处理器LM3S102,控制和检测红外传感器;主CPU 根据检测到的传感信号,控制电机驱动电路调整行走路径,直到到达终点。
四、              硬件部分介绍:
LED 电路
电脑鼠有5 个独立的LED,通过LM3S 系统单片机的GPIO 口直接控制,如图 1.6 所示。电路采用了I/O 口灌电流的驱动方式来驱动LEDLM3S 系统单片机的灌电流为28mA(可配置),所以不需要驱动就可以点亮LEDGPIO 引脚输出高电平时LED 熄灭,低电平时LED 点亮。
电机驱动电路
电机采用直流减速电机,最高输出转速为800 /分钟,工作电压为DC3V。电机驱动
电路采用专用的单相直流电动机桥式驱动芯片。
车速检测电路
车速检测用于检测并记录车体运行的路径,通过车速检测记录车体做迷宫的坐标,同
时也起到控制车速和保持左右双轮的速度一致。
检测原理:在左轮和右轮的内则都贴有的光电码盘,码盘由两种颜色组成白色和黑色。
红外发射管安装在车轮光电检测码盘的检测区域,当红外发射与接收管正对着黑色边时,
红外线没有被反射,接收管的电阻很大;当红外发射与接收管正对着白色边时,红外线被
反射,接收管的电阻很小。
红外检测电路
红外检测电路是用于迷宫挡板的检测,分为左侧、右侧、前方三个方向,三个方向的
检测原理相同,某一个方向的检测电路。
CPU 及晶振电路
电脑鼠的单片机、晶体振荡器和LDO输出原理如图所示。该单片机选用LM3S102
微处理器。
五、              软件部分介绍:
一体化红外接收头工作原理
一体式红外线接收传感器IRM8601S,它内部集成自动增益控制电路、带通滤波电路、
解码电路及输出驱动电路。当连续收到38KHz 的红外线信号时,将产生脉宽10ms 左右的
低电平。如果没有收到信号,便立即输出高电平。Send 为发射控制端,高
电平时发射38KHz 的红外信号。Out 为接收输出端,低电平表示收到信号。
检测障碍物的软件设计
根据接收头是否检测到经过反射的红外线信号,就可以判断是否存在障碍物。由于接
收头检测到信号时只产生一个负脉冲,所以只需要在检测时使能红外线发射,一次检测结
束后使能无效,程序设计参考流程图如图2.5 所示。
接收头有一定的
响应时间
开始发送38KHz
的红外线
迷宫挡板检测
调制信号产生
本设计中采用定时器1 产生38KHz 的调制信号,由PB5 输出,该端口连接到图2.3
Pulse 端口。在中断中翻转PB5 输出信号,所以要产生频率为f 的脉冲,定时器的频率
要为2f。在本设计中要产生38KHz 的频率,定时器中断频率为76KHz
程序清单 3.1 为定时器1 的初始化函数,程序清单 3.2 为中断服务函数,在这里翻转
PB5 口输出状态。
程序清单 3.1 定时器1 初始化
void PULSEIni(void)
{
GPIODirModeSet(GPIO_PORTB_BASE, SEND | PULSE, GPIO_DIR_MODE_OUT); // 设置为输
GPIOPinWrite( GPIO_PORTB_BASE,SEND | PULSE,0); // 红外线初始时停止发射
SysCtlPeripheralEnable( SYSCTL_PERIPH_TIMER1 ); // 使能定时器1 外设
TimerConfigure(TIMER1_BASE, TIMER_CFG_32_BIT_PER); // 设置定时器1 为周期触发
TimerLoadSet(TIMER1_BASE, TIMER_A, SysCtlClockGet()/76000); // 设置定时器装载值
TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
TimerEnable(TIMER1_BASE, TIMER_A);
IntEnable(INT_TIMER1A);
}
程序清单 3.2 定时器1 服务函数
void Timer1A_ISR(void)
{
TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT); // 清除定时器1 中断
GPIOPinWrite(GPIO_PORTB_BASE, PULSE,GPIOPinRead(GPIO_PORTB_BASE, PULSE) ^ PULSE);
// 翻转GPIO B5 端口
}
抗干扰处理
红外线在空气中传播和反射受外界的干扰,如果测量距离刚好处在能够检测到信号的
临界状态,保持距离不变,传感器输出信号也可能不确定。这样就需要在软件中进行抗干
扰处理。参考程序如程序清单3.3 所示。
程序清单3.3 抗干扰处理程序
GPIOPinWrite( GPIO_PORTB_BASE,SEND , SEND); // 发送脉冲
Delay(150); // 延时
for(i=0,j=0;i<10;i++) // 检测接收信号
{
if(GPIOPinRead(GPIO_PORTA_BASE, OUT_L)==0)
j++;
}
GPIOPinWrite( GPIO_PORTB_BASE,SEND , ~SEND); // 停止发送
if(j>5) // 左边存在挡板
{
}
else // 左边存在支路
{
}
3.1 为抗干扰程序在Micromouse 中运行后用逻辑分析仪抓到的波形图,Pulse
38KHz 的输出信号,Send 高电平有效,有效时发送红外线脉冲,OUT 为一体化接收头输
…… ……
出端,该图所示为接收头探测到障碍物,软件在Send 信号无效(下降沿)前完成检测OUT
输出信号,从图中可以看出,此时正处于OUT 有效信号的中间,所以软件里延时参数能
保证正确检测到信号。
3.1 传感器检测波形图
软件设计参考
为用一组红外实现两组参数(是否存在挡板和是否太接近挡板)的检测流程图。在Micromouse 中,用到了三组(左、前、右)反射式红外检测传感器,左边和右边的传感器各自都需要检测两组参数,而前方的传感器只需要探测有无挡板,存在挡板就必须根据策略转换行进方向,若不存在就可以继续前进。如图3.3 所示为Micromouse 红外检测的程序设计流程图。红外检测参考程序见程序清单 3.4 所示,该程序中使用了五个LED 用来指示传感器检测的状态,由于这几个LED 硬件上连接到JTAG,关于如何切换GPIOJTAG功能参见6 使用JTAG 引脚作GPIO
此频率仅作为参考,要根据实际检测距离来确定。结合可调电阻R1 变可以实现挡板和防碰撞的检测。
程序清单 3.4 Micromouse 红外检测函数(见附录)
电机的调速
电机的调速
直流电机的转速控制在本设计中通过PWM来控制,LM3S102 单片机则刚有两路PWM
输出,非常适合用于控制两个电机的转速。
两路PWM LM3S102 通用定时器0Timer0)的三种工作模式之一,16 PWM
式。该模式是将一个32 位的定时器,折分成两个16 位的定时器TimerA TimerB。这些
定时器为计数寄存器(GPTMTnR)递减计数,递减到0 时自动加载预装载值(GPTMTnILR)。
当然预装载值也是由用户设定,该直也就决定了定时周期,也即PWM 的输出周期。
当计数器的值与预装载值相等时,输出PWM 信号有效,当计数器的值与匹配寄存器
GPTMnMATCHR)的值相等时,输出PWM 信号失效。通过软件可以设定PWM 输的信
号有效和信号无效的电平状态。当GPTMCTL 寄存器的TnPWML 位值为0 时,信号有效
为高电平,信号无效为低电平;TnPWML 位值为1 时,则反之。如图 4.1 所示。
输出信号
计数
0x411A
0xC350
TnPWML=0
TnPWML=1
TnEN置位
GPTMTnR=GPTMnMR GPTMTnR=GPTMnMR
时间
4.1 16 PWM 模式输出
占空比的约定:占空比为在一个周期内,输出有信号有效电平占整个周期时间的比率。
在这里为以统一软件控制的约定,用户API 函数输入的占空比值越大,电机转速越快,正
向运行和反向运行都一样。
为了简化占空比输出的计算,将计数寄存器与匹配寄存器值相等时,输出的电平信号
为驱动电机的有效信号。例如将PWM 周期时间设定为60000 个时钟节拍,需要输出驱动
电机的占空比为75%,则设置匹配寄存器值为75*6000
由于电机的转向不一样,所以电机驱动的有效电平也需要调整,通过控制TnPWML
实现。
2 程序设计
Timer0 的两路16 定时器TimerA TimerB PWM 输出引脚分别为PB0 PB6PB0
PB6 分别控制左轮和右轮驱动器TA7291S IN1 引脚,而它们的IN2 引脚分别由GPIO
输出的PA4 PA5 控制。
左轮的控制函数如程序清单 4.1 所示。
该函数的第1 个参数sel 为选择轮子的控制方式:0 为停止,1 为轮子向前,2 为轮子
向后;percen 参数为占空比,其最大值为99,最小值为1,对于轮子的停止控制该参数无
效。
程序清单 4.1 左轮控制函数
void LeftWheelRun(int sel,unsigned char percen)
{
switch(sel)
{
/*轮子停止转动*/
case 0:
TimerDisable(TIMER0_BASE,TIMER_A); // 禁止定时器
GPIOPinWrite(GPIO_PORTA_BASE,LWC2,0xff); // 控制引脚输出高电平
GPIODirModeSet(GPIO_PORTB_BASE, LWC1, GPIO_DIR_MODE_OUT); // GPIO 输出
GPIOPinWrite(GPIO_PORTB_BASE,LWC1, 0xff); // GPIO 输出高电平
break;
/*左轮向前*/
case 1:
GPIOPinWrite(GPIO_PORTA_BASE,LWC2, 0xff); // PA4 输出高电平
TimerControlLevel(TIMER0_BASE,TIMER_A,true); // PWM 有效电平方向
GPIODirModeSet(GPIO_PORTB_BASE, LWC1, GPIO_DIR_MODE_HW); // PWM 输出
TimerMatchSet(TIMER0_BASE,TIMER_A,percen*600); // 设置占空比
TimerEnable(TIMER0_BASE,TIMER_A); // 使能定时器
break;
/*左轮向后*/
case 2:
GPIOPinWrite(GPIO_PORTA_BASE,LWC2, 0); // PA4 输出低电平
TimerControlLevel(TIMER0_BASE,TIMER_A,false); // PWM 有效电平方向
GPIODirModeSet(GPIO_PORTB_BASE, LWC1, GPIO_DIR_MODE_HW); // PWM 输出
TimerMatchSet(TIMER0_BASE,TIMER_A,percen*600); // 设置占空比
TimerEnable(TIMER0_BASE,TIMER_A); // 使能定时器
break;
}
}
右轮的控制函数如程序清单 4.2 所示。
该函数的第1 个参数sel 为选择轮子的控制方式:0 为停止,1 为轮子向前,2 为轮子
向后;percen 参数为占空比,其最大值为99,最小值为1,对于轮子的停止控制该参数无
效。
程序清单 4.2 右轮控制函数
void RightWheelRun(int sel,unsigned char percen)
{
switch(sel)
{
/*轮子停止转动*/
case 0:
TimerDisable(TIMER0_BASE,TIMER_B); // 禁止定时器
GPIOPinWrite(GPIO_PORTA_BASE,RWC2,0xff); // 控制引脚输出高电平
GPIODirModeSet(GPIO_PORTB_BASE, RWC1, GPIO_DIR_MODE_OUT); // GPIO 输出
GPIOPinWrite(GPIO_PORTB_BASE,RWC1,0xff); // GPIO 输出高电平
break;
/*右轮向后*/
case 2:
GPIOPinWrite(GPIO_PORTA_BASE,RWC2, 0xff); // PA4 输出高电平
TimerControlLevel(TIMER0_BASE,TIMER_B,true); // PWM 有效电平方向
GPIODirModeSet(GPIO_PORTB_BASE, RWC1, GPIO_DIR_MODE_HW); // PWM 输出
TimerMatchSet(TIMER0_BASE,TIMER_B,percen*600); // 设置占空比
TimerEnable(TIMER0_BASE,TIMER_B); // 使能定时器
break;
/*右轮向前*/
case 1:
GPIOPinWrite(GPIO_PORTA_BASE,RWC2, 0); // PA4 输出低电平
TimerControlLevel(TIMER0_BASE,TIMER_B,false); // PWM 有效电平方向
GPIODirModeSet(GPIO_PORTB_BASE, RWC1, GPIO_DIR_MODE_HW); // PWM 输出
TimerMatchSet(TIMER0_BASE,TIMER_B,percen*600); // 设置占空比
TimerEnable(TIMER0_BASE,TIMER_B); // 使能定时器
break;
}
}
需要注意的是,当PWM 信号禁止后,其输出引脚的电平状态是保持静止时的状态(可
能为低电平也可能为高电平),导致电机可能不能停止,所以在制停电机时,需要将PWM
引脚改为GPIO 输出,并且出高电平,使电机刹车停止。
定时器PWM 初始化函数如程序清单 4.3 所示。
程序清单 4.3 定时器PWM 初始化
void PWMTimer0AIni(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // 使能定时器0
GPIODirModeSet(GPIO_PORTB_BASE, LWC1|RWC1 , GPIO_DIR_MODE_OUT);
/* 控制引脚输出*/
GPIOPinWrite(GPIO_PORTB_BASE, LWC1|RWC1 , 0xff); // GPIO 输出高电
GPIODirModeSet(GPIO_PORTA_BASE, LWC2|RWC2 , GPIO_DIR_MODE_OUT); // 控制引脚输出
GPIOPinWrite(GPIO_PORTA_BASE, LWC2|RWC2 , 0xff); // GPIO 输出高电
/* 定时器配置*/
TimerConfigure(TIMER0_BASE,TIMER_CFG_16_BIT_PAIR
|TIMER_CFG_A_PWM|TIMER_CFG_B_PWM); // 16 PWM 输出
TimerControlLevel(TIMER0_BASE,TIMER_A,false); //有效信号为低电
TimerControlLevel(TIMER0_BASE,TIMER_B,false);
TimerLoadSet(TIMER0_BASE,TIMER_A,60000); // 设定PWM 频率
TimerLoadSet(TIMER0_BASE,TIMER_B,60000);
}
Micromouse 车速检测
车速检测程序设计
本设计中选用了LM3S102 PA0 PB1 分别检测左轮和右轮的下降沿的脉冲个数,
为了快速向应检测信号,使用了下降沿触发中断。LM3S102 单片机的特点,任何一个GPIO
引脚都可以配置为中断输入,并且可以作任意设定为高电平触发、低电平触发、下降沿触
发、上升沿触发和上升或下降沿触发5 种模式。本应用中使用下降沿触发,其初始化如程
序清单 5.1 所示。
程序清单 5.1 轮子脉冲检测初始化
void WheelPulseIni(void)
{
// 配置引脚为输入
GPIODirModeSet(GPIO_PORTA_BASE, PULSE_R, GPIO_DIR_MODE_IN);
GPIODirModeSet(GPIO_PORTB_BASE, PULSE_L, GPIO_DIR_MODE_IN);
// 配置引脚下降沿触发中断
GPIOIntTypeSet(GPIO_PORTA_BASE,PULSE_R,GPIO_FALLING_EDGE);
GPIOIntTypeSet(GPIO_PORTB_BASE,PULSE_L,GPIO_FALLING_EDGE);
// 使能引脚输入中断
GPIOPinIntEnable(GPIO_PORTA_BASE,PULSE_R);
GPIOPinIntEnable(GPIO_PORTB_BASE,PULSE_L);
// 使能GPIO PA 口和GPIO PB 口中断
IntEnable(INT_GPIOA);
IntEnable(INT_GPIOB);
}
左右轮检测脉冲中断处函数如程序清单 5.2 所示。
程序清单 5.2 左右轮检测脉冲中断处函数
//------------------------------------------------------------------------------------
// 函数名称: GPIO_Port_A_ISR
// 函数功能: 右轮检测脉冲中断处函数
//------------------------------------------------------------------------------------
void GPIO_Port_A_ISR (void)
{
unsigned char IntStatus;
IntStatus = GPIOPinIntStatus(GPIO_PORTA_BASE,true); // PA 口中断状态
if(IntStatus&PULSE_R) // 是否为左轮脉冲中断
{
PulCount_R++;
if(PulCount_R >= RightPulse)
{
RightWheelRun(0, 1);
WheelStop_R= 1;
}
GPIOPinIntClear(GPIO_PORTA_BASE,PULSE_R); // 清中断
}
}
//------------------------------------------------------------------------------------
// 函数名称: GPIO_Port_B_ISR
// 函数功能: 左轮检测脉冲中断处函数
//------------------------------------------------------------------------------------
void GPIO_Port_B_ISR (void)
{
unsigned char IntStatus;
IntStatus = GPIOPinIntStatus(GPIO_PORTB_BASE,true); // PA 口中断状态
if(IntStatus&PULSE_L) // 是否为右轮脉冲中断
{
PulCount_L++;
if(PulCount_L>= LeftPulse)
{
WheelStop_L= 1;
LeftWheelRun(0, 1);
}
GPIOPinIntClear(GPIO_PORTB_BASE,PULSE_L); // 清中断
}
}
六、              系统DV:参看附件:
a)       直线行走3格+右转:
该运动中,小车首先直线行走3格(50CM),然后右转,并在碰到障碍物后右转,直线行走一格,再右转一次;
b)       围绕小桌运动:
该运动中,小车围绕方形小桌绕圈,判断安全距离、检测是否存在通路,并自动修正方向。
七、              测试情况:
经检测,小车能较好的完成给定的运行任务,较为准确地直走、左右转,及180度转。小车完全可以完成探究迷宫、自动寻路等任务,并以较短的时间完成迷宫行走。
但是,小车依旧存在些问题:直走中有摆动现象,左右转也做不到90度(大概85度到95度之间),180度更不好;算法不够优秀,时间依旧较长。虽然这些问题更为琐碎更为难处理,但我们有信心,暑假间会完全克服。
八、       曾遇到的问题:
1.车轮行进速度不一:
       同一函数中,小车的左右转速相差比较大,我们尝试采取了以下几种方式解决
       1)。调占空比:无效,原因不明。在与别的小组交流之后,我们尝试改写了原先的驱动函数,使速度函数与正反转函数区分开:

(原函数 & 改进后的函数 请见附录)

还不太明白是为什么,把两个函数分开写了之后,发现有一定效果。

       2)。脉冲补偿:
       这也是演示程序的方法,在执行完一次运行任务之后,把相差的脉冲补偿到下一次任务的设定中:

       PWMTimer0AIni();                            // PWM初始化
       PULSEIni();                               // 调制信号初始化
       WheelPulseIni();                         // 测速初始化
       while(1)
       {
            LeftPulse = 10;                           // 设定电机运行任务
            RightPulse = 10;
            WheelStop_L = 0;                       // 清零电机停止标志位
            WheelStop_R = 0;
            LeftWheelRun(1, 99);                  // 启动左右电机
            RightWheelRun(1, 99);
            while(!(WheelStop_L && WheelStop_R))// 等待运行结束,状态在中断中改变
                    Check_Infrared(0);               // 等待过程中进行红外检测
            PulCount_L -= LeftPulse;                    // 误差补偿到下一次运动中
            PulCount_R -= RightPulse;   
       }

       想法很好,实际行不通。
       以最低误差来算,假设左轮10个脉冲,右轮9个,小车明显走出一条弧线;而当下次补偿到下次之中时,小车还是先走同样的路程,然后左轮停转,右轮转2个脉冲(上次误差+ 这次误差),表现出了明显的“一瘸一拐”的情况;而且,在我们的调试过程中,出现了不稳定的左右摆动,这是由于“半个脉冲”的问题,小车不能有效识别比较小的距离差,在最好的状态下,小车也存在计数的问题,比如,左轮刚转就开始向下的触发,右轮快转一圈才有第一次的向下触发。而且,这种误差是随机的,与小车车轮的起始位置有关,不好避免。
      
       3.从硬件下手:
       在左右电机同加固定电压时,清楚地看到转速不一样,因此,最好的办法还是从硬件上下手,通过串联电阻来解决问题。这是我们的一个想法,还没开始实施,准备在暑假时再想想软件解决办法,不行就改电路。(电机内阻,运行时电流)

2。检测信号的波形:
       受灯光的影响,可以看到,红外接受得到的波形不时很好。检测初速的还好,因为幅度比较大,所以没有误判的问题;检测挡板的波形振动比较大。按照电路图,尝试着变换的电阻,取得不错的效果,以下函数足够完成判断:

源程序详见附录)
              
3。编译器的问题:
       大量铁的事实证明,crosswork不好用,推荐使用Keil for ARM。前期使用的是crosswork,很多不明就里的问题,换到Keil for ARM就解决了,说明crosswork对小车的支持不够好。很多函数,在crosswork上,完全起不到效果,跑出来都知道是怎么回事。我们不是在责怪crosswork不好,但至少说明,不易于上手。
       总结了一些发现的问题:
       1)。不能出现汉字:还好,无非就是存盘载入时麻烦点。
       2)。只能装C盘:刚开始装在D盘,整天蓝屏。
       3)。头文件载入:很多头文件需要手动一一载入,还是查百度知道的,说明文件上没有。
       4)。编译显示错误,不显示为什么错:开始时,发现错误就在Keil上找错。。。。。。
       5)。脱机运行问题:想脱机运行?需要改很多。。。。。。
       因此,不推荐用crosswork


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:135654 发表于 2016-8-1 10:27 | 只看该作者
正好在做红外的东西,过来学习一下
回复

使用道具 举报

板凳
ID:146651 发表于 2016-11-8 07:59 | 只看该作者
总算看到一个走迷宫的电子鼠程序,虽然不完整,不过也体现了楼主探究的过程,做好了这个电子鼠,一般的避障寻迹都能解决了。多谢楼主分享,认真学习了。
回复

使用道具 举报

地板
ID:500406 发表于 2019-3-29 10:03
毕设是小车走迷宫  大大 您这边资料还全吗 有的话随时联系我QQ:3380486884

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表