目录

开篇

	   博主最近开始学智能车,开始时遇到了很多困难。我觉得这些问题应该也
是每一个智能车人开始都可能会遇到的,写下来分享一下,也顺便巩固一下自
身所学。如果有错误或可以改进的地方还希望多多指出交流~。

这是博主的第一篇文章,如果觉得有帮助还希望点赞收藏支持一下~

舵机

      首先要说说舵机,舵机是让小车车跑好的一大重要因素,网上有很多有关不
      同种类舵机的详细原理和使用。这里我就简单说说

  1. 舵机的作用是控制智能车轮子转向。通过输入不同的脉冲信号来使舵机有不同大小的打角,比如你输入的pwm等于750时舵机打角位于中间,则小车直走,大于750时舵机打角偏向右边,则小车左转。
  2. 通过处理图像中线位置来给舵机输入对应脉冲信号来控制打角。先对你摄像头拍到的图像进行图像处理(摄像头原理在这不过多解释,后面会大致讲一下简单的图像处理)。比如你的屏幕中线的x坐标为50,而你图像处理后得到的中线x坐标为70,说明你的车偏右了(这里要注意我的坐标系零点是屏幕右下角),要让车左走回正,这时你就要输入对应的脉冲信号,让舵机控制车子向左转。
  3. 在写对舵机的控制前请一定要让舵机摆正!先写固定的脉冲信号让舵机打一个固定角度,然后轻推小车,小车能沿直线走,就说明摆正了,再进行之后的调试。

赛道图像处理

怎么处理赛道应该是难点之一了,这里博主只介绍直道和90°弯道,其他的可能有后续更新吧。

图像处理

 智能车(摄像头)的图像处理主要就是识别出左右边线(一般边线是黑线,外边
 是蓝布,中间赛道是白色),然后拟合出中线,让车子沿着中线跑。

这里我推荐新手使用左右寻线法来拟合中线,至于为什么不用八邻域法我只能说,新手阶段不需要贪那运算速度,左右寻线法写起来容易理解,能跑完赛道最重要,优化算法是之后的事情了。

代码在这里插入图片描述

middle是存放中线x坐标的数组
left是存放左边线x坐标的数组
right是存放右边线x坐标的数组
Pixels是像素坐标数组,由摄像头读出并处理生成
pixels为1是白,为0是黑,屏幕x坐标是从0到185

这里放一个我判断左边界的部分代码,首先第0行是从中间开始往左右扫线,比如我这个第0行应该从x=93开始左右扫线 (那我这里为什么是从middle[y-1]开始呢,因为我这是从第1行开始的,我第一行中间起始点是用第0行的中线,第二行中间起始点是用第一行的中线坐标,以此类推) 。以找左边线为例子,右边线类似。从中间起始点开始向左边扫描,如果扫描到白黑黑的部分,则认定为找到左边线,将左边线记录下来。右边线也是找到白黑黑的组合,记录下左右边线。中线就是左右边线之和除2
至于我为什么还有个x==184的条件,其实这是用在弯道处,在这里插入图片描述
这是我将弯道图片上传到上位机后得到的图像,左边是原图,右边是图像处理以后的。可以发现有时左边一直到屏幕边界都还是白色,所以我让左扫描到最左边时,将x=184作为了左边界(其实还有更好的处理的方式,但这里只是介绍给新手们最基本的)。右边同理有个x == 0的边界判断。

小贴士

  1. 第一帧图像的第0行中间起始点可以选屏幕中间点,因为发车都是直道发车,一般不存在第0行中间像素点为黑的情况。之后每一行中间起始点都是前一行的中点(这样可以防止拐弯时中线丢失)。此后第二帧开始,第0行的中间起始点就选择上一帧的第2行的中点(选第几行按照自己情况而定),这样做其实也是在防止拐弯时中线丢失(中线丢失是什么情况还是希望大家可以自己去尝试一下,有时会发现拐弯到一半车子突然直行,只有自己经历过才能更好理解这些方法)
  2. 做好赛道类型判断。通过你处理后得到的中线趋势来判断现在是直道还是弯道
// 赛道类型判断
    int i;
    float sum1 = 0;
    float sum2 = 0;

    for(i=0 ; i<20 ; i++)
    {
        sum2 += (94-middle[i])*(94-middle[i]);
        sum1 += (94-middle[i]);
    }

    if(sqrt(sum2)/20 > 3.2 || sum1/20 > 18.5 || sum1 < -18.5)
    {
        choose = 1;                     //弯道
    }else
    {
        choose = 0;                     //直道
    }

我这里通过图像中线和屏幕中线的方差和平均值来判断赛道类型,这么做有什么好处呢?有时你会发现,走直道时车一直在左右摇摆,就有可能你没有分类赛道,直道和弯道用的同一个PID算法,这会导致直道有点歪时小车想打角来走直线,却用的是弯道的打角,导致打角太大了,就会一直左右摇摆。以后写什么小弯道啊,环岛的也是要判断的。
下面是我直道的PD算法,直道的PD给的就很小,因为就是微调,弯道的PD要给大一点(要问为什么不写i,因为我之前忘记写了…)

float kp1 = 0.2;
float kd1 = 0.4;
void zhidao()
{

    float cha=0;
    cha = 94 - middle[17];                //与中线差值
    duty = (int)(780 - kp1*cha - kd1*(cha - last));
    if(duty>840)
        {
            duty = 840;
        }
        if(duty<700)
        {
            duty = 700;
        }
    //    systick_delay_ms(STM0,20);
        pwm_duty(ATOM0_CH6_P02_6,duty);
        pwm_duty(ATOM1_CH4_P22_3,duty_car_z);
        pwm_duty(ATOM1_CH0_P22_1,0);
        pwm_duty(ATOM1_CH6_P23_1,0);
        pwm_duty(ATOM2_CH5_P33_13,duty_car_z);
}

图像处理控制舵机打角

其实控制舵机打角也是上边的代码
在这里插入图片描述
上位机直道图

    float cha=0;
    cha = 94 - middle[17];                //与中线差值
    duty = (int)(780 - kp1*cha - kd1*(cha - last));
    ...
    ...
    pwm_duty(ATOM0_CH6_P02_6,duty);

这里的duty就是我输出给舵机的脉冲信号,来控制小车在直道时的打角

cha是屏幕中线和第17行中线的差值,用于下面的计算
last是上一次的cha值
这个第17行是根据你摄像头高度来选择的,有很多种方式取这个值

最后亿点

小车最开始调试时,可以给直道和弯道不同的PWM,弯道可以慢速点过,保证平滑,
直道再加速。这里面有很多门道的,博主也在慢慢摸索。
新手想要车能跑正方形赛道,最难的应该是图像处理部分了,这部分我其实主要在
讲一些问题,原理性的可能不太详细,因为这是第一次写博客,很多想法很难表达
出来,大家可以先收藏,然后看看网上左右寻线详细原理,等到写上车后发现问题,
再来看应该会更多体会与帮助。

我也是刚刚开始的智能车小白,希望大家能一起互帮互助,一起进步!如果觉得有帮助,还希望点赞收藏多多支持一下~

最后有一句话分享给大家和我自己:如果你的车没有撞过,就说明速度还不够快!加油智能车人!