智能车制作

 找回密码
 注册

扫一扫,访问微社区

查看: 33270|回复: 130
打印 上一主题 下一主题

我的平衡车设计--软件篇

    [复制链接]

8

主题

119

帖子

0

精华

跨届大侠

Rank: 10Rank: 10Rank: 10

积分
6089
威望
2660
贡献
1737
兑换币
1625
注册时间
2011-7-22
在线时间
846 小时
跳转到指定楼层
1#
发表于 2013-7-30 00:58:40 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
本帖最后由 Malc 于 2013-7-30 01:00 编辑

大赛结束了,由于时间紧迫,做车的时间很短,所以留下了一些遗憾,趁这段时间有空,整理一下几个月来的资料,既是对自己几个月来的总结,也算上和大家的一些交流吧,这篇文章就谈谈我的平衡车所用到的一些方案和算法吧

首先我用的方案是卓晴老师(在常大看到卓老师啦~)的方案,这次方案是做了一些修改和拓展,比如滤波我采用的互补滤波,速度控制用的是P控制而非PI,方向控制使用了转向陀螺仪。控制周期5ms,除了蓝牙发送程序外,其他代码均放在中断中,这样的好处是控制周期准确,5ms周期中,CCD采样572us,ACC、Gyro采样+计算 784us,直立、方向、速度控制 208us,CCD计算500us左右,总共时间略大于2ms。曝光时间固定5ms,这个时间在白天以及比赛现场是很合适的,但是到了晚上就不行了,到了晚上一般我会将曝光时间x2,并用运放对CCD信号进行2~5倍的放大。下面详细说一下一些我认为比较重要的部分吧。

FIR滤波器
首先介绍的FIR滤波器,在我的代码中,我大量使用了FIR低通滤波器,主要是这么5个地方:加速度计角度、速度、直立控制中的Error、赛道中心线、速度控制中的Error。  关于FIR的介绍和设计估计可以重开一贴了,所以这里主要说一下FIR的效果,在直立控制中,我对Error=Setpoint-angle进行了一次低通滤波,带来的效果就是直立控制的P、D参数可以使用更高的值,也就是说小车立的更 硬 了,平常跑的时候基本1.6~1.8m/s过单障碍,FIR之前,kp=1250,kd=18,FIR之后kp=1800,kd=30。速度值通过低通滤波之后杂波明显少了很多,曲线也更光滑了。计算出来的赛道中心线之所以使用低通滤波进行滤波主要是为了防止赛道中心突变,因为整个赛道是连续的,即使是在十字弯。下面附上一张加速度计经过FIR低通滤波之后的效果图:
滤波之前,黄色的是加速度计角度,红色是融合之后的角度:

滤波之后:
当然FIR滤波器也有他的缺点,比如频率选择特性没有IIR好,会有固定的相位延迟,延迟为拍数/2*采样间隔

互补滤波
平衡车角度的获取我并没有采用清华方案,而是采用了动态权值互补滤波,好处是可以得到小车的真实角度,计算量有所增加,但几百us还是可以接受的。互补滤波关键代码:
tempX=angleAX*5/4096*1000/AccSense;//5v,12bit ADC,AccSense查datasheet可得
tempZ=angleAZ*5/4096*1000/AccSense;
tempZ=angleAZ*5/4096*1000/AccSense;
angleA=-atan2(angleAX,angleAZ)*180/PI;//加速度计计算出的角度
angleA=FIR(angleA);
gravity=sqrt(tempX*tempX+tempY*tempY+tempZ*tempZ);
gravityError=fabs(gravity-gravityG);
if(gravityError>gravityVibrationGate)// avoid vibration
   weight=1;
else{
      weight=weight2+(weight1-weight2)*gravityError/gravityVibrationGate;//动态权重
    }
time=micros()-gyroTimer;//micros()用于读取当前的时间,单位us
gyroTimeTest=time;
angleDelta=(testGyroZ1-TLYLDZ1)*5/4096*1.5/5.1/GyroSense2*time/1000;//自制的陀螺仪,放大倍数=5.1/1.5
angleFinal=angleA*(1-weight)+(angleDelta+angleFinal)*weight;//这就是互补滤波了
在这里weight的变化范围是0.98~0.995

黑线提取
黑线提取我采用的是跳变沿检测+动态阀值,好处是可以减少共模干扰,建议采集的128个点经过一次中值滤波,3点足够,5点的时候边沿已经变得略平滑了,代码如下:
for(i=0,CCDAvr0=0;i<128;i++)
           CCDAvr0=CCDa+CCDBuf2;
CCDAvr0=CCDAvr0/128;
FZ=CCDa*FZBL;//阀值=赛道亮度平均值*阀值比例(0.4~0.8)
for(i=LineCenter;i+DCCD<128;i++)  //Rblack
{
        if(CCDBuf2-CCDBuf2[i+DCCD]>FZ)
           Rblack=i+DCCD;
}
值得注意的是边沿检测不一定是两两相邻的点进行比较,因为这样可能会因为边沿特征的不明显而识别失败,建议取3~8个点。另外上面的搜索中,并不是从64点往两边搜索,而是从上次的centerline往两边搜索。
补线:
if(Lblack>50)
  LineCenter=Lblack+trackWidth/2;
else if(Rblack<78)
  LineCenter=Rblack-trackWidth/2;
else
  LineCenter=(Lblack+Rblack)/2;
至于trackWidth,我采用的是动态值,因为它会随车体的前倾角度二变化,我的小车只用了一个CCD,几次尝试使用一前一后的双CCD检测,最后蛋疼的放弃了,就是因为前瞻和前倾的蛋疼关系。。
起跑线的识别,使用的是“夏日的冰”的方法,检测跳变沿个数是否大于5,这个方法非常好用,在此表示感谢,原帖地址:http://www.znczz.com/thread-141798-1-1.html

时间的获取
在很多地方我使用了micros()、millis()这两个函数,这两个函数来自于Arduino,作用就是利用一个定时器,在单片机开机的时候进行计时,通过这两个函数可以获取当前的时间,unsigned long的格式,micros()70分钟后溢出,millis()50天后溢出,用在小车上足够。有了这两个函数可以很方便的计算出一段代码的运行时间、gyro的积分时间等,加上SerialChart、XS在线调试,示波器被彻底取代了:) 代码:
void PIT_Init(void) {
  PITCFLMT_PITE=0; //定时中断通道0 关
  PITCE_PCE0=1;//定时器通道0 使能
  PITMTLD0=80-1;//8 位定时器初值设定。80 分频,在80MHzBusClock 下,为1MHz。即1us.
  PITLD0=54321-1;//16 位定时器初值设定。50ms溢出
  PITINTE_PINTE0=1;//定时器中断通道0 中断使能
  PITCFLMT_PITE=1;//定时器通道0 使能
  
  PITLD1=5000-1;//16 位定时器初值设定。2ms溢出
  PITCE_PCE1=1;//定时器通道1 使能
  PITINTE_PINTE1=0; //定时器中断通道1 中断
}
unsigned long micros() {
return time_us+(54321-PITCNT0);
}
unsigned long millis() {
unsigned long mm=micros();
if(mm>500)
return (54321-PITCNT0)/1000+time_ms+1;
return (54321-PITCNT0)/1000+time_ms;
}
     
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt 66 PIT0(void)
{
    PITTF_PTF0 = 1; //clear interrupts flag
    time_ms_mod+=321;
    if(time_ms_mod>=1000){
     time_ms_mod-=1000;
     time_ms+=1;
    }
    time_ms+=54;
    time_us+=54321;
      
}
#pragma CODE_SEG DEFAULT  
这段代码中,利用PIT0作为定时时钟,溢出周期54321us,而控制周期是5ms,为什么会用这么奇葩的数字,因为我发现如果溢出周期若为50ms,就会导致每隔10次就使得控制中断被忽略一次,没办法,只好增大他们的最小公倍数了。

关于软件,我想写的就这么多吧,时间仓促肯定有遗漏,以后再补充吧,欢迎大家谈谈自己的看法,而不是只留一个“顶”or“路过”~

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

评分

1

查看全部评分

0

主题

18

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
241
QQ
威望
117
贡献
84
兑换币
76
注册时间
2015-7-27
在线时间
20 小时
毕业学校
中南民族大学
132#
发表于 2016-7-22 10:55:26 | 只看该作者
对我自己的ccd处理有帮助。
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

注册会员

Rank: 2

积分
45
威望
33
贡献
8
兑换币
9
注册时间
2016-7-20
在线时间
2 小时
毕业学校
北理
131#
发表于 2016-7-21 18:48:26 | 只看该作者
你好,请教一下互补滤波问题,你前面程序中写到
gravity=sqrt(tempX*tempX+tempY*tempY+tempZ*tempZ);
gravityError=fabs(gravity-gravityG);
if(gravityError>gravityVibrationGate)// avoid vibration
   weight=1;
else{
      weight=weight2+(weight1-weight2)*gravityError/gravityVibrationGate;//动态权重
    }
请问weight1,weight2和gravityVibrationGate该取哪些值?我怎么老是取不好呢?请指教?
回复 支持 反对

使用道具 举报

3

主题

6

帖子

0

精华

高级会员

Rank: 4

积分
751
威望
383
贡献
244
兑换币
246
注册时间
2014-2-13
在线时间
62 小时
130#
发表于 2015-5-10 20:35:08 | 只看该作者
动态阈值采用赛道平均值再乘以系数,这个倒是有点新颖,我的是二值化的,采用的是安微工大的思想,最大加最小的平均值再加一个常数,也基本可以实现,回去参考一下你的思想,我现在在跳变沿和二值化那里纠结得要死
回复 支持 反对

使用道具 举报

12

主题

176

帖子

0

精华

高级会员

Rank: 4

积分
952
威望
480
贡献
316
兑换币
304
注册时间
2014-11-6
在线时间
78 小时
129#
发表于 2015-3-9 07:51:08 | 只看该作者
厉害。。。牛
回复 支持 反对

使用道具 举报

0

主题

35

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1384
威望
647
贡献
423
兑换币
434
注册时间
2015-2-4
在线时间
157 小时
128#
发表于 2015-3-2 19:47:31 | 只看该作者
菜鸟表示没看懂- -要多学学
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

高级会员

Rank: 4

积分
812
威望
406
贡献
256
兑换币
267
注册时间
2013-12-14
在线时间
75 小时
127#
发表于 2015-2-9 00:31:53 | 只看该作者
楼主好厉害
回复 支持 反对

使用道具 举报

0

主题

34

帖子

0

精华

高级会员

Rank: 4

积分
834
威望
433
贡献
255
兑换币
283
注册时间
2014-7-26
在线时间
73 小时
毕业学校
西南科技大学
126#
发表于 2014-9-2 09:37:52 | 只看该作者
仔细学习一下:)
回复 支持 反对

使用道具 举报

5

主题

118

帖子

0

精华

常驻嘉宾

Rank: 8Rank: 8

积分
4825
威望
2207
贡献
1044
兑换币
1242
注册时间
2010-5-24
在线时间
787 小时
125#
发表于 2014-7-25 23:20:12 | 只看该作者
不错的挖坟贴.
回复 支持 反对

使用道具 举报

8

主题

119

帖子

0

精华

跨届大侠

Rank: 10Rank: 10Rank: 10

积分
6089
威望
2660
贡献
1737
兑换币
1625
注册时间
2011-7-22
在线时间
846 小时
124#
 楼主| 发表于 2014-7-10 16:28:21 | 只看该作者
厚重的心 发表于 2014-7-9 16:30
学姐,我还想问下,你上次给我的那个FIR的资料,FIR_Gain文件夹里的那个文件是.ino格式的,拿什么打开?还 ...

ino文件是arduino的文件格式,可以用文本打开
那个exe文件不是打不开,而是没有显示界面,输入在Input.txt中,输出在parameter.txt中
一定要看文件夹里的说明
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-1-13 05:44 , Processed in 0.210625 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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