科技创新3 -小车自动走迷宫G03组

 

小组组成

项目简介

完成情况

硬件介绍

软件介绍

经验心得

照片视频

文件下载

联系我们

小组组成:

 

从左至右:

助教之一

陈其洲:组长,主要负责编写小车的驱动程序和小组的分工等。

王驰:主要负责小车的实地调试工作。

吴凤刚:主要负责走迷宫的算法,编写小车运行的模拟程序。        

(back)

 

 

 

小车自动走迷宫项目简介:

本项目是以“IEEE标准电脑鼠走迷宫”邀请赛(长三角地区)为背景设立的,采用美国LuminaryMicro公司生产的32位ARM CortexM3处理器LM3S102(datasheet下载),控制和检测红外传感器,主CPU 根据检测到的传感信号,控制电机驱动电路调整行走路径,直到到达终点,走出迷宫。

(back)

 

项目完成情况:

我们将整个项目分成三个阶段,如下

至最后验收,我们完成了前两个阶段的工作,最后由于小车调试的并非太理想,没有将完整的算法(小车模拟的算法)移植到单片机中,只是写了个简单的右手法则走出迷宫。

(back)

 

硬件部分介绍:

1.硬件原理图:

2.原理图主要部分介绍:

(1)电机驱动电路

电机采用直流减速电机,最高输出转速为800 转/分钟,工作电压为DC3V。电机驱动
电路采用专用的单相直流电动机桥式驱动芯片TA7291S(
datasheet下载),

电机驱动电路

  TA7291S 是TOSHIBA 公司生产的单相直流电动机桥式驱动芯片,工作电压4~20 伏,
最大输出电流400mA。电动机驱动由输入端IN1 和IN2 控制,控制方法如下表 所示。

                                  表:电机控制

(2)车速检测电路

车速检测用于检测并记录车体运行的路径,通过车速检测记录车体做迷宫的坐标,同
时也起到控制车速和保持左右双轮的速度一致。
检测原理:在左轮和右轮的内则都贴有的光电码盘,码盘由两种颜色组成白色和黑色。
红外发射管安装在车轮光电检测码盘的检测区域,当红外发射与接收管正对着黑色边时,
红外线没有被反射,接收管的电阻很大;当红外发射与接收管正对着白色边时,红外线被
反射,接收管的电阻很小。检测电路如下图 所示。

                          车速检测电路

  在图 1.9 的检测电路中,红外发射与接收管正对着黑色边时,PULSE 输出高电平;正
对着白色边时,PULSE 输出低电平;从黑色边到白色边,PULSE 输出一个下降沿信号;
从白色边到黑色边,PULSE 则输出一个上升沿信号。
LM3S102 单片机可以检测输出脉冲的下降沿信号判断车轮转到的角速度,当检测到
13 个下降沿信号时,轮子转动了一圈。

(3)红外检测电路
  红外检测电路是用于迷宫挡板的检测,分为左侧、右侧、前方三个方向,三个方向的
检测原理相同,某一个方向的检测电路如下图所示。

                              红外检测电路

  一体式红外线接收传感器IRM8601S(datasheet下载),它内部集成自动增益控制电路、带通滤波电路、解码电路及输出驱动电路。当连续收到38KHz 的红外线信号时,将产生脉宽10ms 左右的低电平。如果没有收到信号,便立即输出高电平。如图2.4 所示,Send 为发射控制端,高电平时发射38KHz 的红外信号。Out 为接收输出端,低电平表示收到信号。
R16 为发射端的限流电阻,起保护Q3 管作用;R28 为接收端的限流电阻,防止过大
的I/O 端口电压,起保护LM3S 系统单片机的I/O 口作用。

 

 

(back)

 

 

 

 

软件部分介绍:

 

 

一、检测障碍物的软件设计

根据接收头是否检测到经过反射的红外线信号,就可以判断是否存在障碍物。由于接
收头检测到信号时只产生一个负脉冲,所以只需要在检测时使能红外线发射,一次检测结
束后使能无效,程序设计参考流程图如图2.5 所示。

 

二、模拟程序的设计

 1、基本思路

编写模拟程序的出发点是在没有硬件的情况下,模拟出小车走迷宫的环境,然后探索一种能让小车走出迷宫的算法。这项工作与小车的硬件调试同时进行,为整个小车走迷宫的任务做先期准备。

 

基本思路如下:

(1)  图形库CS111的利用。

使用Visual Studio中的图形库CS111(须另外安装),可以使虚拟的小车走迷宫可视化,其一可以加快程序编写的效率,其二可以作为以后实际调试车子的参考。

 

(2)  关于迷宫。

有两种属性不同的迷宫,一个是模拟的客观迷宫,另外一个是随着小车的探测,储存在小鼠内存中的迷宫。

前者以txt文档存储客观迷宫信息。

例如,右图的迷宫,可以表示为

 

C6C2

5596

5DA3

19A2                               

                                                      迷宫示例

4*4的迷宫,可表示为一个4*4 数组,数组元素为一个16进制数。

左上角的(C16= 11002,表示迷宫左上角的格子按ESWN,逆时针的顺序为(有墙,有墙,无墙,无墙)的状态。

 

小鼠内存中的迷宫,也为类似的4*4结构,初始设为全0,即未经探测的方格设为四面均不通。

 

(3)  主函数执行过程。

A. 读迷宫数据              bool GetMaze(int*mazeData)

B. 画出迷宫                void DrawMaze()

C. 初探迷宫的算法          void Go(int x1,int y1,int x2,int y2,int d)

D.往返探测

E. 图形补全,计算最佳路径  void DataRefresh()

F. 小车最后一次行走

 

4、小车的遍历过程为右手定则,即小车遇过分岔路口,按照“右,中,左”的顺序行进探测。

 

5、模拟算法的演示程序下载,exe文件,txt文件(注:txt文件中存储了迷宫信息,两个文件下载到同一文件夹下双击exe文件观看演示)

 

三、小车驱动程序

基本以模拟程序的算法编写小车程序。但有些细节的问题,还是要想一些特殊的算法来解决

1、左右以及车头发射红外的占空比

在检测小车周围挡板情况时,首先检测车头是不是已经歪了,是不是离左边或右边挡板太近,然后检测左右有没有路可以走。这两次检测所发射的红外是不同的,前者的占空比较小,只能检测到较近距离的挡板;后者的占空比较大,可以检测到较远的挡板。

首先是左右近距占空比的设置,一开始设的很小,当小车靠挡板很近时才有反应。这样即使已经将车头调整到与挡板平行,还是会测到近距挡板,结果是继续向反方向调整直到车头偏向另一方向。所以一开始走出来的是斜向左和斜向右交替的情况,走成一条折线。这样的不良影响是当到达路口需要转弯时,车头是歪的,转过90度后可能会撞到拐角。如下图(1)所示:

      

        图(1                    图(2

解决方法是加大近距红外的占空比,当小车稍微有一点偏时就进行调整,这样避免了调整过大,而且将小车限制在两挡板间很窄的路径里,可以近似认为走的是直线。实际观察结果也正是如此。

还有就时车头红外,当小车倾斜的角度较大时,会错将左右的挡板误认为是前方挡板,从而进行后转,打乱了小车的行进路线。如图(2)所示。

解决方法是在Check_Infrared函数中添加一个前方的近距红外检测(在函数中反映为option7),在检测到前方远距后再检测前方近距,若近距也检测到挡板,则认为前方其实并无挡板,只是小车倾斜造成的影响。

if(option==7)

              //; //近距  前方有挡板0x**1**

       {

       Setduration(10);                                              //先将占空比调低

       TimerEnable(TIMER0_BASE,TIMER_B);           //send

           Delay(150);

           for(i=0,j=0;i<10;i++)

           {p; {

               if(GPIOPinRead(GPIO_PORTA_BASE, OUT_F)==0)

                   j++;j++;

           }

              TimerDisable(TIMER0_BASE,TIMER_B);          //not send          

              if(j>5)                                // 前面近距有挡板

           {

                     if(option==0||option == 2)

                            State |= 1 << 8;; 8;

                     GPIOPinWrite(GPIO_PORTC_BASE, DF, 0);

                    

           }p; }p; }

           Else                                  // 前面近距没有挡板

           {

                     if(option==0||option == 2)

                            State |= 0 << 8;; 8;

                     GPIOPinWrite(GPIO_PORTC_BASE, DF, DF);

                    

           }p; }p; }

           Setduration(30);            //将占空比调整回去,以备后面检测

           return State;

       }

 

2、小车在行进过程中被卡住的解决

小车在走迷宫的过程中并不能像上述的那样不发生偏移,由于一些偶然因素产生的影响可能会使小车有很大的偏转角度,甚至会撞到挡板上,如果这个时候不是处在检测调整阶段,那样小车就会卡在那里。考虑到这种情况在调试过程中发生的频率之高,已经不能将它看作偶然事件,这样的话是不可能走出迷宫的。

解决该问题的基本思想:加入一个看门狗程序,在每次小车运动时调用(包括转弯,调整等)。考虑到卡住分为前面卡住和后面卡住两种情况,设两个全局变量dog1,dog2。左轮或右轮每转动一格时将全局变量dog1,dog2清零,如果两个轮子都停止就开始先对dog1进行加一计数,当记到预设值时(通常预设值较大),说明轮子很久不转,小车一定是被卡住了。然后就要进行调整,先将小车向后退。若轮子不转,就对dog2加一计数,当达到预设值时,说明无法后退,是后面被卡住,就将小车向前进。以下是程序代码:

void dbldog(){

       dog1++;

       if(dog1>60000){

              LeftPulse = 1;                                                               

              RightPulse = 1;

              PulCount_L = 0;

              PulCount_R = 0;

 

              WheelStop_L = 0;                                                          

              WheelStop_R = 0;

             

              LeftWheel(1);                                                 

              RightWheel(1);                                                                                     

              while(!(WheelStop_L && WheelStop_R)){

                     dog2++;

                     if(dog2>60000){

                            LeftPulse = 1;                     

                            RightPulse = 1;

                            PulCount_L = 0;

                            PulCount_R = 0;

 

                           WheelStop_L=0;                                                                 

                            WheelStop_R = 0;

             

                            LeftWheel(2);                                                        

                            RightWheel(2);                                                                                            

                            while(!(WheelStop_L && WheelStop_R)){}

             

                     }                                        sp;

              }

 

       }

 

}

 

 

(back)

 

 

 

经验及改进建议:

 

车轮码盘的改进和红外的调试

陈其洲

 

 

小车车轮码盘改进方案:

小车最初的码盘是纸制的,为黑白相间,一共24格。理论上,当红外照射白色部分时,红外反射,由红外接收管接收到红外线形成低电平;当照射到黑色部分时,红外吸收,形成高电平。然后,在实际应用过程中,由于码盘是打印的,黑色的吸收红外的效果并非很理想,导致我们想得到的高电平实际上并不一定是高电平。这就直接导致我们通过在数脉冲个数时常常漏数。这是非常致命的,因为如果一边多走几格就会导致最后车停的方向与前方会成一个比较大的角度,非常不利于调试。

由于黑色的吸收红外效果非常不理想,我想到将黑色用镂空的方式代替,这样,当红外线通过镂空部分就直接射出并不反射。起初,可以说我们想出的这种采用纸镂空的码盘效果非常理想,小车在数脉冲方面的问题几乎得到了完美的解决,然而在我们兴奋了一段时间之后,突然发现原本走的好好的车又开始行走不正了。我的第一反映便是码盘。码盘毕竟是用纸做的,本来就容易在告诉旋转很长时间后出现位置的不正,加上镂空处理后,其中有一个辐条还出现了断裂,纸也不能正对红外,这时的红外检测波形出现了严重的变形。后来,我想到用金属材料制作码盘,我选了易拉罐,因为在只有剪刀的情况下,易拉罐比较好剪,尽管这个还是会有很大问题 。易拉罐的好处有很多,首先金属材料相对纸来说不易变形,另外,易拉罐内侧的表面反射红外效果非常好,从示波器我们可以看到 。

  

                    码盘设计                                         示波器波形

   另外,现在轮子转一圈是12个脉冲,为了提高精度,我们想到了几种方法:一种方法是我们在得到测车轮脉冲的信号后将单边触发改为双边触发,这样理论上精度可以提高一倍。然而我们最后并没有采用这种方法,理由是码盘是我们自己剪的,自己剪的一个很大的问题是间隔不能做到均匀,这样双边触发就失去他本身的意义了。因为两个触发之间车轮转过的角度不一样。不过如果能让工厂通过激光或其他手段制作出来,效果应该是非常理想的。另外一种方法是我们可以增加格子数量,尽管不能向第一中方法那样大幅度提高精度,但是如果两种方法结合的话,精度提高也是非常明显的。但是这种方法不能任意多的增加格子数,因为经过测试,随着格子数的增加,红外的分辨能力下降,我们初步测了下,在改为28格子后,效果依然能够接受。当然,这样使我们剪码盘的时候带来更高的要求。

关于红外

  当时我们拿到小车时,有一个红外发射管是坏的,肉眼又辨别不出来,如果不注意会给调试带来很多问题。不过我们可以用摄像头来观察红外管,如果红外管正常工作,我们可以看到白光 。这种方法在有关红外问题上非常简便可行(如果手机有摄像头的话)。

    关于红外的另外一个问题可能是当时画硬件pcb板的人没有注意到,左边的车轮红外检测电路红外发射管在内侧,接收管在外侧。由于越接近电机的轴,码盘的间隔越小,这样会导致分辨率明显下降,在转数很快的时候很容易导致漏数,因此,我们将他改成发射管在外侧,接收管在内侧。

 

 

 

小车走迷宫模拟程序的几个问题

吴凤刚

 

1、数组与迷宫的坐标的出入

起初利用txt文本录入迷宫数组数据时,按照人们习惯的坐标,第一行左数第二条格子为  23),但用嵌套for循环后,对应该格的i = 1,j = 2.因此,在调试程序时,一度使画出的效果与预期的效果有很大出入。因此也可作为一条经验,若其他组在编写算法时,采取与我们组相似的内存约定,可以先用一下坐标转换,使各个表现形式的迷宫形式统一,少走弯路。

 

2、  关于右手定则

右手并不是一定能走出迷宫。对于有“回”字形回路的迷宫,小车将一直绕着走下去。因此我们假定迷宫没有这样的回路。

 

3、迷宫的规格

可以利用

# define N 4

来统一规定迷宫边长N的大小。因为小的迷宫(如4*4)的可使编程调试简单化,当4*4的迷宫功能完全实现之后,我们再开始任务要求的16*16的迷宫调试,会提高效率。

 

3、  关于数据补全

对于还没探测到的格子,可以进行数据补全。对于一个特定的格子,可以访问与其相临的格子,若与其相关的墙壁为0,可大胆进行阻断。

 

 

 

实地调试经验与收获 

 王驰

一、关于小车行进的稳定性问题

    最早我们的想法是让小车一直不停地走,同时不断调用Check_Infrared函数来检测周围挡板情况,遇到路口或障碍物时做相应调整。但由于小车的两个轮子走的不够稳定,很难走成直线,这样会给小车走的过程带来很多不确定因素。后来编写了Adjust函数用来调整小车走直线,又因为小车的速度相对于迷宫的大小来说比较快,在考虑惯性问题时很难把握,因此在刚开始调试时出现了很大障碍:就时一些子函数在走的过程中未能及时调用,最终造成小车状态难以确定。

    后来,我们想到让小车每走一个脉冲数停一下,然后调用Check_Infrared检测挡板,需要进行调整时做相应调整,然后重复以上步骤。由于一个脉冲数小车走过的距离很短,通常还没有达到应有的最大速度,因而受惯性的影响较小,而且每次调整(包括转弯和调整车头角度)都是在小车已经停下的情况下进行的,这样一来就减少了很多不确定的因素,比如小车此时的速度之类的。

    每次步进间隔的时间可以调整,调试过程中为了便于准确观察小车状态,将间隔时间设的很大,走的比较“丑陋”,之后只要把间隔时间合适设置后,小车可以走的像连续行进一样。

 

二、关于左右轮不同步的问题

    软件调试过程中受硬件问题的困扰很多,其中最大的一个问题就是左右轮子不同步:由于左右轮码盘和发射与接受红外的不同,导致两个轮子在设置相同脉冲数后走的步数不同,进而导致轮子无法走出直线。具体情况见陈其洲总结的第一段。

    在经过对码盘和红外的改造后,两个轮子在走一定脉冲数后产生的差异以及由此导致其偏转的角度已经很小。但是Turn,Adjust,move这三个函数本身设置的脉冲数就比较小,这样即使产生一个格子的误差影响也是很大的。

    后经过我们检测,左轮脉冲的计数基本正常,而右轮脉冲会有漏数现象。因为右轮漏数脉冲,必然导致它会比左轮多走几格,这样,就在左轮走完的同时将右轮也停下来。

    具体方法,改变左右轮脉冲控制函数的执行部分,即当任一个轮子的脉冲计数达到设定值后,就将两个轮子都停止,并将置电机停止标志。(黑体部分)

void GPIO_Port_A_ISR(void)

{

       unsigned char  IntStatus;

       dog1 = 0;

       dog2 = 0;

       IntStatus = GPIOPinIntStatus(GPIO_PORTA_BASE,true); // PA口中断状态

       if(IntStatus&PULSE_R)                         // 是否为左轮脉冲中断

       {

              PulCount_R++;                                              // 脉冲计数

 

              if(PulCount_R >= RightPulse)                      // 判断是否达到设定值

              {

                     LeftWheel(0);

                     RightWheel(0);

                     WheelStop_L= 1;

                     WheelStop_R= 1;                                   // 置电机停止标志

              }

              GPIOPinIntClear(GPIO_PORTA_BASE,PULSE_R);           // 清中断

       }

}

 

void GPIO_Port_B_ISR(void)

{

       unsigned char IntStatus;

       dog1 = 0;

       dog2 = 0;

 

       IntStatus = GPIOPinIntStatus(GPIO_PORTB_BASE,true); // PA口中断状态

       if(IntStatus&PULSE_L)                               // 是否为右轮脉冲中断

       {

              PulCount_L++;                                     // 脉冲计数

 

              if(PulCount_L>= LeftPulse)                      // 判断是否达到设定值

              {

 

                     LeftWheel(0);

                     RightWheel(0);

                     WheelStop_L= 1;

                     WheelStop_R= 1;                   // 置电机停止标志

                    

              }

             GPIOPinIntClear(GPIO_PORTB_BASE,PULSE_L);           // 清中断

       }

}    

 

 

三、连续转弯时的步进问题

 左右的红外发射与接收都是在车头的地方,当检测到左边或右边有路可走时,需要先向先继续步进(称为前步进),当小车完全处于拐弯口时再转弯;转弯后小车一般还需要向前步进(称为后步进),以避免继续检测造成多余的转弯。通过move函数实现:

void move()

{

   LeftPulse = 6;                                                                      

  RightPulse = 6;

  PulCount_L = 0;

  PulCount_R = 0;

  WheelStop_L = 0;                                                                 

  WheelStop_R = 0;

  LeftWheel(2);                                                 

  RightWheel(2);                                                              

  while(!(WheelStop_L && WheelStop_R)){

  dbldog();                

}

但是当连续两次转弯时,第一次的后步进和第二次的前步进重复,小车的多余步进使得其驶出拐弯口,第二次转弯无法正常进行。

解决方法:设置标志位count,记录前一次小车的运动状态。每次走直道时将count清零,而每次转弯时将count置一。需要转弯时先判断标志位。若count=0,则先调用一次move,否则不需要调用。

 Ps:在一开始研究小车连续走的时候,我们使用了反转制动。即将停机时的LeftWheel(0)RightWheel(0)改为LeftWheel(1)RightWheel(1),发现这样的制动效果很好,轮子停的很快。但后来的小车行进方式变为单步,这个方法就不需要了。但如果以后的小组的硬件条件足够好,小车可以较稳定地连续走时,可以考虑使用上述方法制动。

 

(back)

 

 

小车照片与视频:

 

                    小车外观照片                                      模拟程序运行照片

                       小车行走视频

(back)

 

相关文件下载:

KeilForArm

Keil uv3快速入门

Stellaris驱动库用户指南

MiroMouse102用户手册

源代码及hex文件下载

报告下载

(back)

 

 

 

联系我们:

姓名

学院

班级

电子邮箱

陈其洲

电子信息与电气工程学院

F0603008

cqz524@sjtu.edu.cn

王驰

电子信息与电气工程学院

F0603007

likeaperson@163.com

吴凤刚

电子信息与电气工程学院

F0603005

wfg7530@sjtu.edu.cn

(back)