飞思卡尔光电编码器测速程序
飞思卡尔智能车电路
注释:一字型排布,中间对称发射接收:电路图激光传感控制电路速度检测模块硬件板速度检测模块由一对红外对管配以编码盘实现,可以实现一圈24点分辨率。
电路上只有一个电阻结构十分简单。
在编码盘的设计上,我们直接用薄的PCB板嵌入在车模的后轮轴上,简单、牢固。
编码盘外观图如图1.2所示。
车速测定(红外对管)光电编码器与电路板和单片机的接口:图4.11 车速采集模块接口图测速:光电编码器摄像头信号采样电路图:图5.3 摄像头信号采样电路图:5v电压电路光电(两层排布)光栅盘测速,如图3.10 所示。
光栅盘是从机械鼠标上拆下来,总共有50个齿。
将栅盘直接用热熔胶粘接在后轮传动轴上,避免了打滑的可能。
在栅盘的正下方安装槽型光耦(又称光断续器,实际也是红外光电对管)。
当发射的光线被栅齿挡住,接受端管子应该截止,但该栅齿附近间隙仍有光透过并被接受到,所以截止的不够彻底;同理,本该完全导通时也没有完全导通。
所以接收端接受到的信号实际是连续变化的信号,类似于正弦波,而不是理想的脉冲方波信号。
需要在后级信号调理电路中,加上放大级和比较级电路就可得到与TTL电平兼容的脉冲方波信号。
单个传感器检测电路速度检测:ST150为单光束直射取样式光电传感器,它由高输出的红外光电二极管与高灵敏度光敏晶体管组成直射型光电传感器方案。
由速度传感器可以获得一个脉冲信号,该信号直接进入S12 芯片的ETC 模块,经程序计算后便可获得当前车速,其电路原理图如上。
VCC+5图 2.3 红外接收电路红外发射管不是同时点亮,而是隔足够远的距离的两个发射管同时点亮。
这样就可以把邻近干扰降到最底了。
实际测量中使用1.6cm长,直径为3mm的黑色套管套住红外接收管时,发射管发射的红外线对相隔一个管的红外接收的干扰几乎已经很小了。
飞思卡尔程序
飞思卡尔程序#include <hidef.h> /* common defines andmacros */#include <mc9s12dg128.h> /* derivativeinformation *///#include "PWM.h"//#include "AD.h"#include "control.h"#pragma LINK_INFO DERIVATIVE "mc9s12dg128b"word AD_wData[9]; //全局变量存放 AD0,AD1,AD2的结果word sum[9]; //初始化时为求平均值,全白中,各个灯的FF次的电压和word avrg0[9]; //全白时各个灯的平均电压word summ[9];//初始化时为求平均值,全黑中,各个灯的FF次的电压和word avrg1[9]; //全黑时各个灯的平均电压word ss[9]; //实际采集来的各个灯的电压word s[9]; // 实际采集来的各个灯的电压word sum2[8];//用于存放两两灯电压之和word k; //用于存放比较出的最大值uint h=1500;//转角大小int flag = 0;//标志中间灯是否第一次在黑道附近int flagg=0;//标志0灯从哪边感应到黑道int flagg1=0;//标志8灯从哪边感应到黑道int flagg0=0;//标志是左边还是右边出道int j=0;dword i;dword m;dword s0;dword s1;dword p11=0;//以下四个变量用于记录黑道处于同一侧的时间dword p12=0;dword p21=0;dword p22=0;word max0[9]=0;//初始化时采集来的黑道的值int g=0;//为过滤算法使用word cha[9];//用来存放黑白电压差int ffgg0=0;//标志是否用中间板采的数据int ffgg1=0;//标志是否用中间板采的数据word sum0=0; //初始化时采集来9个灯的全白电压和//word sum1=0; //实际采集来的左4个灯的电压和//word sum22=0; //实际采集来的右4个灯的电压和int fla=0;//标志是出道还是入道void AD_Init();void PWM_Init();void PWM_Init1();//void PID();void AD_Init(void) //AD初始化{//控制寄存器2:上电,标志位快速清零,开中断ATD0CTL2 =(ATD0CTL2_ADPU_MASK|ATD0CTL2_AFFC_MASK|ATD0CTL2_ASCIE_MASK) ;ATD1CTL2 =(ATD1CTL2_ADPU_MASK|ATD1CTL2_AFFC_MASK|ATD1CTL2_ASCIE_MASK) ;//控制寄存器3:转换序列长度为3ATD0CTL3 =0x78;//(ATD0CTL3_S2C_MASK|ATD0CTL3_S1C_MASK);ATD1CTL3 =0x78;//(ATD1CTL3_S2C_MASK|ATD1CTL3_S1C_MASK);//控制寄存器4:ATD0CTL4 =(ATD0CTL4_SRES8_MASK|ATD0CTL4_PRS1_MASK|ATD0CTL4_PRS0_MASK) ;ATD1CTL4 =(ATD1CTL4_SRES8_MASK|ATD1CTL4_PRS1_MASK|ATD1CTL4_PRS0_MASK) ;//控制寄存器5:ATD0CTL5 =(ATD0CTL5_DJM_MASK|ATD0CTL5_SCAN_MASK|ATD0CTL5_MULT_MASK);ATD1CTL5 =(ATD1CTL5_DJM_MASK|ATD1CTL5_SCAN_MASK|ATD1CTL5_MULT_MASK); ATD0DIEN=0x00; // 禁止数字输入缓冲ATD1DIEN=0x00; // 禁止数字输入缓冲}#pragma CODE_SEG NON_BANKED //中断服务程序#pragma TRAP_PROCvoid interrupt 22 Int_AD0(void){AD_wData[0] = ATD0DR0; //将结果寄存器中的值存放到数组中AD_wData[1] = ATD0DR1; //将结果寄存器中的值存放到数组中AD_wData[2] = ATD0DR2; //将结果寄存器中的值存放到数组中AD_wData[3] = ATD0DR3;AD_wData[4] = ATD0DR4;AD_wData[5] = ATD0DR5;AD_wData[6] = ATD0DR6;AD_wData[7] = ATD0DR7;AD_wData[8] = ATD1DR0;}#pragma CODE_SEG DEFAULTword max(word a,word b,word c,word d,word e,wordf,word r,word w) {word maxx=0;if(a>maxx)maxx=a;if(b>maxx)maxx=b;if(c>maxx)maxx=c;if(d>maxx)maxx=d;if(e>maxx)maxx=e;if(f>maxx)maxx=f;if(r>maxx)maxx=r;if(w>maxx)maxx=w;return maxx;}void delay0(){for(i=0;i<0xFFFF;i++)for(m=0;m<0x05;m++);}void delay1(){for(i=0;i<0xFFFF;i++);// for(i=0;i<0xFFFF;i++);}void main(void){AD_Init(); //AD 初始化DDRB = 0xFF;DDRA_BIT6=0; //A_BIT6口作为第二块板左边传感器的输入口 DDRA_BIT7=0; //A_BIT7口作为第二块板右边传感器的输入口 PORTB = 0xFF;p=0;for(j=0;j<9;j++){AD_wData[j] = 0; //全局变量初始化sum[j]=0;avrg0[j]=0;avrg1[j]=0;summ[j]=0;}for(j=0;j<9;j++) {max0[j]=0;ss[j]=0;}for(j=0;j<8;j++)sum2[j]=0;EnableInterrupts; //开AD中断for(i=0;i<0xFFFF;i++);for(i=0;i<0xFF;i++) //只能是FF,防止下面sum溢出 {for(j=0;j<9;j++)//采集白道路信息{sum[j]=sum[j]+AD_wData[j];}}for(i=0;i<9;i++) {sum0=sum0+sum[i]/0xFF;avrg0[i]=sum[i]/0xFF;}PORTB=sum[0]/0xFF; //显示0通道采集到的值delay0();PORTB=0x00;//显示马上得进行黑道信息采集了delay1();for(j=0;j<9;j++){for(m=0;m<0xFF;m++){summ[j]=summ[j]+AD_wData[j];}avrg1[j]=summ[j]/0xFF;PORTB=avrg1[j]; //显示采来的黑道信息cha[j]=avrg1[j]-avrg0[j];delay0();PORTB=0x00; //显示马上得进行下一次黑道信息采集了 delay1();}PORTB=0x00;//灯全亮,提示车马上就可以跑了delay1();PWM_Init() ;PWM_Init1(1500,1,200);for(i=0;i<0xFFF;i++);// delay1();for(;;){int f=0;u3=100;if(flagk1==1){p21=0;flagk2=0;p11++;if(p11==0xFFF)flagkk1=1;}else if(flagk2==1){p11=0;flagk1=0;p21++;if(p21==0xFFF)flagkk2=1;}for(f=0;f<9;f++){s[f]=AD_wData[f];ss[f]=s[f]-(avrg0[f]-0x50); //当前值减去初始白道值,以便比较}for(f=0;f<8;f++)sum2[f]=ss[f]+ss[f+1]; //两两灯电压之和//减去1.6V防止溢出*******************if(AD_wData[0]<0xC0&& AD_wData[1]<0xC0&&AD_wData[2]<0xC0&&AD_wData[3]<0xC0&&AD_wData[4]<0xC0&&AD_wData[5]<0xC0&&AD_wData[6]<0xC0&&AD_wD ata[7]<0xC0&&AD_wData[8]<0xC0){if(sum2[0]<0xC0&&sum2[1]<0xC0&&sum2[2]<0xC0&&sum2[3]<0xC0&&sum2[4]<0xC0&&sum2[5]<0xC0&&sum2[6]<0xC0&&sum2[7]<0xD0){fla=1;if(flagg0==1){for(i=0;i<0xFF;i++);PWM_Init1(1140,u1,200);flagk1=1;flagkk2=0;for(;;){if(AD_wData[4]>0xB0||AD_wData[5]>0xB0||AD_wData[6]>0xB0|| AD_wData[7]>0xB0||AD_wData[8]>0xB0){flagg0=0;break;}}}else if(flagg0==2){for(i=0;i<0xFF;i++);PWM_Init1(1860,u1,200);flagk1=0;flagkk2=1;for(;;)if(AD_wData[0]>0xB0||AD_wData[1]>0xB0||AD_wData[2]>0xB0||AD_wData[3]>0xB0||AD_wData[4]>0xB0){flagg0=0;break;}}}else{}}else{if(s[0]-(avrg0[0]-0x13)<0x40 &&s[1]-(avrg0[1]-0x13)<0x40 &&s[2]-(avrg0[2]-0x13)<0x40 && s[3]-(avrg0[3]-0x13)<0x40 &&s[4]-(avrg0[4]-0x13)<0x40 && s[5]-(avrg0[5]-0x13)<0x40 &&s[6]-(avrg0[6]-0x13)<0x40 && s[7]-(avrg0[7]-0x13)<0x40 &&s[8]-(avrg0[8]-0x13)<0x40)///////////注意调整该值36***************{/* if(PORTA_BIT6!=0||PORTA_BIT7!=0){if(PORTA_BIT6!=0&&PORTA_BIT7==0)PWM_Init1(1900,200,1);else if(PORTA_BIT7!=0&&PORTA_BIT6==0)PWM_Init1(1100,200,1);}*/}else{k=max(sum2[0],sum2[1],sum2[2],sum2[3],sum2[4],sum2[5],sum2[ 6],sum2[7]);//谁两和最大,黑道就在谁两之间if(k==sum2[0]){p=0;flagg0=2;if(fla==1)control_11();else if(fla==0) control_1();}else{if(k==sum2[1]){p=0;p1=0;fla=0;control_2(s[1],s[2],ss[1],ss[2],cha[1],cha[2],avrg0[1],avrg 0[2]);}else{if(k==sum2[2]){p=0;p1=0;fla=0;control_3(s[2],s[3],ss[2],ss[3],cha[2],cha[3],avrg0[2],avrg 0[3]);}else{if(k==sum2[3]){p=0;p1=0;fla=0;control_4(s[3],s[4],ss[3],ss[4],cha[3],cha[4],avrg0[3],avrg 0[4]);}else{if(k==sum2[4]){fla=0;p1=0;control_5(s[4],s[5],ss[4],ss[5],cha[4],cha[5],avrg0[4],avrg 0[5]);}else{if(k==sum2[5]){fla=0;p1=0;control_6(s[5],s[6],ss[5],ss[6],cha[5],cha[6],avrg0[5],avrg 0[6]);}else{if(k==sum2[6]){p=0;p1=0;fla=0;control_7(s[6],s[7],ss[6],ss[7],cha[6],cha[7],avrg0[6],avrg 0[7]);}else{if(k==sum2[7]){p=0;flagg0=1;if(fla==0)control_8(); elseif(fla==1)control_88(); } else{}}}}}}}}}}}}。
飞思卡尔单片机程序调试方法说明
飞思卡尔单片机程序调试方法说明对于飞思卡尔单片机编程,常用的调试方法有3种:调试方法1:在线调试法(Debug模式)CodeWarrior 10.3 开发环境下,可启动Debug模式,利用step into, step over, step return ,run to line 按钮,程序中设置断点,修改变量的值,查看寄存器的值等,进行调试。
有关调试窗口的按钮定义和调试方法,可查看帮助中debug View 和Debug information的说明。
调试方法2:串口调试法通过将程序运行过程中的数据、变量值等发送到PC机上查看,同时也可从PC机上通过串口发送数据到单片机,修改程序运行的参数(或步骤)进行调试。
智能车运行过程中常用用串口调试的方法。
调试方法3:硬件调试法通过连接在芯片外部的硬件或电路的变化或响应,查看程序运行的结果或状态(例如,在程序的某一位置点亮小灯、开蜂鸣器、发数据到LCD等)。
理解和掌握概念:单步调试相信任何调试人员对单步调试非常的熟悉。
CodeWarrior(与Eclipse基本一致)提供step into、step over、step return三个命令来支持单步调试。
三者的具体区别是:step into(快捷键F5)就是单步执行,遇到子函数就进入并且继续单步执行;step over(快捷键F6)是在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止,也就是把子函数整个作为一步。
step return(快捷键F7)就是单步执行到子函数内时,用step return就可以执行完子函数余下部分,并返回到上一层函数。
说的通俗点就是,step into:进入子函数,step over:越过子函数,但子函数会执行,step return:跳出子函数。
此外,Eclipse还提供了Run to line(快捷键Ctr + R)功能,从开始处运行程序,到正在执行的断点暂停。
一种基于光电编码器和matlab曲线拟合的测速
一种基于光电编码器和Matlab曲线拟合的测速方法作者:广东海洋大学电子信息工程系王嘉斌大家都知道,对于电机速度的测量方法有很多种,其中比较经典有M法测速、T法测速和MT法测速。
而在这里,我要介绍的是一种非常适合于飞思卡尔智能车的基于光电编码器的测速方法。
这里以200P/R的为例,它每转一周就会输出200个脉冲,通过单片机的脉冲捕捉功能就能检测到编码器输出的脉冲数。
众所周知,电机的转速是通过PWM的占空比来控制,想到这里,我们可以提出这样的一个疑问:既然占空比决定电机转速,而转速可以通过编码器输出的脉冲个数来表示,那么电机的PWM占空比跟编码器输出的脉冲个数是不是有某种必然的关系呢?答案是肯定的。
没错,占空比跟脉冲个数之间一定有种必然的关系!这种关系可能是线性的,也可能是非线性的。
在偏差允许的范围内,我们一般会选择线性的。
原因很简单,线性的让单片机计算起来肯定要快一些。
既然怀疑这两者之间有某种联系,那么我们就要想办法去找出它们之间的关系来。
首先,我们得先做一件事——测量。
通过测量不同占空比所对应的脉冲个数,再通过一定的数据处理(例如多次测量求平均值),得到两组对应的数据。
本人是通过先编写好程序,在程序中设置6种不同的速度值,即6种电机的PWM占空比值,然后通过每10ms的中断来读取编码器输出的脉冲个数。
因为都是10ms,所以每次读取到的脉冲个数都相差不大,最多差9个脉冲,为了减小测量误差,我取了4组数,然后对这4组数取平均值。
这样,就得到了一组电机PWM占空比跟编码器脉冲个数的数据。
对所得到的数据,我们可以借助Matlab这个强大的数学工具来处理。
主要用的是Matlab 的曲线拟合功能。
下面我将为大家介绍一下相关的操作步骤。
首先,我们把得到的占空比和脉冲个数以数组的形式输入到Matlab中(x代表占空比,y为脉冲个数):x=[100,200,300,400,500,600];y=[123,350,560,763,970,1206]; 然后再输入曲线拟合工具箱cftool(x,y)命令,此时Matlab会自动弹出一个新的窗口(如下图1)进入曲线拟合工具箱界面“Curve Fitting tool”后,按下面步骤操作:(1)点击“Data”按钮,弹出“Data”窗口;(2)利用X data和Y data的下拉菜单读入数据x,y,可修改数据集名“Data set name”,然后击“Create data set”按钮窗口,退出“Data”,返回工具箱界面,这时会自动画出数据集的曲线图(图2);图2(3)点击“Fitting”按钮,弹出“Fitting”窗口;(4)点击“New fit”按钮,可修改拟合项目名称“Fit name”,通过“Data set”下拉菜单选择数据集,然后通过下拉菜单“Type of fit”,选择拟合曲线的类型,在这里我们直接选择Polynomial:多形式逼近中的liner类型;(5)类型设置完成后,点击“Apply”按钮,就可以在Results框中得到拟合结果(图3)。
光电编码器测量电机转速的方法
光电编码器测量电机转速的方法光电编码器测量电机转速的方法可以利用定时器/计数器配合光电编码器的输出脉冲信号来测量电机的转速。
具体的测速方法有M法、T法和M/T法3种。
一、M法又称之为测频法,其测速原理是在规定的检测时间Tc内,对光电编码器输出的脉冲信号计数的测速方法,例如光电编码器是N线的,则每旋转一周可以有4N个脉冲,因为两路脉冲的上升沿与下降沿正好使编码器信号4倍频。
现在假设检测时间是Tc,计数器的记录的脉冲数是M1,在实际的测量中,时间Tc内的脉冲个数不一定正好是整数,而且存在最大半个脉冲的误差。
如果要求测量的误差小于规定的范围,比如说是小于百分之一,那么M1就应该大于50。
在一定的转速下要增大检测脉冲数M1以减小误差,可以增大检测时间Tc单考虑到实际的应用检测时间很短,例如伺服系统中的测量速度用于反馈控制,一般应在0.01秒以下。
由此可见,减小测量误差的方法是采用高线数的光电编码器。
M法测速适用于测量高转速,因为对于给定的光电编码器线数N机测量时间Tc条件下,转速越高,计数脉冲M1越大,误差也就越小。
二、T法也称之为测周法,该测速方法是在一个脉冲周期内对时钟信号脉冲进行计数的方法。
为了减小误差,希望尽可能记录较多的脉冲数,因此T法测速适用于低速运行的场合。
但转速太低,一个编码器输出脉冲的时间太长,时钟脉冲数会超过计数器最大计数值而产生溢出;另外,时间太长也会影响控制的快速性。
与M法测速一样,选用线数较多的光电编码器可以提高对电机转速测量的快速性与精度。
三、M/T法M/T法测速是将M法和T法两种方法结合在一起使用,在一定的时间范围内,同时对光电编码器输出的脉冲个数M1和M2进行计数。
实际工作时,在固定的Tc时间内对光电编码器的脉冲计数,在第一个光电编码器上升沿定时器开始定时,同时开始记录光电编码器和时钟脉冲数,定时器定时Tc时间到,对光电编码器的脉冲停止计数,而在下一个光电编码器的上升沿到来时刻,时钟脉冲才停止记录。
光电编码器测速
飞思卡尔智能车舵机和测速的控制设计与实现时间:2010-04-14 11:53:10 来源:电子设计工程作者:雷贞勇谢光骥五邑大学2.1 舵机工作原理舵机在6 V电压下正常工作,而大赛组委会统一提供的标准电源输出电压为7.2 V,则需一个外围电压转换电路将电源电压转换为舵机的工作电压6 V。
图2为舵机供电电路。
舵机由舵盘、位置反馈电位计、减速齿轮组、直流动电机和控制电路组成,内部位置反馈减速齿轮组由直流电动机驱动,其输出轴带动一个具有线性比例特性的位置反馈电位器作为位置检测。
当电位器转角线性地转换为电压并反馈给控制电路时,控制电路将反馈信号与输入的控制脉冲信号相比较,产生纠正脉冲,控制并驱动直流电机正向或反向转动,使减速齿轮组输出的位置与期望值相符。
从而达到舵机精确控制转向角度的目的。
舵机工作原理框图如图3所示。
2.2 舵机的安装与调节舵机的控制脉宽与转角在-45°~+45°范围内线性变化。
对于对速度有一定要求的智能车,舵机的响应速度和舵机的转向传动比直接影响车模能否以最佳速度顺利通过弯道。
车模在赛道上高速行驶,特别是对于前瞻性不够远的红外光电检测智能车,舵机的响应速度及其转向传动比将直接影响车模行驶的稳定性,因此必须细心调试,逐一解决。
由于舵机从执行转动指令到响应输出需占用一定的时间,因而产生舵机实时控制的滞后。
虽然车模在进入弯道时能够检测到黑色路线的偏转方向,但由于舵机的滞后性,使得车模在转弯过程中时常偏离跑道,且速度越快,偏离越远,极大限制车模在连续弯道上行驶的最大时速,使得车模全程赛道速度很难进一步提高。
为了减小舵机响应时间,在遵守比赛规则不允许改造舵机结构的前提下,利用杠杆原理,采用加长舵机力臂的方案来弥补这一缺陷,加长舵机力臂示意图如图4所示。
图4中,R为舵机力臂;θ为舵机转向角度;F为转向所需外力;α为外力同力臂的夹角。
在舵机输出盘上增加长方形杠杆,在杠杆的末端固定转向传动连杆,其表达式为:加长力臂后欲使前轮转动相同角度时,在舵机角速度ω相同的条件下舵机力臂加长后增大了线速度v,最终使得舵机的转向角度θ减小。
飞思卡尔卡尔曼滤波程序
卡尔曼滤波:以陀螺仪测量的角速度作为预测值的控制量,加速度传感器测量的角度作为观测值。
下面程序中angle_m为测量角度,gyro_m为测量角速度,gyro_m*dt为控制量。
以下程序是按卡尔曼滤波的五个公式来编写的。
X(k|k-1)=A X(k-1|k-1)+B U(k) (1)P(k|k-1)=A P(k-1|k-1) A’+Q (2)X(k|k)= X(k|k-1)+Kg(k) (Z(k)-H X(k|k-1)) (3)Kg(k)= P(k|k-1) H’ / (H P(k|k-1) H’ + R) (4)P(k|k)=(I-Kg(k) H)P(k|k-1) (5)对于单输入单输出系统,A、B、H、I不为矩阵且值都为1。
卡尔曼滤波参数的调整:其参数有三个,p0是初始化最优角度估计的协方差(初始化最优角度估计可设为零),它是一个初值。
Q是预测值的协方差,R是测量值的协方差。
对Q和R的设定只需记住,Q/(Q+R)的值就是卡尔曼增益的收敛值,比如其值为0.2,那么卡尔曼增益会向0.2收敛(对于0.2的含义解释一下,比如预测角度值是5度,角度测量值是10度,那么最优化角度为:5+0.2*(10-5)=6。
从这里可以看出,卡尔曼增益越小,说明预测值越可靠,最优化角度越接近预测值;相反的,卡尔曼增益越大,说明测量值越可靠,最优化角度越接近测量值)。
p0/(Q+R)反映收敛的快慢程度,该值设定越小,收敛越快,该值越大,收敛越慢(这里的p0是指初始最优角度值的协方差),因为卡尔曼增益收敛总的来说是很快的,所以该值设定大一点或小一点都没什么关系。
注:以下程序只用于说明算法,存在语法错误,初始的参数也是随意给定的。
x=0;/* 最优角度初值*/p=1;/* 最优角度对应协方差初值*/dt=0.02;Q=0.0025;R=0.25;void Kalman_Filter(float angle_m,float gyro_m) //gyro_m:gyro_measure{x=x+ gyro_m*dt; 等号右边的x表示上一次最优角度值,等号左边的x表示这一次的角度的预测值p=p+Q; 等号右边的p表示上一次最优角度值的协方差,等号左边的p表示这一次的角度预测值的协方差k=p/(p+R); k值为卡尔曼增益(k值每次计算都不一样,它会越来越趋近于Q/(Q+R)这个收敛值)x=x+k*( angle_m-x); 等号左边的x表示根据预测值和测量值计算出来的这一次的最优角度值(从这里可以看出,k越大,等号左边的最优值x与等号右边的测量值angle_m越接近;k越小,等号左边的最优值x与等号右边的预测值x越接近;)p=(1-k)*p; 等号左边的p表示这一次最优角度值的协方差}从上面的程序可以看出,卡尔曼滤波是一个递推过程,初始的最优角度值可设为x=0,初始最优角度值的协方差p一定不能设为零,dt是采样周期,Q 与R可共同决定卡尔曼增益收敛的大小。
光电编码器测速
实验三光电传感器转速测量实验实验目的1.通过本实验了解和掌握采用光电传感器测量的原理和方法。
2.通过本实验了解和掌握转速测量的基本方法。
实验原理直接测量电机转速的方法很多,可以采用各种光电传感器,也可以采用霍尔元件。
本实验采用光电传感器来测量电机的转速。
由于光电测量方法灵活多样,可测参数众多,一般情况下又具有非接触、高精度、高分辨率、高可靠性和相应快等优点,加之激光光源、光栅、光学码盘、CCD器件、光导纤维等的相继出现和成功应用,使得光电传感器在检测和控制领域得到了广泛的应用。
光电传感器在工业上的应用可归纳为吸收式、遮光式、反射式、辐射式四种基本形式。
图3.31说明了这四种形式的工作方式。
图3.31 光电传感器的工作方式图3.32直射式光电转速传感器的结构图直射式光电转速传感器的结构见图3.32。
它由开孔圆盘、光源、光敏元件及缝隙板等组成。
开孔圆盘的输入轴与被测轴相连接,光源发出的光,通过开孔圆盘和缝隙板照射到光敏元件上被光敏元件所接收,将光信号转为电信号输出。
开孔圆盘上有许多小孔,开孔圆盘旋转一周,光敏元件输出的电脉冲个数等于圆盘的开孔数,因此,可通过测量光敏元件输出的脉冲频率,得知被测转速,即n=f/N式中:n - 转速f - 脉冲频率N - 圆盘开孔数。
反射式光电传感器的工作原理见图3.33,主要由被测旋转部件、反光片(或反光贴纸)、反射式光电传感器组成,在可以进行精确定位的情况下,在被测部件上对称安装多个反光片或反光贴纸会取得较好的测量效果。
在本实验中,由于测试距离近且测试要求不高,仅在被测部件上只安装了一片反光贴纸,因此,当旋转部件上的反光贴纸通过光电传感器前时,光电传感器的输出就会跳变一次。
通过测出这个跳变频率f,就可知道转速n。
n=f如果在被测部件上对称安装多个反光片或反光贴纸,那么,n=f/N。
N-反光片或反光贴纸的数量。
图3.33 反射式光电转速传感器的结构图实验仪器和设备1. 计算机 n台2. DRVI快速可重组虚拟仪器平台 1套3. 并口数据采集仪(DRDAQ-EPP2)1台4. 开关电源(DRDY-A)1台5. 光电转速传感器(DRHYF-12-A) 1套6. 转子/振动实验台(DRZZS-A)/(DRZD-A) 1 台实验步骤及内容1.光电传感器转速测量实验结构示意图如图3.34所示,按图示结构连接实验设备,其中光电转速传感器接入数据采集仪A/D输入通道。
飞思科尔光电组程序
我是光电组的,下面是程序,小车可以跑起来,但速度有待提升#include <hidef.h> /* common defines and macros */#include <MC9S12XS128.h> /* derivative information */#pragma LINK_INFO DERIVATIVE "mc9s12xs128"//static unsigned chardirection_turn[12]={888,1098,1208,1328,1481,1612,1730,1856,1988,2100,22 22,2368};//Chapter 12//Periodic Interrupt Timer (S12PIT24B4CV1) Page349//The PIT module has no external pins.//PIT 模式没有外部引脚//========================================================== ==============================unsigned char light=0; //激光管检测标志unsigned short turn_value=0; //转向的PWM数值unsigned short direction_turn[7]={333,430,560,647,705,780,888}; //转向给定值初始化short speed_set[7]={250,300,350,400,350,300,250}; //速度给定值short speed_flag=0; //速度档位标志位short speed[3]={0,0,0}; //速度检测函数short pulse_count=0; //编码器脉冲计数值short speed_expect=0; //理想速度short kp=2; //比例环节short ki=0; //积分环节short kd=1; //微分环节short ek1=0; //误差1short ek2=0; //误差2short ek3=0; //误差3short speed_add=0; //速度增量//========================================================== =============================void PLL_Init() //时钟初始化{REFDV=0x81; /*PLLCLK=2*OSCCLK*(SYNR+1)/(REFDV+1)*/SYNR=2; /* 锁相环时钟=2*16*(2+1)/(1+1)=48MHZ */while(!(CRGFLG&0x08)); /* 总线时钟=48/2=24MHZ */CLKSEL=0x80;}void PWM_Init() //PWM初始化{PWME=0x00; //关闭PWM使能PWMPRCLK=0x66; //A,B时钟均为总线的64分频,375KHZ//PWMSCLA=0x01; //clockSA=clockA/(2*PWMSCLA) = 1500KHZ //PWMSCLB=0X01; //clockSB=clockB/(2*PWMSCLB) =1500KHZ PWMCLK=0x00;PWMPOL=0xFF; //PWM输出起始电平为高电平PWMCAE=0x00; //输出左对齐PWMCTL=0xf0; //通道01,23,45,67级联PWMPER01=5999; //舵机频率为62.5HzPWMDTY01=647; //占空比a=(PWMDTY01+1)/(PWMPER01+1) PWMPER23=1000; //PWM通道3周期为375HZPWMDTY23=0; //占空比a=(PWMDTY01+1)/(PWMPER01+1)占空比50% ~~ 150PWMPER45=1000; //PWM通道5周期为0.10ms 10KZH300=0.00010/(1/3000000)PWMDTY45=300; //占空比a=(PWMDTY01+1)/(PWMPER01+1)PWMPER67=375; //频率为1000HzPWMDTY67=200; //PWME=0xff; //使能pwm}void Pit0_Init() //PIT初始化{PITCFLMT_PITE=0; //关PIT使能PITCE_PCE0=1; //通道0使能PITMUX_PMUX0=0; //通道0接微时钟0PITMTLD0=99; //微时钟0值设置为7fPITLD0=3839; //time-out period = (PITMTLD + 1) * (PITLD + 1) / fBUS.//时间计算100*3840/24000000=0.016s PITINTE_PINTE0=1; //通道0中断时能PITCFLMT_PITE=1; //PIT使能}void ECT_Init(){TIOS=0x00; /* OC0路为输出比较,OC1路为输入捕捉*/TSCR2=0x06; /* 定时器溢出中断禁止,计数器自由运行禁止复位,64分频*/TSCR1=0x80; /* 定时器使能*/TIE=0x01; /* 输出比较相应中断使能*/TCTL4=0x01;}void dly_1ms(){int i,j;for(i=0;i<200;i++){for(j=0;j<1000;j++){;}}}void sam_position() //车位检测函数{int i=0,j=0;unsigned char m=0,n=0;n=PORTA;for(i;i<10;i++){m=PORTA;if(n==m)j++;}if(j>6)light=n;}void check_start() //检测起始线{if((light&&4)||(light&&16))start_flag++;}void check_start(){}void turning() //舵机转向函数{switch(light){case 1:if(turn_value==direction_turn[1]) //出界判断算法{turn_value=direction_turn[0];speed_expect=speed_set[0];}else if(turn_value==direction_turn[0]){turn_value=direction_turn[0];speed_expect=speed_set[0];}break;case 2:if(turn_value==direction_turn[0]){turn_value=direction_turn[1];speed_expect=speed_set[1];}else if(turn_value==direction_turn[1]){turn_value=direction_turn[1];speed_expect=speed_set[1];}else if(turn_value==direction_turn[2]){turn_value=direction_turn[1];speed_expect=speed_set[1];}break;case 4:if(turn_value==direction_turn[1]){turn_value=direction_turn[2];speed_expect=speed_set[2];}else if(turn_value==direction_turn[2]){turn_value=direction_turn[2];speed_expect=speed_set[2];}else if(turn_value==direction_turn[3]){turn_value=direction_turn[2];speed_expect=speed_set[2];}break;case 8:if(turn_value==direction_turn[2]){turn_value=direction_turn[3];speed_expect=speed_set[3];}else if(turn_value==direction_turn[3]){turn_value=direction_turn[3];speed_expect=speed_set[3];}else if(turn_value==direction_turn[4]){turn_value=direction_turn[3];speed_expect=speed_set[3];}break;case 16:if(turn_value==direction_turn[3]){turn_value=direction_turn[4];speed_expect=speed_set[4];}else if(turn_value==direction_turn[4]){turn_value=direction_turn[4];speed_expect=speed_set[4];}else if(turn_value==direction_turn[5]){turn_value=direction_turn[4];speed_expect=speed_set[4];}break;case 32:if(turn_value==direction_turn[4]){turn_value=direction_turn[5];speed_expect=speed_set[5];}else if(turn_value==direction_turn[5]){turn_value=direction_turn[5];speed_expect=speed_set[5];}else if(turn_value==direction_turn[6]){turn_value=direction_turn[5];speed_expect=speed_set[5];}break;case 64:if(turn_value==direction_turn[5]) //出界判断算法{turn_value=direction_turn[6];speed_expect=speed_set[6];}else if(turn_value==direction_turn[6]){turn_value=direction_turn[6];speed_expect=speed_set[6];}break;default:break;}PWMDTY01=turn_value;}void check_speed() //速度检测函数{ek3=ek2; //计算速度差值ek2=ek1;ek1=speed_expect-pulse_count;speed[2]=speed[1]; //当前速度放在[0],之前放在[1],[2]speed[1]=speed[0];speed[0]=pulse_count;pulse_count=0;}void speed_down() //制动函数{PWMDTY23=300; //电机反向供电PWMDTY45=0;}void speed_pid() //PID算法{speed_add=kp*(ek1-ek2)+ki*ek1+kd*(ek1-2*ek2+ek3); //PID增量式}void driver() //驱动电机控制函数{//if(((turn_value>705)||(turn_value<560))&&(speed[0]>200)) //当前速度若远超给定速度// {//speed_down();// }//else// {PWMDTY23=0;speed_pid();PWMDTY45=PWMDTY45+speed_add;// }if(PWMDTY45>600)PWMDTY45=600;}void main(){DisableInterrupts; /* 关中断*/PLL_Init();PWM_Init();Pit0_Init();ECT_Init();turn_value=direction_turn[3];DDRA=0x00;DDRB=0xFF;PORTB=0X00;EnableInterrupts;for(;;){//sam_position();//turning();}}#pragma CODE_SEG NON_BANKEDvoid interrupt 8 Timer0_ISR(void){pulse_count++;TFLG1_C0F=1; /* TC0端有中断产生*/ }void interrupt 66 PIT0_ISR(void){sam_position(); //车位检测函数turning(); //舵机转向函数check_speed(); //速度检测函数driver(); // 驱动电机控制函数PITTF_PTF0=1; /* PIT0端有中断产生,清除标志位*/ }。
编码器与程序
飞思卡尔那些事之ECT方式检测速度(2009-05-03 16:03:17)转载资源:1、增量式旋转编码器。
旋转编码器是测量速度的一种装置,旋转编码器每旋转一周,就会输出特定数目的脉冲。
在单位时间内记录读取到旋转编码器输出的脉冲数,即可知道旋转编码器转动的圈数,即轮胎的转动速度。
因为轮胎周长一定,所有可以求得在单位时间内小车行驶的路程,再通过计算即可得到小车的速度,如果单位时间足够小,则可以近似认为该速度位瞬时速度。
2、HCS12的ECT模块。
在ECT模块中的输入捕捉定时器和脉冲累加器可以实现旋转编码器的脉冲计数。
方案:1、输入捕捉(Intput Capture)计数方式。
通过输入捕捉模块,进行脉冲输入捕捉,在中断程序中通过全局变量进行计数,每捕捉到一个脉冲进行一次计数,在单位时间内读取输入捕捉中断程序计数变量的计数值。
2、脉冲计数器(Modulus Counter)方式。
通过脉冲累加器进行脉冲输入捕捉,模数计数器设定为单位时间中断,在模数计数器中断程序中读取脉冲累加器的计数数值。
脉冲累加器可以选用16位脉冲累加器。
也可以用8位的脉冲累加器。
3、模数计数器进行定时,每500MS读取一次脉冲数。
读取这500MS中的脉冲数即可算出输出速度。
说明:1、旋转编码器选用的是YZ30D-4S-2NA-200;该旋转编码器旋转一周,输出200个脉冲。
2、使用输入捕捉通道0进行脉冲的捕捉。
设定位下降沿捕捉方式。
开启输入捕捉中断,在中断程序中对全局变量iPulesNumAll进行计数,每进入一次中断程序,变量iPulesNumAll加1。
3、使用模数计数器进行定时,定时时间为500ms,当达到500MS后,读取iPulesNumAll中的数值,即可通过公式计算出速度。
定时过程中,既可以直接定时500MS,也可以定时1MS。
在定时1MS的方案中,通过设定一个全局变量或静态变量iSpeedNum进行计数,当计数到500后再读取iPulesNumAll中的数值。
飞思卡尔光电程序
/*文件名:main.c硬件:MC9SDG128Bclk=16m编译:CodeWarrior*/#include <hidef.h> /* common defines and macros */#include <mc9s12dg128.h> /* derivative information */#pragma LINK_INFO DERIV ATIVE "mc9s12dg128b"#include<string.h>#include "printp.h"#include "math.h"//------------------------PID函数-----------------------------static int set_integration=80;static int dError,Error;static int SetPoint=50;//初始值设置static int Proportion=7; //比例Kstatic int Integral=70;//set_integration; // 积分T*K/Ti static int Derivative=50; // 微分K*Td/Tstatic int Proportion2=1; //比例Kstatic int Integral2=70;//set_integration; // 积分T*K/Ti static int Derivative2=15; // 微分K*Td/Tstatic int LastError=0; // Error[-1]static int PrevError=0; // Error[-2]static int Point_lineroad = 140 ;static int Point_sturnroad = 90 ;static int Point_bigturnroad = 90 ;static int Point_gooutroadlittle = 80 ;static int Point_gooutroadbig = 80 ;static int Point_littlebig = 100;static int Point_gooutroadnoline = 70 ;static int Point_nearlineroad = 90 ;static int Point_Add = 0 ;//-------------------舵机PD-----static int PD_SetPoint=0;//初始值设置static int PD_Proportion=15; //比例Kstatic int PD_Derivative=1; // 微分K*Td/Tstatic int PD_LastError=0; // Error[-1]static int PD_PrevError=0; // Error[-2]static int PD_dError,PD_Error,PD_rout,PD_RError;static int i_Position,PD_i_Position; //黑线位置辽宁工程技术大学毕业设计(论文)static int Position[7]={-460,-300,-150,0,150,300,460};static unsigned int Position_R[7]={150,150,150,150,150,150};static int Vs;static int Vf;//++++++++++++++++++++舵机相关++++++++++++++++++++++++++++++++++++++static int turn_control=0,oldturn_control=0;static unsigned char turn_filter_count=0;static unsigned char crossroad; //十字路口//---------------------电机相关--------------------------------------static unsigned int uint_Array_SetSpeed_line[7] ={80,80,80,80,80,80};static unsigned int *point_uint_SetSpeed= uint_Array_SetSpeed_line;static unsigned int wheel_speed_p=0,wheel_speed=0;static int rout,rin; //pid parmeterstatic int control=0,old_control;//control=100;static int delay;//---------------------输入捕捉相关----------------------------------static unsigned int Time_inCapture,count=0;static unsigned int Average_inCatime,Average_inCapturetime[4]={0,0,0,0};static unsigned int go=0,see_noline=0,see_blackline=0,backline_flag,see_gonow;static unsigned char go_flag=0;static unsigned int N=0,P=0; //speedstatic void wait(long ms){long timeout;timeout = ui_absoluteTime + ms;while (timeout != ui_absoluteTime){__asm NOP;timeout = timeout-1; /* __asm WAI; */ /* will be waken up by the RTI exception. Not well supported in BDM mode */}}void ADCInit(void){ATD0CTL2=0xC0; //EAD模块上电, 快速清零, 无等待模式, 禁止外部触发ATD0CTL3=0X38; // 每个序列7次转换, No FIFO, Freeze模式下继续转换ATD0CTL4=0x81; // 8位精度, 2个时钟,2uS ATDClock=[BusClock*0.5]/[PRS+1] ; PRS=1, divider=4ATD0CTL5=0xb0; //右对齐无符号,多通道采样,通道0开始至6ATD0DIEN=0x00; // 禁止数字输入ATD0CTL2=0xC0; //EAD模块上电, 快速清零, 无等待模式, 禁止外部触发,允许中?}{PLLCTL=0XF1;SYNR=0X02;REFDV=0X01;CRGFLG=0X40;while((CRGFLG!=0X0C)&(CRGFLG!=0X1C)) { ;}CLKSEL=0X80;}void SciInit(){SCI0BDL = (unsigned char)((48000000UL / 2) / 9600/ 16);SCI0CR1=0; /*normal,no parity*/SCI0CR2=0X08; /*RIE=1,TE=1,RE=1*/}void IRT_INIT(void){RTICTL=0x39; //0.00256中断一次CRGINT=0x80;}void Time_MCC(){MCCTL=0xc7;MCCNT=0x2710;}//-----------------------pwm---------------------------------void pwm_init(void){//设置前进方向PWMCAE =0x00; /*LIFE ALIGE 左对齐*/PWMPRCLK =0x13; /*pwm a分频128,b分频2*/ //a 32PWMPOL =0xAa; /*通道1和3上升开始*/PWMCTL =0xF0; /*01,23为16位输出*/PWMCLK =0x00; /*选择阿01A 23B时钟*/PWMPER01 =37500; /*设置脉冲个数1875 输出100Hz,128分频8分频37500 80Hz*/PWMDTY01 =turn_middle ; //240--340// -42度到+42度PWMPER23 =1281; /*设置脉冲个数输出10KHz 6000是2KHz*/PWMDTY23 =1000; //700PWMPER45 =1875;PWMDTY45 =c_midile; // 255 //355right hi 155辽宁工程技术大学毕业设计(论文)PWMDTY67 =0;PWME =0x02; /*打开P1和P3口*/DDRP=0xff; //设置控制输出PTP=0XFE;}//======================capture====================================void capture_init(void){TIOS=0X00; //输入捕捉0口TCTL4=0X02; //扑捉falling edge沿TIE=0X01; //开扑捉中断TSCR2=0X07; //分频128分频TSCR2_TOI=1;开溢出中断TFLG1_C0F=1; //置位标志位TFLG2_TOF=1; //置标志位TSCR1=0X80; //开定时器,标志位自动清零TSCR2_TOI=1;}//++++++++++++++++++++++++++EEROM+++++++++++++++++++++++++++++++++++ void eeprom_program(uint data,uint addr){uint *p;p = (uint*)addr;ECLKDIV = 0x4a; //设置时钟ESTAT=ESTA T_PVIOL_MASK+ESTAT_ACCERR_MASK; //清出错标志位*p=data;ECMD=prog; //赋命令ESTAT_CBEIF = 1; //清缓存标志位if((ESTA T_PVIOL==0)&&(ESTAT_ACCERR==0)){while(!ESTA T_CCIF); // 等待命令执行完成}}void eeprom_erase(uint addr) //擦数据addr将数据从地址开始位擦出{uint *p;p = (uint*)addr;ECLKDIV = 0x4a; //设置时钟ESTAT=ESTA T_PVIOL_MASK+ESTAT_ACCERR_MASK; //清出错标志位*p=0xffff;ECMD=sector_erase; //赋命令ESTAT_CBEIF = 1; //清缓存标志位{while(!ESTA T_CCIF); // 等待命令执行完成}}void eeprom_init(void){INITEE=0x41; //eeprom地址从0x4000到0x47ff; asm NOP;MISC=1;}void PH_INIT(void){DDRH=0X00;PERH=0XFF; //PULL UP PULL DOWN DEVICE is enabled PPSH =0X00; //Falling edge up pull PIEH=0XFF; //interupt p0 enable }//++++++++++刹车++++++++++++++++++++++++++++++++++++++++++++++void brake_car(){back_car;PWMDTY23=300; //>300_asm("nop");_asm("nop");_asm("nop");_asm("nop");forward_car;}//----------------------------------------------------------------------------------void PID_speed_control_2(){wheel_speed= Time_inCapture;wheel_speed=60000/wheel_speed ; // rin值越大,速度越快rin =(int)(wheel_speed); // rin=90:1meter rin=120;;2meter Error = SetPoint-rin; // 积分dError = Error-2*LastError + PrevError; // 微分项rout=((Proportion2*(Error-LastError)) +(Integral2*Error)+(Derivative2*dError));PrevError = LastError; // 偏差存储LastError = Error; // 偏差存储辽宁工程技术大学毕业设计(论文)// control =control+(rout/set_integration);old_control = control ;control =control+(rout/80);//----------------------限制加速度----------------------------------------- if( Average_inCatime > 900 )car_static = stop_gogo;if( car_static == stop_brake ){brake_car() ;PWMDTY23 = 1281;car_static = stop_nobrake;}else if( car_static == stop_nobrake )PWMDTY23 = 1281;else if( car_static == stop_gogo ){if( ( control < 550 ) && ( control >- 550 ) ) {PWMDTY23 = setspeed - (control) ;} else if( control >= 550 ){control = 550 ;PWMDTY23 = setspeed-control ;} else if( control <= -550 ){control = -550;PWMDTY23 = setspeed-control ;}}}if((go_flag|0x01)==0x03){switch(uc_AD_Data_divmin_F_count){case first:ui_AA += 1;ui_AA_shadow += 1;ui_BB = 0;ui_CC = 0;ui_DD = 0;ui_EE = 0;ui_GG = 0;ui_GG_shadow = 0;if( ui_AA > 500 )ui_AA = 500 ;if( ui_AA_shadow > 500 ) ui_AA_shadow = 500 ;if( see_blackline == 0 )ui_AA_shadow = 0;break;case second:ui_AA = 0;ui_BB += 1;ui_CC = 0;ui_DD = 0;ui_EE = 0;ui_FF = 0;ui_GG = 0;ui_GG_shadow = 0;ui_AA_shadow = 0;if( ui_BB > 500)ui_BB = 500;break;case three:ui_AA = 0;ui_BB = 0;ui_CC = 0;ui_DD += 1;ui_EE = 0;ui_FF = 0;ui_GG = 0;ui_GG_shadow = 0;ui_AA_shadow = 0;if( ui_DD > 500)ui_DD = 500;break;辽宁工程技术大学毕业设计(论文)ui_AA = 0;ui_BB = 0;ui_CC = 0;ui_DD += 1;ui_EE = 0;ui_FF = 0;ui_GG = 0;ui_GG_shadow = 0;ui_AA_shadow = 0;if( ui_DD > 500)ui_DD = 500;break;case fifth:ui_AA = 0;ui_BB = 0;ui_CC = 0;ui_DD += 1;ui_EE = 0;ui_FF = 0;ui_GG = 0;ui_GG_shadow = 0;ui_AA_shadow = 0;if( ui_DD > 500)ui_DD = 500;break;case sixth:ui_AA = 0;ui_BB = 0;ui_CC = 0;ui_DD = 0;ui_EE = 0;ui_FF += 1;ui_GG = 0;ui_GG_shadow = 0;ui_AA_shadow = 0;if( ui_FF >= 500 )break;case seventh:ui_AA = 0;ui_BB = 0;ui_CC = 0;ui_DD = 0;ui_EE = 0;ui_FF = 0;ui_GG += 1;ui_GG_shadow += 1;ui_AA_shadow = 0;if( ui_GG > 500 )ui_GG = 500 ;if( ui_GG_shadow > 500 )ui_GG_shadow = 500 ;if( see_blackline == 0 )ui_GG_shadow = 0;break;}//++++++++++++++++++++++++++++++++++++++++++if( ui_DD > 100 )uc_road_static = islineroad;else if( ui_DD > 50)uc_road_static = isnearlineroad;//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if( ( ui_BB >= 5 ) || ( ui_FF >= 5 ) ) //8uc_road_static = islittlebig;else if (( ui_BB >= 1 ) || ( ui_FF >= 1 ) )uc_road_static = isgotobig;//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if( ( ui_AA >= 10 ) || ( ui_GG >= 10 ) ){if( ( ui_AA_shadow >= 50 ) || ( ui_GG_shadow >= 50 ) )uc_road_static = isgooutroadbig;else if( ( ui_AA_shadow >= 15 ) || ( ui_GG_shadow >= 15 ) )辽宁工程技术大学毕业设计(论文)else if( ( ui_AA >= 2 ) || ( ui_GG >= 2 ) )uc_road_static = isbigturnroad;}else if( ( ui_AA >= 1 ) || ( ui_GG >= 1 ) )uc_road_static = isbigturnroad;go_flag=go_flag&0x01;}if( see_blackline > 50 ){Vf=((AD_Data[uc_AD_Data_divmin_F_count]-AD_Data_min[uc_AD_Data_divmin_F_count])*100)/ee_AD _Data[uc_AD_Data_divmin_F_count];if( Vf> 95 ){if( uc_road_static > 3 ){if( uc_AD_Data_divmin_F_count > 3 ){uc_AD_Data_divmin_F_count = 6;uc_AD_Data_divmin_S_count = 6;}else{uc_AD_Data_divmin_F_count = 0;uc_AD_Data_divmin_S_count = 0;}uc_road_static = isgooutroadbig ;PORTB=0;}}}//*************路线处理****************************************************Vf=((AD_Data[uc_AD_Data_divmin_F_count]-AD_Data_min[uc_AD_Data_divmin_F_count])*100)/ee_AD _Data[uc_AD_Data_divmin_F_count];Vs=((AD_Data[uc_AD_Data_divmin_S_count]-AD_Data_min[uc_AD_Data_divmin_S_count])*100)/ee_AD _Data[uc_AD_Data_divmin_S_count];if( uc_AD_Data_divmin_F_count < uc_AD_Data_divmin_S_count )i_Position=( Position[uc_AD_Data_divmin_S_count]+Position[uc_AD_Data_divmin_F_count] )/2+(((int)(Vf *Position_R[uc_AD_Data_divmin_F_count]-Vs*Position_R[uc_AD_Data_divmin_S_count])/17)/10);i_Position=( Position[uc_AD_Data_divmin_S_count]+Position[uc_AD_Data_divmin_F_count] )/2+(((int)(Vs *Position_R[uc_AD_Data_divmin_S_count]-Vf*Position_R[uc_AD_Data_divmin_F_count])/17)/10);if( uc_AD_Data_divmin_F_count == 0 && Vs > 80 )i_Position = Position[0] - Vf* Position_R[0] / 80;else if( uc_AD_Data_divmin_F_count == 6 && Vs > 80 )i_Position = Position[6] + Vf* Position_R[6] / 80;if( Vf > 60 && Vs > 60 ){if( uc_AD_Data_divmin_F_count == 0 )i_Position = -500 ;if( uc_AD_Data_divmin_F_count == 6 )i_Position = 500 ;}switch( uc_AD_Data_divmin_F_count ){case 0: if( abs(i_Position+460) > 150 )i_Position = -460;break;case 1: if( abs(i_Position+300) > 150 )i_Position = -300;break;case 2: if( abs(i_Position+150) > 150 )i_Position = -150;break;case 3: if( abs(i_Position) > 150 )i_Position = 0;break;case 4: if( abs(i_Position-150) > 150 )i_Position = 150;break;case 5: if( abs(i_Position-300) > 150 )i_Position = 300;break;case 6: if( abs(i_Position-460) > 150 )i_Position = 460;break;}switch(uc_road_static){case isnearlineroad:辽宁工程技术大学毕业设计(论文)PORTA =0xff;PORTA_BIT0=0;if( uc_oldroad_static == isbigturnroad )PD_Proportion=7;elsePD_Proportion=6;SetPoint = Point_nearlineroad;break;case islineroad:PORTA =0xff;PORTA_BIT1 = 0;PD_Proportion=5;uc_oldroad_static = islineroad ;SetPoint = Point_lineroad; //直道速度break;case isbigturnroad:PORTA =0xff;PORTA_BIT2=0;PD_Proportion=9;if( uc_oldroad_static == islineroad ){ //前一个状态是直道的情况/* if( Average_inCatime <= 400) //直道进入弯道速度很快的时候的处理car_static = stop_brake;else */if( Average_inCatime <= 550 )car_static = stop_nobrake;else{car_static = stop_gogo ;SetPoint = Point_bigturnroad ;uc_oldroad_static = isbigturnroad ;}}elseSetPoint = Point_bigturnroad;if( Average_inCatime <= 600 ){if( uc_AD_Data_divmin_F_count == first )i_Position = -500;else if( uc_AD_Data_divmin_F_count == seventh )i_Position = 500;}break;case isgooutroadlittle: //速度降低,舵机摆角不刹车PORTA =0xff;PORTA_BIT3=0;PD_Proportion=9;if( uc_oldroad_static == islineroad ){ //前一个状态是直道的情况/* if( Average_inCatime <= 400) //直道进入弯道速度很快的时候的处理car_static = stop_brake;else */if( Average_inCatime <= 600 )car_static = stop_nobrake;else{car_static = stop_gogo;SetPoint = Point_gooutroadlittle ;uc_oldroad_static=isbigturnroad;}}else{if( Average_inCatime <= 600 )car_static = stop_nobrake;elsecar_static = stop_gogo;SetPoint = Point_gooutroadlittle ;uc_oldroad_static = isbigturnroad;}if( Average_inCatime >= 750 ){if( uc_AD_Data_divmin_F_count == first )辽宁工程技术大学毕业设计(论文)i_Position = -460;else if( uc_AD_Data_divmin_F_count == seventh )i_Position = 460;}else{if( uc_AD_Data_divmin_F_count == first )i_Position = -500;else if( uc_AD_Data_divmin_F_count == seventh )i_Position = 500;}break;case isgooutroadbig:PORTA =0xff;PORTA_BIT4=0;PD_Proportion=9;if( uc_oldroad_static == islineroad ){ //前一个状态是直道的情况/* if( Average_inCatime <= 400) //直道进入弯道速度很快的时候的处理car_static = stop_brake;else */if( Average_inCatime <=600 )car_static = stop_nobrake;else{car_static = stop_gogo;SetPoint = Point_gooutroadbig ;uc_oldroad_static=isbigturnroad;}}else{if( Average_inCatime <= 600 )car_static = stop_nobrake;elsecar_static = stop_gogo;SetPoint= Point_gooutroadbig ;uc_oldroad_static = isgooutroadbig;}if( Average_inCatime >= 750 ){if( uc_AD_Data_divmin_F_count == first )i_Position = -460;else if( uc_AD_Data_divmin_F_count == seventh ) i_Position = 460;}else{if( uc_AD_Data_divmin_F_count == first )i_Position = -500;else if( uc_AD_Data_divmin_F_count == seventh ) i_Position = 500;}break;case islittlebig :PORTA =0xff;PORTA_BIT5=0;if( uc_oldroad_static == islineroad ){SetPoint = Point_littlebig ;PD_Proportion=7;}uc_oldroad_static = isbigturnroad;break;case isgotobig :SetPoint = Point_littlebig ;PD_Proportion=8;uc_oldroad_static = isbigturnroad;}PD_i_Position =i_Position;}。
飞思卡尔程序
I
全国大学生智能汽车竞赛
5420,5180,4920,4650,4390,4130,3870,3620,3370,3110,2840}; unsigned char Rev_High[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; unsigned int timer_count = 0; int now_position = 0; int last_position = 0; const char Mid_PointWeight[15] = {2,4,68,10,12,14,16,18,20,22,24,26,28,30}; const unsigned char Laser_Ctrl[16] = {0X44,0X41,0X40,0X15,0X14,0X10,0X05,0X04, 0X01,0X00,0X45,0X50,0X51,0X54,0X55,0X11}; unsigned char Out_flag = 0; unsigned char Scan_flag = 0; unsigned char Delay_flag = 0; unsigned char Rev_HighTemp[15][10] = { 0 }; uchar HighP = 0; uchar HighD = 0; uchar MotorP = 0; uchar MotorI = 0; uchar MotorD = 0; int Save_Position[20]; char Load_Position[20]; uint Now_Speed = 0; uint Last_motor_ctrl = 0; uchar Lcd_tableP[] = "P765432101234567"; uchar Lcd_tableD[] = "D000000000000000"; void INIT_REGISTER(void) { /****************锁相环升频 SetBusCLK_40M**********************/ CLKSEL=0X00; //disengage PLL to system PLLCTL_PLLON=1; //turn on PLL SYNR=0X80|0X09; //pllclock=2*osc*(1+SYNR)/(1+REFDV)=160MHz; REFDV=0X80|0X01; //BUS CLOCK=40M POSTDIV=0X01; _asm(nop); _asm(nop); while(!(CRGFLG_LOCK==1)); //when pll is steady ,then use it; CLKSEL_PLLSEL =1; /*********************INIT_I/O********************************/ DDRB = 0XFF; //输出
飞思卡尔光电编码器测速程序
}
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt 68 timer2(void)
{
_asm(MOVB #$07,PITTF); //clear interrupt falg
void delay_ms(uint ms)
{
volatile uint x=0;
while(ms--)
{
for(x=2800;x>0;x--)
{
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
}
}
}
//注意外接16M晶体。
//飞思卡尔推荐配置,主频道50MHZ,速度更快!
PITCFLMT|=0X80;
//time-out period = (PITMTLD + 1) * (PITLD + 1) / fBUS.
//For example, for a 50 MHz bus clock, the maximum time-out period equals:
//256 * 65536 * 20 ns = 419.43 ms.
_asm(nop);
while(!(CRGFLG_LOCK==1));//when pll is steady ,then use it;
CLKSEL_PLLSEL = 1;//engage PLL to system;
}
//500us one interrupt
飞思卡尔光电组检测起跑线
最近很多人问光电车如何检测起跑线,是红外管还是ccd,ccd需不需要另外加多一个。
其实我很想说,如果不清楚不行是实践说的话常识一下就行了,行话的,理论是辅助自己更好去实践的,并非事实就是这样,太多的因素我们无法理论推理!在这里分享一下我检测起跑线的一些经验:1、我的CCD是检测跳变沿来识别黑线的,一开始观察到当车经过起跑线的时候,是可以检测到6个跳变沿的,在其他任何的地方都不会检测到这么多的跳变沿,这是我开始检测的简单方法。
这里检测跳变沿的阈值很关键,有一个范围,动态的,其实如果你能保证每一次检测都不会检测不到或者误判黑线这6个跳变沿是没问题的。
阈值方面属于检测黑线的范围就不多说了。
2、上面检测六个跳变沿一直用的很准确的,但是当速度上到1.8以上的时候偶尔就检测不到,常识降低阈值,还行,勉强提取黑线和起跑线都没有问题。
(在这里发现如果速度继续加快的话方法就会检测不到了)3、速度要继续提高,没有办法了,想到用红外对管,不过由于是直立车,车身的角度不能很好的保持,红外对管不调制过的话距离太短,更重要的是,过障碍和坡度的时候肯定会卡到或者误判。
想着想着发现极为纠结的红外,不靠谱。
4、接着就考虑从CCD下手,加多一个CCD?加多一个的话让他斜着放速度就算是3.0还是可以检测的,不过不仅在车身重心增高,代码的时序要求更严格了,检修和维护的困难都会增加。
pass.5、最后我的决定是,减小曝光时间,增加CCD检测的周期,之前是9ms的周期,现在继续缩短,6ms。
经过测试认证,巡线白天依然毫无压力,晚上实验室灯全开,全程偶尔会有十来个6ms周期丢线之外其他地方都还ok。
起跑线检测目前还没有出现误判漏判的i情况。
以上是我在弄起跑线的一个过程,希望能帮助到有需要的的车友。
PS:送上我做车的重要心得体会:大胆的打破常局去实践才是王道,即使理论明明说是错误的,你也可以去尝试。
信心、创新、实践。
光电编码器位置检测程序
光电编码器位置检测程序1.位置检测,计算过程中的变量的定义/*-------------------------------------------------------------------- Define the structure of the QEP (Quadrature Encoder) Driver Object -----------------------------------------------------------------------------*/ typedef struct {int16 ElecTheta; // Output: Motor Electrical angle (Q15)//(输出的电角度,)int16 MechTheta; // Output: Motor Mechanical Angle (Q15)//(输出的机械角度,)Uint16 DirectionQep; // Output: Motor rotation direction (Q0)//(电机转向,)Uint16 QepCountIndex; // Variable: Encoder counter index (Q0)//(编码器输出的脉冲数,)Uint16 RawTheta; // Variable: Raw angle from Timer 2 (Q0)//(某一时刻转子对于定子A相的绝对角度,)Uint32 MechScaler; // Parameter: 0.9999/total count (Q30)//(每个脉冲所转过的机械角度,)Uint16 LineEncoder; // Parameter: Number of line encoder (Q0)//(编码器每转输出的脉冲个数,)Uint16 PolePairs; // Parameter: Number of pole pairs (Q0)//(极对数)int16 CalibratedAngle; // Parameter: Raw angular offset between encoder//index and phase a (Q0)//翻译过来是编码器与定子A相之间的角度偏量,//但不知道到底这个偏移量是指什么,请教高人Uint16 IndexSyncFlag; // Output: Index sync status (Q0) (,) void (*init)(); // Pointer to the init function//(初始化函数)void (*calc)(); // Pointer to the calc function//(位置测量,计算函数)void (*isr)(); // Pointer to the isr function//(Z信号的捕获中断)} QEP;上面的汉语解释不知道对不对,请高人过目,指出问题。
光电编码器速度测量方法
光电编码器速度测量方法
光电编码器是一种常用的速度测量设备,其工作原理是利用光电效应将旋转运动转化为电信号,用来测量旋转物体的角速度。
在实际应用中,为了获得更精确的测量结果,需要采用一些特殊的方法来提高测量精度。
第一种方法是使用多个光电编码器。
通过将多个光电编码器分别安装在被测物体的不同位置上,可以获得更加准确的旋转速度信息。
在实际应用中,通常会使用三个或更多的光电编码器,分别测量被测物体的不同位置。
第二种方法是使用边沿计数器。
边沿计数器是一种精密的计数器,可以对光电编码器输出的电信号进行精确的计数。
通过对边沿计数器进行配置,可以实现高速的计数和计算,从而提高测量精度。
第三种方法是使用数字信号处理器。
数字信号处理器可以对光电编码器输出的信号进行数字滤波和处理,从而提高测量精度。
通过对输入信号进行数字滤波和滤波器设计,可以获得更加稳定和精确的测量结果。
综上所述,光电编码器速度测量方法有多种,每种方法都有其优缺点和适用范围。
在实际应用中,需要根据被测物体的具体特点和测量要求,选择最合适的测量方法,从而获得更加准确和可靠的测量结果。
- 1 -。
飞思卡尔智能车S12XS128PWM控制程序编写
飞思卡尔智能车S12XS128PWM控制程序编写SeptStringS原创,转载请注明。
对于飞思卡尔智能车,电机和舵机的控制通常使⽤的都是以PWM脉冲宽度调制的⽅法实现的,其可⾏性基于电机可以由占空⽐控制转速,⽽舵机也由脉宽控制摆动。
PWM 调制波有 8 个输出通道,每⼀个输出通道都可以独⽴的进⾏输出。
每⼀个输出通道都有⼀个精确的计数器(计算脉冲的个数),⼀个周期控制寄存器和两个可供选择的时钟源。
每⼀个 PWM 输出通道都能调制出占空⽐从 0—100% 变化的波形。
PWM控制程序的编写⼀般按照以下的⼀种流程:1,禁⽌PWM模块;//这是由于改变周期和脉宽等操作需要在PWM禁⽌的情况下才能被设置2,PWM级联选择,是否级联通道67,45,23,01;//最多单独使⽤8个8位和级联使⽤4个16位3,给通道选择时钟源控制位;//0,1,4,5通道可选择ClockA和ClockSA;2,3,6,7通道可选择ClockB和ClockSB4,给时钟源A\B预分频;//可对总线时钟进⾏预分频,确定ClockA和ClockB,满⾜1,2,4,8,16,32,64,128这8个分频量5,根据时钟源A\B确定时钟源SA\SB;//由ClockA和ClockB、分频设值来确定ClockA和ClockB,满⾜1-255的分频量6,输出极性的选择;//也就是选择输出极性先低后⾼还是先⾼后低7,对齐⽅式的选择;//可设置为左对齐或者中间对齐⽅式8,实际通道频率的计算;//也就是周期的设定9,占空⽐寄存器的设置;//占空⽐常数的设定,可以以此决定占空⽐10,使能PWM模块。
//你已经⾸尾呼应了,有⽊有接下来通过寄存器的介绍,以上⾯流程为⼤纲,详细地说明⼀下该如何操作~~【PWME】寄存器PWME = (PWME~7 | PWME~6 | PWME~5 | PWME~4 | PWME~3 | PWME~2 | PWME~1 | PWME~0)将每⼀位设置为1即可使能该位,0对应的既是禁⽌。
飞思卡尔编码器调整波形教程
模拟编码器调整教程
在开始,鄙视某些没有道德的卖家,出来混,早 晚要还的,只是时间问题!
对照编码器的四根线,橙色,红色,棕色,黑色顺序连接到提供的小 PCB 板子上! 如图:
编码器对外只有三个接口,请看上图,三个接口分别为 GND 5V,分别为电源地,信号(方波信号)输出,和电源正(3.3-5V)
OUT
接下来我来详细说说调节过程: 首先,本店编码器在发货前,都已经将精密可调电阻的参考电压值调 节到了最佳,所以,一般情况下,您是不需要再做任何调整,但是如果您 不放心,那么您可以再按照我们下面提供的方法再调节一次,然后将可调 电炉的可调旋钮固定死,这样以后就不用再调节了! 然后将编码器按照我提供给您的安装图安装在车子上,注意齿轮不要 咬合的太紧,太紧的话会增大阻力,减少电机的寿命。
安装好后,通上电源,将示波器的探针接到 SIGNAL 引脚上,示波器 的 GND 接到电路的 GND 上, 然后我们继续进行下面特别重要的调试步骤, 仔细看: 首先,给电机通电,让电机以最高的转速的运转,然后,用小改 锥,慢慢的调节精密可调电阻,直到示波器屏幕上出现一个方波,占空比 调节到 50%左右为止,最好就是 50%。
这样不管你的车子跑多快,波形绝 对超级稳定!然后将可调电阻调节螺丝处用热熔胶水封起来,保证不再被 改动,然后接到单片机的 PT7/IOC7 口,将我提供给您的初始化程序放在 你的初始化函数中,这样就可以定时读取测速脉冲了,然后配合您的 PID 程序,就可以闭环调节速度了! 最后调节好的波形如下图:
。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
//time-out period = (PITMTLD + 1) * (PITLD + 1) / fBUS.
//For example, for a 50 MHz bus clock, the maximum time-out period equals:
//256 * 65536 * 20 ns = 419.43 ms.
#include <hidef.h> /* common defines and macros */
#include <MC9S12XS128.h> /* derivative information */
#pragma LINK_INFO DERIVATIVE "mc9s12xs128"
volatile uint speed_back=0,temp=0;
/* please make sure that you never leave this function */
}
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt 68 timer2(void)
{
_asm(MOVB #$07,PITTF); //clear interrupt falg
void Init_PLL(void)
{
CLKSEL = 0X00;//disengage PLL to system
PLLCTL_PLLON = 1;//turn on PLL
SYNR = (0xc0|0x18); //SYDIV=0X18=24
REFDV = (0x40|0x07); //REFDIV=0X07=7
SCI0BDH=0x01;
SCI0BDL=0x46;
实际波特率是:9585
****************************************************/
}
void UART_Send(uchar data)
{
while(!(SCI0SR1&0x80));//keep waiting when not empty
SCI0DRL = data;
}
void main(void) {
Init_PLL();
UART_Init();
Init_Event_Count();
Init_PIT_Timer();
/* put your own code here */
EnableInterrupts;
for(;;) {} /* wait forever */
}
void Init_Event_Count(void)
{
PACTL = (1<<6);//脉冲累加器启动,外部发生一次下降沿就计数一次。外部编码器连接到IOC7.
//在中断里读取PACNT的值就是脉冲个数。读取后清零PACNT。
}
void UART_Init(void)
{
SCI0CR2 = 0x0C;
_asm(nop);
while(!(CRGFLG_LOCK==1));//when pll is steady ,then use it;
CLKSEL_PLLSEL = 1;//engage PLL to system;
}
//500us one interrupt
void Init_PIT_Timer(void)
SCI0BDH = 0x00;
SCI0BDL = 0xa2;
/****************************************************
当波特率为19200,主频为50MHZ时:
SCI0BDH=0x00;
SCI0BDL=0xa2;
实际波特率是:19170
当波特率为9600,主频为50MHZ时:
void delay_ms(uint ms)
{
volatile uint x=0;
while(ms--)
{
for(x=2800;x>0;x--)
{
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
}
}
}
//注意外接16M晶体。
//飞思卡尔推荐配置,主频道50MHZ,速度更快!
temp++;
if(temp>3) //10MS读取一次速度
{
speed_back = PACNT;//返回速度值
PACNT = 0;//速度归零
UART_Send(speed_back&0X00FF);
speed_back=0;
temp=0;
}Байду номын сангаас
}
#pragma CODE_SEG DEFAULT
POSTDIV = 0x00; //pllclock=2*osc*(1+SYDIV)/(1+REFDIV)=100MHz;
_asm(nop); //BUS CLOCK=50M
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
{
PITCFLMT=0X00;
PITCE|=0X07;
PITMUX|=0X04;//BASED 0 timer2 based 1
PITMTLD1=49; //
PITLD2=2499; //temer 2 2.5MS一次中断
PITTF|=0x07; //clear interrupt falg
PITINTE|=0X07;//ENABLE TIMER0 INTERRUPT