vlambda博客
学习文章列表

线性CCD循迹小车制作——常用算法

如果说硬件是小车的躯体,那么软件就是小车的灵魂。

                                                                                         ——沃兹基·硕德


控制的核心就是算法,无论是信号量的采集还是处理,都离不开算法的存在,一个良好的算法可能能省去很多冗长的、枯燥的代码,当然要是对自己的代码和思路有相当自信的话,也是可以尝试一下(《太吾绘卷》永远滴神)。


一、排序算法

1、桶排序

实现原理如下图,以数组下标存放对应数据,再对数组内部有数据存在的“桶”进行打印输出即可排序。

示例代码如下:

#include <stdio.h>int main (){int book [ 1001 ] ,i,j,t ,n;for( i=0 ; i<=1000 ; i++){ book [ i]=0 ;}scanf"%d" ,&n);//输入一个数n,表示接下来有n个数for (i=1; i<=n ; i++)//循环读入n个数,并进行桶排序for(i=1;i<n;i++){  scanf ( "%d" ,&t) ;//把每一个数读到变量t中 book [t]++;//进行计数,对编号为t的桶放一个小旗子}for(i=1000; i>=0; i--){  //依次判断编号1000~o的桶 for(j=1;j<=book [i];j++){    //出现了几次就将桶的编号打印几次 printf ( "%d " ,i) ; } } getchar( ) ;  getchar ( ) ; return 0 ;}

2、冒泡排序

如果有n个数进行排序,只需将n-1个数归位,也就是说要进行n-1趟操作。而“每一趟”都需要从第1位开始进行相邻两个数的比较,将较小的一个数放在后面,比较完毕后向后挪一位继续比较下面两个相邻数的大小,重复此步骤,直到最后一个尚未归位的数,已经归位的数则无需再进行比较实现原理如下图:

线性CCD循迹小车制作——常用算法

示例代码:

#include <stdio.h>int main( ){int a [ 100 ] ,i,j,t,n;scanf ( "%d" , &n) ;//输入一个数n,表示接下来有n个数for(i=1; i<=n ; i++)/l/循环读入n个数到数组a中 scanf ( "%d" ,&a[i] ) ;//冒泡排序的核心部分for ( i=1; i<=n-1 ; i++){ //n个数排序,只用进行n-1趟 for(j=1;j<=n-i;j++){    //从第1位开始比较直到最后一个尚未归位的数,想一想为什么到n-i就可以了。 if(a[j]<a[j+1])//比较大小并交换 { t=a[j]; a[j]=a[j+1] ; a[j+1]=t; } } } //输出结果for ( i=1; i<=n ; i++) printf ( "%d " ,a [i ] );getchar ( ) ; getchar ( ) ;return 0;}

3、快速排序

快速排序基于二分法的思想,平均复杂度为O(NlogN)。一组数据中选定基准数之后根据基准数对数据进排序,小于基准数的排左侧,大于基准数的右侧,然后将基准数归位,将左右两侧的数据分段为新的两组数据进行排序。可以看出这个不断进行二分法细分的过程实际上是个递归过程。算法过程如下:

线性CCD循迹小车制作——常用算法

示例代码:

#include <stdio.h>int a [101] ,n;//定义全局变量,这两个变量需要在子函数中使用void quicksort ( int left, int right)( int i,j,t , temp ;if(left>right) return ;  temp=a[ left]; // temp中存的就是基准数i=left; j=right ; while(i!=j){ //顺序很重要,要先从右往左找 while(a[j]>=temp && i<j) j--; //再从左往右找 while(a[i]<=temp && i<j) i++; //交换两个数在数组中的位置   if( i<j){      //当i和j没有相遇时      t=a[i];a[i]=a[j];a[j]=t;    }  } //基准数归位 a[left]=a [i]; a[i] =temp; quicksort (left ,i-1);//继续处理左边的,这里是一个递归的过程 quicksort (i+1,right) ;//继续处理右边的,这里是一个递归的过程}

二、滤波算法:


1、中值滤波

结合上文描述的排序算法对数据进行排序,采取中位数作为有效值参与决策。


2、均值滤波

对采集到的多个数据求和平均,取得的平均数作为有效值参与决策。


3、中值+均值

排序完成后取中值及中值附近的多个数(数据可信程度都较高),再对这些数据进行中值滤波。


4、互补滤波

适用于(数据变化慢但是可信程度高)+(数据变化快但会出现坏值)的两组数据的滤波。放在智能车上最直观的体现就在陀螺仪的短期测得的值比较准,但是由于存在温漂,经过积分,长期就不能用了。所以要通过加速度计进行修正角度,但是加速度计的短期不行,噪声比较大,所以要将陀螺仪高通,加速度计低通后进行一定比列的融合。才能比较准确的反应角度的变化。


5、卡尔曼滤波

也是跟互补滤波一样适合融合两种数据进行滤波。具体实现过程篇幅较长,不赘叙。


三、控制算法:

1、绝对式PID

PID理论公式是连续的,但是数字控制需要离散量,将理论公式离散后得到的离散后的绝对式(位置式)PID公式如下:

线性CCD循迹小车制作——常用算法

而由于积分环节和比例环节的参数是积分时间和微分时间和时间常数的关系,但是最终参数由人为整定,所以可以简化为以下公式:

线性CCD循迹小车制作——常用算法

err(K)表示系统输入的偏差,err(K)=rin(K)-rout(K);

C语言实现:

pid.err=pid.SetSpeed-pid.ActualSpeed;pid.integral+=pid.err;pid.voltage=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);pid.err_last=pid.err

2、增量式PID

由上文的位置式PID可得:

增量式PID是以增量的形式往系统里输出的,

增量式的表达结果和最近三次的偏差有关,这样就大大提高了系统的稳定性。需要注意的是最终的输出结果应该为:

u(K)+增量调节值;

C语言实现结合位置式和其C语言实现即可得出。




篇幅有限,具体实现过程详解和滤波算法的C语言实现我会开个专栏进行详细描述(如果不鸽的话......),不定时更新。https://blog.csdn.net/Crazy_Diamond_?spm=1010.2135.3001.5421