×
嵌入式 > 技术百科 > 详情

飞思卡尔那些事之离散型光电管路径识别

发布时间:2020-06-16 发布时间:
|
光电管路径识别算法
资源:
1、红外光电发射接收管
2、电压比较器
3、HCS12的IO口
4、HCS12的ATD模块
5、HCS12的ECT模块
原理:
1、红外发射管,将红外线信号发射出去,当遇到遮挡物是,会反射回来。如果当部分为黑色时,则不会发射回来(黑色能吸收光线,红外线在遇到黑色遮挡物时,被吸收)。接收管在接收到反射的红外线时,其两端的电阻发生变化,从而可以输出不同的电压值,最后根据这些电压值来识别路径。
2、电压比较器能将连续量转变成开关量,在大于设定的阈值时,输出高电平,小于设定的阈值时,则输出低电平。
3、ADC能将模拟量转换成计算机可以识别的数字量,可是自己对这些数字信号进行处理,对路径信息进行识别。
方案:
1、离散型路径识别算法。
将红外接收管输出的电压信号通过电压比较器进行电压比较,输出一个开关量,HCS12的IO读取电压比较器输出的开关量。安装若干个光电管排成一排,并且同时读取信息,当与发射管连接的IO口输入一个0值时,则判断黑色轨道在该光电接收管下,通过一定的算法即可求出黑色轨道和小车的偏移角度。
优点:简单易行。
缺点:
   a.存在检测盲区,即在接收管之间的区域。
   b.道路信息为离散值,通过道路信息经过控制算法得到的控制信息为阶跃的而非连续的控制量,这对小车的稳定影响。
2、连续型路径识别算法。
将红外接收管输出的电压信号经过AD转换,等到数字量的的电压信号。通过对这些数字亮的处理可以得到近似于连续的道路信息。
优点:路径信息为连续,路径信息更加精确。
缺点:
  a.数据处理算法实现较为困难。
  b.因为光电接收管本身参数的不同,在同样条件下,输出的电压可能有所不同,这对数字信号的处理带来难度。
方案选择:因为是初次接触路径识别算法,为了小车能稳定的行驶,于是选择了较为容易实现的离散路径识别算法。
说明:
1、光电接收管为16个,在离前轮Hmm的距离排成一排,同时检测道路信息,每个光电管之间的距离为15mm。
2、16个光电管分别和HCS12的PORTB口和PORTE口连接。
3、检测时间间隔为10MS。  
    车轮和接收管的车子垂直距离为500mm。
4、变量iRoutPlace存放路径信息。
5、数组iPLace存放路径位置。
6、数组iplaceAngle存放方向角度。
7、位置信息数据:
    当某位红外接收管检测到黑线时,则通过比较器,该位输出为0,未检测到的则为1。
  iPLace[28]={0x7fff,0x3fff,0xbfff,0x9fff,0xdfff,0xcfff,0xefff,
              0xf7ff,0xf3ff,0xfbff,0xf9ff,0xfdff,0xfcff,0xfeff,
              0xff7f,0xff3f,0xffbf,0xff9f,0xffdf,0xffcf,0xffef,
              0xfff7,0xfff3,0xfffb,0xfff9,0xfffd,0xfffc,0xfffe}
8、位置与偏移角的关系。
通过C程序计算出来。程序如下:
#include
#include
void main()
{
int i;
long double h,n;
n=0.0;
h=500.0;
for(i=0;i<16;i++)
{
  printf("%d--%lf--",i,atan((15.0*n)/h));
  printf("%lfn",((atan((15.0*n)/h))*180.0)/3.14);
  n++;
}
}
运行结果:
位置-弧度角--角度
0--0.000000--0.000000
1--0.029991--1.719230
2--0.059928--3.435372
3--0.089758--5.145373
4--0.119429--6.846244
5--0.148890--8.535093
6--0.178093--10.209149
7--0.206992--11.865795
8--0.235545--13.502579
9--0.263712--15.117239
10--0.291457--16.707714
11--0.318748--18.272153
12--0.345556--19.808919
13--0.371856--21.316590
14--0.397628--22.793961
15--0.422854--24.240034
通过上表可以近似为,每偏移一个位置,角度增加1°。
9、角度信息:
iplaceAngle[]={-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,5,5,6,7,8,9,10,11,12,13}

CODE:
#include       
#include     
#pragma LINK_INFO DERIVATIVE "mc9s12xs128"
//===========================================================//
//光电管离散路径识别算法
//PORTB和PORTE接电压比较器的输出端
//16位模数递减计数器进行计数
//author: Yangtze
//time:2009/4/19/15:15:45
//===========================================================//
#define iSampling 10//路径采样时间设置
int iRoutPlace;   //路径位置临时变量
int Angle;     //角度
int iPLace[28]={0x7fff,0x3fff,0xbfff,0x9fff,0xdfff,0xcfff,0xefff,   //路径位置数组
                0xf7ff,0xf3ff,0xfbff,0xf9ff,0xfdff,0xfcff,0xfeff,
                0xff7f,0xff3f,0xffbf,0xff9f,0xffdf,0xffcf,0xffef,
                0xfff7,0xfff3,0xfffb,0xfff9,0xfffd,0xfffc,0xfffe};
            
int iplaceAngle[]={-13,-12,-11,-10,-9,-8,      //轨道偏移角度
                   -7,-6,-5,-4,-3,-2,
                   -1,0,1,2,3,5,5,6,
                   7,8,9,10,11,12,13};
void Init_MDC(void)
{
    MCCTL=0xDF;//设定模数计数器工作方式,中断使能,计数器使能
               //分频系数为16
    MCCNT=1000;//定时器赋初值 (1/16M)*16*1000= 1ms
}
void pllclk(void) //16MHz
{
    SYNR=0x01;    //PLLCLK =2*OSCCLK*(SYNR + 1)/(REFDV + 1)
    REFDV=0x01;
    CLKSEL=0x80;  //选定PLL时钟
}
void IO_Init()  //PORTB和PORTE设置为输入口
{
  DDRB=0X00;
  DDRE=0X00;
}
void main(void)
{
  pllclk();
  Init_PT0_ICapture();
  IO_Init();
  EnableInterrupts;
  for(;;) {}
}
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt 26 MDC_ISR(void)
{
  static unsigned int count=0;
  count++;
  if(count==iSampling)        //100MS读取一次
    {
      iRoutPlace=PORTB; //将IO口读取到的信息存入变量iRoutPlace中,B口在高8为,E口在底8位
      iRoutPlace=iRoutPlace<<8;
      iRoutPlace|=PORTE;
      
      for(i=0;i<28;i++)  //通过循环比较,取得黑色轨道与中轴的偏移角度
      {
          if(iPLace==iRoutPlace)
          {
             Angle=iplaceAngle;
          }
      }
    }
  MCFLG = 0x80;  //清中断标志位
}

  后记:
  该程序仅仅为黑色轨道的路径识别程序,通过红外接收管检测黑色路径,然后,输出位置偏移的角度,并没有控制程序。不过如果得到了偏移角度,控制程序就很好处理了。直接将角度和相应的PWM占空比进行比较,输出对应角度的占空比,以控制舵机。
  如果加上舵机控制程序,就能形成了以个开环的自控控制系统,控制算法为模糊控制算法。很多人都说模糊控制算法很难理解,很不好用,可是从这个程序上看来,模糊控制算法还是挺简单的.只要根据自己的经验来设计一些控制量的表格,通过检测到路径信息然后和控制量的表格进行对比,输出对应的控制量。这就是模糊控制算法的思路。当然这也仅仅只是模糊控制算法的一点思路,有很多不足。
  以上程序仅仅只是一个前期的使用版本,还有很多缺陷有待改进。缺陷如下:
  1、没有发射管的驱动程序,默认为发射管一直在发射。这样的结果红外接收管在检测信息的时候,会受到很大的干扰,而且功耗很大,对整个系统的电流供应和功率输出有很大影响。
  改进方法:在用从一定方向逐个启动的方式进行检测。假如有4对红外发射接收管ABCD。先将D管的发射管开启,ABC发射管均关闭,读取D接收管的信息。然后在开去C发射管,关闭ABD发射管,读取C接收管的信息。依次读取每一个接收管的信息。以ns级的速度读取,可以近似的认为接收管是同时读取信息的。
  2、没有进行滤波处理。在读取道路信息的时候,可能会受到多方面的干扰,为了取得更加接近真实值的信息,有必要进行滤波处理,将干扰噪声剔除。
  改进方法:在用多次读取,取平均值的方法可以在一定程度上减小噪声干扰。
  3、位置处理和角度输出的时候没有按照经验进行适当的处理,比如说,在偏移角度很小的时候,可以近似的认为是在直线上行驶,直接输出0°角,让小车能快速的行驶。
  4、上述程序中的采样周期是随意设定的,没有科学依据,在设定采样周期的时候,一定要通过计算出最优的周期,这样才能保证小车行驶的稳定性和前瞻性。
  暂时找到这么多缺陷,更多的缺陷以及改进还得在实际运用中去发现,去寻求解决的方法。
  完成这个程序,让我也学到了很多。现总结如下:
  1、重视源代码的保存。C语言具有很强的移植性,在不同的平台上尚且能进行移植,在同一个平台上就更容易移植了。我上边写的这写程序,其实很大部分都是之前ECT_SPEED程序里边写过,而我这次在编写程序的时候,根本不用重新编写,直接调用ECT_SPEED里边的程序就可以完成任务。
  我这个程序调用ECT_SPEED文件里的函数有:Init_MDC(), pllclk(),如果在大型的软件开发项目中,这样将会大大缩短程序的开发周期,降低程序的开发成本。
  2、重视程序说明文档的编写。这几天的编程练习中,在编程之前,认真思考,将整个程序的算法,流程都考虑清楚之后,然后将其通过说明文档的形式写出来。这样的好处是,使我在程序的编写的过程中,能一气呵成,不再像以前那样,一个稍微大一点的程序编写下来,还没编写完毕,就已经原来的思路忘记了。他的另一个好处就是方便以后阅读程序。
  3、编写程序的时候,一定要多想,而且从不同的角度去寻找解决问题的方法。在编写这个程序之前,在我的意识当中,是知道用一排红外检测管是可以检测出黑色轨道的,可是在处理轨道位置的时候,一直都不知道怎么处理,怎么才能让单片机知道黑线在那个地方。想了好久,才从角度的这个方向去理解,最终找到了位置处理的方法。
  4、一定要重视循环,尽可能多的使用循环。在上述程序的对比中,我第一感觉是用switch语句进行比较,当输入和whitch中的某一个case吻合时,执行相应的语句。可是在这样的情况下,得写28个case语句,并写与之对应输出语句。这样会大大增加程序的体积,这在单片机内存空间很少的情况下,造成的错误是致命的。
  为了节省存储空间,就开始寻求其他方法来解决这个问题。这样我想到了冒泡程序中逐次对比的方法。我这个程序的问题也可以用多次个循环来实现次比较啊,如果比较结果为真,则执行相应的语句。
  于是就得到了这个比较程序:
      for(i=0;i<28;i++)  //通过循环比较,取得黑色轨道与中轴的偏移角度
      {
          if(iPLace==iRoutPlace)
          {
             Angle=iplaceAngle;
          }
      }  



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
激光跟踪仪市场2023年有望达5.216亿美元