资讯 DIY
此为临时链接,仅用于文章预览,将在时失效

高性能循迹跟踪小车,怎么在比赛中击败对手?

作者:吴攀
2015/12/04 09:56

高性能循迹跟踪小车,怎么在比赛中击败对手?

编者注:本项目来自Instructables,作者为newtonis。这是一个用于比赛的循迹跟踪小车项目,他是怎么在兼顾尺寸和速度性的同时满足小车高性能的要求的呢?

循迹小车在创客圈里面并不是什么新鲜事,但普通的循迹小车要么比较大,要么则比较重,并不适合用来比赛。在我们当地的创客圈子里面有一个循迹小车的比赛项目,要求上场的小车的尺寸不能超过12x20cm,那我们该怎样来满足这样的需求呢?

本项目的主要开发过程分为三个部分:电子构建,结构设计和3D打印,程序配置和调试。下面我们就来完成它吧。

第一步:电机

高性能循迹跟踪小车,怎么在比赛中击败对手?

在开发此项目的过程中,要切记的一点是我们是在开发一个比赛用的小车。此处我选用了Pololu提供的电机,他家的电机分为四种:低功率、中等功率、高功率和长寿命高功率,这四种电机的工作电压都为6V,而且物理尺寸也基本相同。低功率的电机功耗较低,但是要知道我们这是为了比赛,所以应该选择那两种高功率的电机。其中长寿命高功率的电机的使用寿命更长,但是并不能承受高于6V的电压。综合考虑之后,我选择了高功率的电机,它们能够不中断地连续使用好几个小时,这已经足够了。

高性能循迹跟踪小车,怎么在比赛中击败对手?

接下来我们应该选择多少的传动比呢?通常电机的传动比越高,电机的速度就越低,但是电机提供的扭矩却更高,就能提供更高的加速度。对比较重的机器人来说这确实非常重要。我的建议是在30:1到10:1的传动比之间做出选择,最后我选择的四个传动比为10:1的电机,毕竟是为了比赛,我会尽量降低小车的质量,从而提供更高的速度。当然,你也可以选择使用2个30:1的传动比的电机,这样为了获得更高的速度,你需要为电机提供高于6V的电压。

第二步:车轮

高性能循迹跟踪小车,怎么在比赛中击败对手?

因为电机的速度是以每分钟的转速衡量的,所以在转速固定的情况下,轮子直径越大,理论上就跑得越快,但与此同时轮子也会越重。综合考虑之后我选择了直径32毫米的窄边车轮,其单个重量为3.2克。

第三步:电池

高性能循迹跟踪小车,怎么在比赛中击败对手?

电池方面我推荐使用储能密度大、可充电的LiPo电池。我使用的是850mAh 7.4V双芯LiPo电池

第四步:球脚轮

高性能循迹跟踪小车,怎么在比赛中击败对手?

为了能让小车的电机获得足够的反应时间,需要将小车的循迹探测器尽量前置,那么这就需要用到2个前置的球脚轮.当然这两个球脚轮并不是必需的,如果你的小车的设计能够在行进过程中维持平衡,或者只是采用后轮驱动的方式运动(将探测器安装在车体前部),那么就不需要这两个球脚轮。

注意两只球脚轮的相对位置,不要让其对小车的行进方向产生影响。

第五步:小车结构

高性能循迹跟踪小车,怎么在比赛中击败对手?

为了在保证小车基本结构上尽量降低小车的质量,我选择自己设计小车的结构件。点击这里下载我用Google SketchUp设计的3D结构模型,然后用3D打印机打印出来即可。注意,打印之前需要导出适合3D打印机的STL文件。

高性能循迹跟踪小车,怎么在比赛中击败对手?

第六步:探测器组件

这一步我需要搭建能够用来探测地面标线的探测器设备。这里我用到了9个CNY70光电传感器(5个或7个应该也可以),9个220Ω电阻和9个56kΩ下拉电阻。另外我还设计了一个简易的PCB板用来承载我的电路结构。

高性能循迹跟踪小车,怎么在比赛中击败对手?

这套探测器的原理很简单,每个CNY70传感器都会产生0-5V的电压,其中0V左右表示探测到黑色,5V左右则是白色。CNY70提供了0-1024的精度范围。

高性能循迹跟踪小车,怎么在比赛中击败对手?

电路板上一共引出了11个接口,其中两个分别是接地和5V电源,其它9个是传感器的模拟输出。电路本身并不复杂,复制以下电路9次即可。

高性能循迹跟踪小车,怎么在比赛中击败对手?

第七步:主电路设计

探测器的电路不复杂,主电路却相对较为复杂一点。这里我们没有使用常见的Arduino,而是使用了PIC18F4550单片机,因为其体积更小,而且在某些比赛中是禁止使用Arduino的。

电路设计如下:

高性能循迹跟踪小车,怎么在比赛中击败对手?

高性能循迹跟踪小车,怎么在比赛中击败对手?

相关文件:

主电路的组件清单如下:

  • PIC18F4550单片机

  • 20MHz晶振

  • 3到6个LED(PCB上只使用了3个)

  • 3个220欧姆电阻(用于LED)

  • 2个10nF陶瓷电容

  • 2个18nF陶瓷电容

  • L293D或SN7544(电机驱动模块)

  • 开关

  • 三个按钮

  • 7805三端稳压器(为单片机提供5V电压)

  • 线材等

接下来就是制作对应的PCB板。

高性能循迹跟踪小车,怎么在比赛中击败对手?

然后将各个组件焊接到PCB上。

高性能循迹跟踪小车,怎么在比赛中击败对手?

第八步:编程

高性能循迹跟踪小车,怎么在比赛中击败对手?

接下来就要对我们机器人的大脑做文章了。这里我使用的是MPLAB XC8编译器和Sublime Text作为开发环境。具体的安装过程这里不提,这里提供了Sublime Text用来构建和运行XC8的命令行代码,你需要用它来配置XC8的路径和安装PK2CMD。

rayito.c是我编写的代码,下一个步骤我会对其中一些代码进行一些说明。

第九步:代码解析

代码的工作原理示意图:

高性能循迹跟踪小车,怎么在比赛中击败对手?

各个传感器的工作模式示意图:

高性能循迹跟踪小车,怎么在比赛中击败对手?

传感器的精度为0-1024,但事实上我们的测量基本上不可能达到两边的顶点(纯黑和纯全反射)。那么我们就可以对传感器得到的数值进行定义,低于A值都定义为黑色,高于B值都定义为白色,则有0<=A<=B<=1024。

对传感器的读数进行调试和校准:

void initLED(){ ///初始化读数变量,在程序启动时调用一次

    int x;

    for (x = 0;x < 8;x++){

        amax[x] = 0; ///Amax是上面提到的B值

        amin[x] = 1024; ///Amin是上面提到的A值

    }

}

void CalRead(){ ///读取校准数值

L_ROJO = T1000 < 500*6; ///红色LED闪烁

    int x;

    for (x = 0;x < 7;x++){  //跟踪传感器

        /***注意: 使用T(x)是因为其在程序的第一部分就进行了定义,让排成列的传感器能够以正确的顺序排列。***/

        amax[x] = max(amax[x],T(x)); ///如果得到的值高于上一次值则替代

        amin[x] = min(amin[x],T(x)); ///如果得到的值低于上一个值则替代

    }

    ///不能使用T(7)加入第7个传感器的数值,该传感器不用于读路线。. 

    ///我们用其来读取某些赛道特定的曲线路径标记。

    

    amax[7] = max(amax[7],J(7));  

    amin[7] = min(amin[7],J(7));

}

经过了此段之后,我们会得到7个由传感器产生的数值,并将其存储在C数列中,每一个传感器都有amin (A)和amax (B)值。那么在程序进行标准取值时,我们将小于A的值都当成A,将大于B的值都当成B。中间值忽略。

///这是伪代码,不能直接工作,只用于了解原理

///在实际代码中,amax[x]是B而amin[x]是A

int w = W[x]; ///W[x] 取值0~1024

w = min(w,B); //如果w大于B,则w=B

w = max(w,A); //如果w小于A,则w= A

w -= A; ///让w逻辑上取值在0到B-A

w *= 1024; ///w取值为(0到B-A)*1024

w /= (B-A); ///现在w取值为0 到1024

第十步:加权平均

高性能循迹跟踪小车,怎么在比赛中击败对手?

这一部分算法是我们实现高性能的关键部分之一。在本算法中,用于取平均数的数字的价值越高,其对最终平均数的影响就越大。这样我们的算法就不只是以下的算法那么简单了:

if (S1 see black){

Left();

}else if (S2 see black){

Right();

}else{

Front();

}

为了真正造出一个高性能的机器小车,我们需要尽可能准确地确定路线的中心线。使用传感器进行测量时,每一个程序循环中我们都可以得到5组不同的中心线位置,而我们需要通过加权平均的方式将这5个数值转变成一个数值。

void Ponderado(){    sum = 0;

    division = 0;

    nove = 0;

    char center;

    for (x = 0;x <= 6;x++){

 

if(T(x)>amax[x]){

w=amax[x];

}else if(T(x) < amin[x]){

w=amin[x];

}else{

w=T(x);

}***/

 

w = ran(T(x),amin[x],amax[x]);

        w -= amin[x];

        w *= (ll)1000;

        w /= (amax[x]-amin[x]);

        if (w > TH){

            nove = 1;

        }

        if (x == 3){

            if (w > TH){ center = 1; }else{ center = 0; } ///We store here if the center sensor reads 0 or 1000

        }

        ///A is the weight

        ///B is the position

        if (x == 0 or x == 6){ continue; } ///We ignore the sensors 0 and 6

v = (1000) * (x-3);///This variable will be -2000,-1000,0,1000,2000 in each cycle

        sum += (w*v); 

        division += (w);

    }

   if (nove == 0){ ///if we don't see the line        POSICION = POSICION > 0 ? 200 : - 200; ///Now we set the value accordingly the last value set. if posicion is > to 0 then posicion equals 200, if not it equals -200

        

    }else{

        POSICION = (ll)(sum) / (ll)(division); ///We get the weighted average result

        POSICION /= 10; ///We change the scale from -2000,2000 to -200,200

    }

}

第十一步:路径跟踪

确定了中心线之后就需要控制电机对线进行跟踪了。由于我们采用的电机并不具有直接转向的功能,我们需要用到另一种转向方式:速度差转向——通过为小车的轮子设定不同的速度从而让小车整体产生转向效果。控制速度则用到了常用的脉冲宽度调制,这一部分整合到了小车的代码中。此处我们需要用到一个函数MotorsSpeed(a,b),其将定义电机的速度,并将其设置到区间(-1000,1000)之间,包括前后速度。

void MotorsSpeed(int A,int B){

///If mode equals alfa then we invert the motors voltage

    MotorASpeed(MODE == ALFA ? A : B); 

    MotorBSpeed(MODE == BETA ? A : B);

}

void MotorASpeed(int S){

S = min(S,1000); 

S = max(S,-1000);

    

    ADIR = S > 0 ? 0 : 1;

    S = S > 0 ? S : 1000 + S; 

    

    CCP1CONbits.DC1B1 = S % 4;

    CCPR1L = S / 4;

}

void MotorBSpeed(int S){

    S = min(S,1000);

    S = max(S,-1000);

    

    BDIR = S > 0 ? 0 : 1;

    S = S > 0 ? S : 1000 + S;

    

    CCP2CONbits.DC2B = S % 4;

    CCPR2L = S / 4;

}

高性能循迹跟踪小车,怎么在比赛中击败对手?

实现了对电机的速度控制,就可以实现转向算法了。

void LineFollow(){

    double kp,kd,kr,speed;

///POSICION has the value of the center of the line previously calculated

    kp = KP[speedMode];

    kd = KD[speedMode];

    kr = KR[speedMode]; 

    DER = POSICION - LP; ///We calculate how much the line has moved from the last iteration

    PIDf = (POSICION* kp + DER * kd);

 

        if (PIDf > 0){

            MotorsSpeed(Mr(speed-PIDf,kr) , speed); ///Mr makes the value to multiply by KR if it is negative. You can delete it        

}else{

            MotorsSpeed(speed , Mr(speed+PIDf,kr) ); ///Mr makes the value to multiply by KR if it is negative. You can delete it

        }

    LP = POSICION;  ///We store the last line position

}

高性能循迹跟踪小车,怎么在比赛中击败对手?

第十二步:完成

部署好了算法也就大功告成了,接下来就该拿到赛场上比试比试。哦,看起来高手还是挺多的嘛……

2015-2016赛季全球创客马拉松深圳大学站持续报名中!关注“硬创邦”(微信号:leiphone_bang),回复“深大”即可参与报名!而且,雷锋网在未来三个月内选一个合适的时间,在北上深选择一个地点,举办创马“火星救援”专场!详情可点击此处了解。

此外还可加入全球创客马拉松主群(群号:259592983),参与我们的互动讨论~

高性能循迹跟踪小车,怎么在比赛中击败对手?


长按图片保存图片,分享给好友或朋友圈

高性能循迹跟踪小车,怎么在比赛中击败对手?

扫码查看文章

正在生成分享图...

取消
相关文章