智能车制作

 找回密码
 注册

扫一扫,访问微社区

查看: 3969|回复: 20
打印 上一主题 下一主题

《飞思卡尔光电结束散尽经验和程序》

  [复制链接]

4

主题

11

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
410
威望
209
贡献
111
兑换币
116
注册时间
2014-3-9
在线时间
45 小时
毕业学校
安徽大学
跳转到指定楼层
1#
发表于 2014-7-31 17:43:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
做智能车的过程中,如果有一天我把车做出来了,并且做的不错,我会把代码以及思路贡献出来,让以后做车的同学们少走些弯路,我们是省赛一等奖,所以看看还是有些意义的。
我是做光电的,不知道其他智能车是怎么写的,但根本都差不多。光电车控制简单分为3部分:寻迹,方向控制,电机控制。
首先我是基于lpld库写的程序,如果没看懂的话可以稍微了解下这个库
寻迹:首先进行ccd采集,有人搞半天都不知道曝光时间是什么东西。你可以大致的认为曝光改变ccd电压作用的,你可以先用静态曝光试试看,如果算法写的好的话,再用动态曝光。我们没用曝光程序,有人觉得不可思议,其实是可以的,我们用的是固定6ms采集。
void ImageCapture(uint8 * ImageData)     //图像采集128个点
{
  unsigned char i;
  CCD_SI1; // SI = 1
  delay200ns();
  CCD_CLK1; // CLK = 1
  delay200ns();
  CCD_SI0; // SI = 0
  delay200ns();
  //delay 20us for the first pixel
   delay10us();
   ImageData[0]=LPLD_ADC_Get(ADC0,AD8);
   CCD_CLK0; // CLK = 0
   for(i=1;i<128;i++)
    {
     delay200ns();
     delay200ns();
     CCD_CLK1;   //CLK=1
     delay200ns();
     delay200ns();
     ImageData=LPLD_ADC_Get(ADC0,AD8);
     CCD_CLK0;   //CLK=0
    }
     delay200ns();
     delay200ns();
     CCD_CLK1; // CLK = 1
     delay200ns();
     delay200ns();
     CCD_CLK0; // CLK = 0
}


采集好之后就可以进行区分黑白底了,区分黑白底方法主要分为两种:二值化法,边沿法。我相信大部分都用的二值化法,因为边沿法对采集回来的图像和ccd本身性能要求比较高,我也写过,不太好写。我们用的就是二值化方法,二值化主要就是确定一个阈值,确定阈值的方法也有很多种 ,我首先举一些我听过的算法,一种是车子在开机的时候采集赛道信息,分出黑点的灰度blackdc,以及白点的灰度whitedc,如果跑的过程中出现灰度在blackdc+20以下的默认为低,出现灰度在whitedc-20以上的默认为高,这是一种方法。
第二种方法,比较常用求平均值,怎么说呢,在不丢线的情况下,这个方法是可行的,丢线时要作特殊处理。第三种方法,就是静态阈值,就是自己在跑之前,通过上位机看一下图像,人为的输入一个阈值,这种方法有个弊端吧,就是每次换个新环境的时候,你都要担心你的阈值准不准确。我们用的是静态的阈值。
有了阈值就可以找出左右线了。
//==============随后即是提取黑线,代码如下:=====================
/*车位置越大说明靠左,ccd看到右边的还是右边的,左边还是左边的
直道时如果车位置较小,说明在车子靠右
弯道时,比如左转弯,他只看到右边的线,车位置也很小。
*/
void Get_Flag(void)   //我感觉这里应该舍弃两边的几个点  
{
    shiziwan=0;
    fandiuxianflag=0;//防丢线标志位
    int16 left_num,right_num;
    left_flag=0;
    right_flag=0;
    erzhihua();//二值化,里面包含了求动态阀值
    Filter_Pixel_Two();//滤波
    Filter_Pixel_Three();//滤波
    if(left_point>100)
    {
        right_flag=0;
        for(left_num=midlinexian;left_num>90;left_num--) //取得最左边的点,舍弃第一个坏点, 从上次车的中点开始向左边寻找舍弃了10个点
         {
         if(pixel[left_num]-pixel[left_num-1]==200)
           {
             left_point=left_num;
             left_flag=1;                           
             break;                 
           }
        }
        fandiuxianflag=1;
    }
    if(right_point<28)
    {
        left_flag=0;
           for(right_num=midlinexian+1;right_num<38;right_num++) //取得最右边的点舍弃了10个点 右边死区110
           {
          if(pixel[right_num]-pixel[right_num+1]==200)
            {               
              right_point=right_num;
                    right_flag=1;
                    break;                              
            }
          }
          fandiuxianflag=2;
    }
    if((fandiuxianflag!=1)&&(fandiuxianflag!=2))
    {
    for(left_num=midlinexian;left_num>11;left_num--) //取得最左边的点,舍弃第一个坏点, 从上次车的中点开始向左边寻找舍弃了10个点
      {
         if(pixel[left_num]-pixel[left_num-1]==200)
          {
             left_point=left_num;
             left_flag=1;
             break;                 
          }
      }
   for(right_num=midlinexian+1;right_num<114;right_num++) //取得最右边的点舍弃了10个点 右边死区110
        {
          if(pixel[right_num]-pixel[right_num+1]==200)
            {

                    right_point=right_num;
                    right_flag=1;
                    break;                              
            }
       }
    }
}


有的时候在转弯的时候会出现串道的情况,就是跑到旁边的赛道了,这个时候要做特殊处理,上面有写。就是让他只检测一定范围的区域就行了。
寻迹到这就讲完了,重点就是上面这个程序。


接下来就是方向控制
对于方向控制基本上就两种方法:一个就是连续控制,一个就是分段控制。
这两种方法,我比较偏向于第一个,第一种跑起来更平滑。在直道的时候给个固定p值,弯道的时候给个二次函数的p值,算法如下:
  if(a<14)
   {
        K_Direction_P=19;      //14
        K_Direction_D=100;   
   }  
  else if(a<26)
  {
    K_Direction_P=0.018*a*a+1.226*a;       //a>16,P=0.048*a*a+0.037
    K_Direction_D=100;
  }
  else
  {
    K_Direction_P=42;       //a>16,P=0.048*a*a+0.037*a;
    K_Direction_D=100;
  }


这里的a是当前位置到中线的差值。
d值一般给大点就行了,有消抖的左右。
然后就是控制舵机打脚了,这个比较简单,
       mid_err2=mid_err1;         //上次偏差
       mid_err1=midline-64;   //车位置与中点的差
       mid_err_err=mid_err1-mid_err2;
       DirectionOutnew=(uint32)(angle_value+(K_Direction_P*mid_err1         +K_Direction_D*mid_err_err));//angle_value是指0度的时候对应的占空比angle_value=750

       DirectionOutold=DirectionOutnew;
       if(DirectionOutnew>rightlimit)   //rightlimit=639向右打弯
       {
         LPLD_FTM_PWM_ChangeDuty(FTM0,FTM_Ch0,rightlimit);
       }
      else if(DirectionOutnew       {
         LPLD_FTM_PWM_ChangeDuty(FTM0,FTM_Ch0,leftlimit);
       }

       else
       {
        LPLD_FTM_PWM_ChangeDuty(FTM0,FTM_Ch0,DirectionOutnew);
       }


就是中间值+pid值就行了,关于pid算法,什么增量式,什么是位置式,这没必要纠结,能用就行。用c编写程序的时候要经常用到变量的强制转换。还有就是定义变量的时候一定要注意变量大小。有时出错了,找一晚上都找不出来,最后才发现是变量定义的有问题。


最后就是最重要的速度控制了。速度控制是提速的保证,你的车想跑多快,不仅仅是方向控制写的好,到了后期大家拼的就是速度控制了。关于速度控制主要有三种方法:pid,bang-bang,pid+bang-bang;
那哪种方法好呢,只能说,哪种你的车跑的快,哪种就好。bang-bang算法具有很强的加速能力和减速能力,有个弊端就是容易飘逸。如果控制的好,我感觉是非常nb的。pid算法速度具有很强的连续性,加减速看的不明显,直道与弯道速度不能差太大,跑起来四平八稳,过弯道能力强。我们用的就是pid算法。pid+bangbang算法被认为是最理想的,本人也写过,一直到校赛我一直都用pid+bangbang ,效果其实也还行。但是最后不知道怎么还是钟情于pid了,呵呵。
接下来就是速度控制,

//===============速度控制函数==================
void speed_control(void)
{

  float a,b;
   a=abs(mid_err1);
  if(stopflag==1)    //stopflag是起跑线标志
   {
     speed_mid=0;
   }
   else
   {
   if(a<6)
    {
      speed_mid=zhixianspeed_mid;
    }
   else if(a<20)
   {
     speed_mid=ruwanspeed_mid1;
   }
   else
   {
     speed_mid=ruwanspeed_mid1-10;
   }

   }
   /* if(stop==1)
    {
    speed_mid=0;
    fanzhuanduty=1000;
    if(ch0_pulseacc<3)
    {
    fanzhuanduty=0;
    }
    }*/
   speed_pluse=ch0_pulseacc;//speed_pluse=pluse/(float)speedcount;
   if(speed_pluse<5)   //当编码器的值很小的时候,让车停下来
   {
     stop=1;
   }
   speed_err1=speed_mid-speed_pluse;
   speedoutold=speedoutnew;
   p_value=K_p*(speed_err1-speed_err2);
   i_value=K_i*speed_err1;
   d_value=K_d*(speed_err1-2*speed_err2+speed_err3);
   speedoutnew=speedoutold+(p_value+i_value+d_value);//著名的pid算法,绝对正确
   speed_err3=speed_err2;
   speed_err2=speed_err1;
   if(stop==1)
   {
   speedoutnew=0;
   }
  if(speedoutnew<-6000)
   {
   speedoutnew=-6000;
   }
  if(speedoutnew>6000)
   {
   speedoutnew=6000;
   }
   if((speed_pluse>speed_mid)&&(a<10)&&(stopflag==0)) //刚入弯的时
     {                           //候,如果当前速度大于目标速度,清
      LPLD_FTM_PWM_ChangeDuty(FTM1,FTM_Ch0,0);  //零
      speed_zhen;
      speedoutnew=0;
      speed_err1=0;
      speed_err2=0;
     }
     else
     {
     if(speedoutnew>0)
     {
      LPLD_FTM_PWM_ChangeDuty(FTM1,FTM_Ch0,(uint32)speedoutnew);
      speed_zhen;
     }
     else
     {
     b=-speedoutnew;
     LPLD_FTM_PWM_ChangeDuty(FTM1,FTM_Ch0,(uint32)b);//正转方向占空比为0  反转
     speed_fang;
     }
    }

}


关于电机驱动我建议用mos管,btn能把你手烫熟了。


好了到了这里,基本就写完了,有人问那你人字弯和障碍以及十字怎么没写。我只能说自己探索的过程是别人无法知道的乐趣。再说明年就不一定是人字弯了,肯定又有新的挑战了。只有不断不断的学习,才能一直进步,不要满足现状。


评分

1

查看全部评分

回复

使用道具 举报

2

主题

321

帖子

0

精华

常驻嘉宾

Rank: 8Rank: 8

积分
3737
威望
1811
贡献
1188
兑换币
1144
注册时间
2014-2-17
在线时间
369 小时
毕业学校
非常小学
2#
发表于 2014-7-31 18:00:36 | 只看该作者
楼主好人
回复 支持 反对

使用道具 举报

6

主题

257

帖子

0

精华

高级会员

Rank: 4

积分
743
威望
353
贡献
234
兑换币
241
注册时间
2013-10-12
在线时间
78 小时
3#
发表于 2014-7-31 18:08:08 | 只看该作者
回复 支持 反对

使用道具 举报

10

主题

1956

帖子

0

精华

跨届大侠

Rank: 10Rank: 10Rank: 10

积分
10144

优秀会员奖章活跃会员奖章在线王奖章论坛元老奖章论坛元老奖章

威望
4669
贡献
2699
兑换币
2876
注册时间
2013-10-2
在线时间
1388 小时
4#
发表于 2014-7-31 18:28:43 | 只看该作者
浪险。
回复 支持 反对

使用道具 举报

14

主题

644

帖子

0

精华

常驻嘉宾

Rank: 8Rank: 8

积分
4415

在线王奖章优秀会员奖章活跃会员奖章论坛元老奖章

威望
2369
贡献
358
兑换币
1614
注册时间
2013-9-23
在线时间
844 小时
5#
发表于 2014-7-31 18:39:17 | 只看该作者
好人啊
回复 支持 反对

使用道具 举报

1

主题

138

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1933
威望
941
贡献
578
兑换币
457
注册时间
2013-12-4
在线时间
207 小时
6#
发表于 2014-7-31 19:04:09 | 只看该作者
楼主 你好,,我想知道你那滤波是怎么回事
回复 支持 反对

使用道具 举报

8

主题

600

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2518

优秀会员奖章活跃会员奖章

威望
1201
贡献
861
兑换币
813
注册时间
2014-7-21
在线时间
228 小时
7#
发表于 2014-7-31 19:14:28 | 只看该作者
:victory:
回复 支持 反对

使用道具 举报

1

主题

146

帖子

0

精华

常驻嘉宾

Rank: 8Rank: 8

积分
3830
威望
1792
贡献
1212
兑换币
1193
注册时间
2013-9-6
在线时间
413 小时
毕业学校
中南大学
8#
发表于 2014-7-31 22:18:06 | 只看该作者
楼主好人
回复 支持 反对

使用道具 举报

13

主题

488

帖子

0

精华

常驻嘉宾

爱是不是不开口才珍贵

Rank: 8Rank: 8

积分
4455

在线王奖章活跃会员奖章优秀会员奖章论坛元老奖章

QQ
威望
2240
贡献
1141
兑换币
1437
注册时间
2013-2-28
在线时间
537 小时
9#
发表于 2014-7-31 23:23:25 | 只看该作者
厉害1
回复 支持 反对

使用道具 举报

0

主题

192

帖子

0

精华

跨届大侠

Rank: 10Rank: 10Rank: 10

积分
6838

在线王奖章优秀会员奖章活跃会员奖章论坛元老奖章

威望
3762
贡献
614
兑换币
2483
注册时间
2013-10-20
在线时间
1231 小时
毕业学校
JUST_SLG
10#
发表于 2014-8-1 01:09:49 | 只看该作者
不知道楼主是怎么解决光线太强的问题的,是大津法么?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

关于我们|联系我们|小黑屋|智能车制作 ( 黑ICP备2022002344号

GMT+8, 2024-12-24 11:31 , Processed in 0.050472 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表