这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 767472021两轮自平衡小车DIY进程贴

共22条 2/3 1 2 3 跳转至
助工
2015-08-20 19:51:13     打赏
11楼

实验七 基于mpu6050的体感小车

       今天是820日,然而这和我并没有什么关系,七夕怎么了,给它脸它就是七夕,不给它脸充其量就是个星期四罢了(ps额,暴露我单身汪的身份了),楼主在这里祝大家情人节快乐,我还是继续呆在家调试代码吧,免得在外面要承受成吨的真实伤害………

好了,现在切入正题,我来带领大家一步一步做出属于自己的体感平衡小车

        首先,我们先准备一些需要额外用到的材料:

  1. stm32的最小系统版(ps开发板也行)

  2. mpu6050陀螺仪模块

  3. Nrf24l01+模块×2

  4. 双母头杜邦线若干

有了这些材料,考虑到每个人的基础还不一样,所以我们还需要先储备一点点的关于mpu6050的基础知识。首先我们来看看原理图吧:

大家看这上面只有两个io口连接到了cpu上面,就是我圈出的两根线,这两根线是I2C总线的信号线,SDA是双向数据线,SCL是时钟线SCL。在I2C 总线上传送数据,首先送最高位,由主机发出启动信号,SDASCL 高电平期间由高电平跳变为低电平,然后由主机发送一个字节的数据。数据传送完毕,由主机发出停止信号,SDASCL 高电平期间由低电平跳变为高电平。

       如果大家不怎么明白的话,也没什么关系,原理图这玩意儿也确实刚开始不好懂,我还为大家准备了一个更直观的图片:

                  

        这下大家看清楚了吧,只需要把这四个引脚连上stm32的最小系统上并且给发射端(最小系统)和接收端(小车)分别装上nrf24l01+无线模块(某宝上5块钱能买到)就完成硬件部分的连接了,从原理图上很清楚的看到将SCL连接PA11SDA 连接PA8,然后连上VCCGND就好了,大家不是很明白的可以看视频里面的详细解说。


然后我们科普一下mpu6050陀螺仪的性能。为了方便大家观看,我借用一下版主的关于移植DMP的帖子的部分内容,希望版主不要介意,我会注明出处:




以下内容为版主原著:


我们期望得到的是姿态数据,也就是平衡小车的倾角。要得到平衡小车的倾角,就得利用我们的原始数据,进行姿态融合解算,这个比较复杂,知识点比较多,初学者不易掌握。其实, MPU6050 自带了数字运动处理器, DMPDigital Motion Processing), 并且InvenSense提供了一个 MPU6050 的嵌入式运动驱动库, 结合 MPU6050 DMP 可以将我们的原始数据,直接转换成四元数输出,而得到四元数之后,就可以很方便的计算出欧拉角,从而得到 yawroll pitch

使用内置的 DMP,简化了平衡小车的代码设计,且单片机不用进行姿态解算过程,在一定程度上降低了 MCU 的负担,从而有更多的时间去处理其他事件,提高系统实时性(其实卡尔曼滤波和互补滤波在STM32里面也没花多少时间)。更重要的是,让大家可以不需要接触复杂的滤波算法就可以直接得到平衡小车倾角。

使用 MPU6050 DMP 输出的四元数是 q30 格式的, 也就是浮点数放大了 2 30 次方倍。在换算成欧拉角之前,必须先将其转换为浮点数,也就是除以 2 30 次方,然后再进行计算,

计算公式为:

q0=quat[0] / q30; //q30 格式转换为浮点数

q1=quat[1] / q30;

q2=quat[2] / q30;

q3=quat[3] / q30;

//计算得到俯仰角/横滚角/航向角

pitch=asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; //俯仰角

roll=atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; //横滚角

yaw=atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3; //航向角


这里,我们是做平衡小车而不是四轴飞行器,所以,仅仅使用pitch就行了。其他两个角度直接在程序中屏蔽了,因为反三角函数运算在STM32F1中还是需要不少时间的。





        相信看了版主的详细讲解之后我们对陀螺仪有了一个初步的了解,通俗点说就是mpu6050自带DMP,可以直接输出四元数,四元数通过公式就可以转换为欧拉角了。至于什么事欧拉角(ps也就是版主写的yawroll pitch), 接下来我们进入一段通俗易懂的小视频了解一下欧拉角(要看完哦):

        



视频地址:http://www.tudou.com/v/hYREJkNVtsE/&bid=05&rpid=489096632&resourceId=489096632_05_05_99/v.swf

       相信大家看完这段视频就已经了解了欧拉角了吧。而我们的体感小车就需要用到这个里面的roll pitch角来控制前后和左右了。

好了,基础知识已经说完了,下面来仔细的看看代码部分,其实代码部分和上一个实验很像的,小车上的接收程序和实验6完全一样,大家如果没有看不知道怎么改程序的话可以去13楼看看,我就不在做过多解释了,我们着重点在接收部分吗,大家仔细看,其实很简单。

       我用的接收端程序是在正点原子stm32mini板例程24无线通信实验的基础上移植修改的,这里将此例程给大家,大家如果想自己去移植DMP的话也可以,给个版主的帖子传送门:http://forum.eepw.com.cn/thread/274797/1

       我就不谈怎么移植DMP了,直接讲解移植好的代码吧:

       首先,在mpu6050.c(注意是接收端代码)里面,我们将读取MPU6050内置DMP的姿态信息的函数”(293行开始)做一些改动让其可以得到PitchRool的返回值。

我们可以通过串口来连接电脑来看看:

这上面是以浮点型显示的PitchRool的值。

这是代码:


float qianhou(void) //前后

{    

         unsigned long sensor_timestamp; 

         unsigned char more; 

         long quat[4]; 

  

         dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors, &more);         

                  if (sensors & INV_WXYZ_QUAT ) 

                  {     

                        q0=quat[0] / q30; 

                        q1=quat[1] / q30; 

                        q2=quat[2] / q30; 

                        q3=quat[3] / q30; 

                        Pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; //四元数转欧拉角公式 

                        printf("%f,%f,\r\n",Pitch,Rool); 

                        return Pitch;//得到Pitch角 

                  } 

} 

float zuoyou(void) //左右

{    

         unsigned long sensor_timestamp; 
 
         unsigned char more; 

         long quat[4]; 

  

                  dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors, &more);         

                  if (sensors & INV_WXYZ_QUAT ) 

                  {     

                        q0=quat[0] / q30; 

                        q1=quat[1] / q30; 

                        q2=quat[2] / q30; 

                        q3=quat[3] / q30; 

                        Rool = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;//四元数转欧拉角公式 

                        return Rool;//得到Rool角 

                  } 
} 



       然后利用Pitch角和Rool角用一些if语句做出判断,和之前的按键差不多,我贴一下核心的代码:


while(1) 

         {              

             zuoyou(); 

             qianhou(); 

             a=zuoyou(); 

             b=qianhou();           

             if(NRF24L01_TxPacket(tmp_buf)==TX_OK) 

             {              

             if(a<-15) tmp_buf[1]=70; else if(b>15)  tmp_buf[1]=50;  

             else if(b<-15) tmp_buf[1]=40; else tmp_buf[1]=30; } } 



      但是和之前又有一些区别,这几个问题让我调了很长时间,这里告诉大家,大家就不用浪费时间了。

问题一、

      由于mpu6050陀螺仪模块很灵敏,所以if语句里面是if(b>15)if(b<-15),而不是if(b>0)if(b<-0).

问题二、

      每个if语句之间要有顺序,要用if else 语句,不能是并列关系;

问题三、

      如果同时加入左右控制的话,就会有很大的干扰识别不准,可能是我的程序没写好,大家可以改进了跟帖告诉我,但是我想到了一个解决的办法,因为我们的小车是两轮的,独家支持原地360度无死角的旋转,所以我们可以用右转来代替左右转,而向左倾斜的时候就不给信号,这样稍微向左倾的时候控制前后就特别的灵敏并且没有任何干扰。详细的操控方法请看下面这段演示视频:


 



视频地址:http://player.youku.com/player.php/sid/XMTMxMzgxNzU4NA==/v.swf

      后期还会重新拍摄新的视频,谢谢大家观看。

      最后,附上发送接收端的代码打包给大家,我也履行了和大家的七夕约定,更新了这贴作为大家的礼物,祝大家七夕情人节快乐!!!

体感小车.zip

未移植DMP的发射端源程序.zip




助工
2015-08-20 20:15:33     打赏
12楼

咱们和七夕有个约定,欢迎大家来交流指教,这里是交流楼

这个体感小车非常推荐大家试着做一下,很好玩而且可以学到很多东西,材料不多,成本低,并且做起来非常容易。

大家有什么问题还可以提出来的》

对了,我拍的视频里面有个地方说错了,mpu6050陀螺仪上的SCL和SDA不是发送和接收线,而是双向数据线和时钟线,请见谅。大家如果发现其他问题或者好的建议,希望一定给我指出!再次谢过。


助工
2015-09-07 20:29:47     打赏
13楼


                                    实验八 超声波壁障体感小车

这几天在回家了,没来更新帖子,不过我也经常关注群里有关大家的一些动态,but now,楼主又来了,嘿嘿。我们今天来将上一个实验中的基于mpu6050nrf24l01的体感小车进行一个升级,让它拥有超声波壁障功能。这也相当于一个简单的多传感器数据融合吧。

首先,简单介绍一下超声波模块测距的基本原理,说的通俗一点就是S=V×T,也就是距离等于速度乘以时间,而声波的速度是340m/s,只要得出声波从发射出去到接收回来的双面时间T,则S=340×(T/2),就可以算出距离了。

然后进入我们今天的重点,我们从另一个角度来看看壁障,其实把上一个实验中的体感小车做好了之后将sys.h里面的壁障标志位置1然后做一下简单的修改就可以了,但是我们需要关注的是为什么之前的代码不能够在移动中实现壁障,但是0710版本的代码确可以,我们来看看两者之间的区别到底在那。

这两段核心的代码都只有四行,但是区别却相当的大。

 代码一 :

       if(Distance<100)

Flag_Hou=1;

          else

Flag_Hou=0;          //===简单避障:遇到障碍物就退

      

代码二 :

  if(Distance<500) 

         {

           Movement+=700 ;

           if(1==Flag_Qian)  

           Movement=700;

         }

首先,我们看看第一段代码,意思是如果超声波距离小于100的话,后退标志位置1,否则,置0。意味着小车遇到障碍物时会后退,退到安全距离是就会前进了,那么似乎这样不影响移动中的壁障啊,究竟是什么原因导致无法实现这个功能呢?我想了很长时间才发现,当我们在安全距离时,假如我们控制后退,那么需要将后标志位置1,左右前标志位都会置0,这个可以在蓝牙控制代码usart3.c中看到,但是这时候因为是在安全距离内,壁障函数中又会将后标志位置0,造成互相矛盾的后果,而当在遇到障碍物时,我们想要控制左右,那么这时后退标志位置0,同样的道理,此时壁障函数会将后退标志位置1,依然会造成代码逻辑错误。

然后我们看看代码二,显然代码二要高明许多了,同样是四行代码,却行行都是精髓,没有较高的编程思想是写不出来的,足以见得版主的编程功底非常的好了。当距离小于500Movement+=700 ;同样是控制向后,却十分巧妙的避开了使用标志位的逻辑混乱,而高明的采用了编码器数值直接控制,并且后面两句写出了当遇到障碍物时,你还要继续控制前进,则强制后退,这样就能完全的实现移动中的壁障了,简直是非常聪明巧妙的一种方法。

最后按老规矩奉上演示视频:




视频地址:http://player.youku.com/player.php/sid/XMTMxNzI1OTI4NA==/v.swf

助工
2015-09-08 12:10:48     打赏
14楼
      这个视频里面的配乐是我最喜欢听的歌之一,大家猜猜歌名是什么?猜对有奖哦

助工
2015-09-24 14:16:12     打赏
15楼

                  实验九 小车花样秀—大胆秀出爱

     这次实验我们来做一下有意思的东西,我们不需要任何其他的工具,只需要用到我们的小车然后配合我们的程序走出我们想要走出的形状,当然已经有很多人走8字了,我们在这里就不再走一遍了,那么现在我们就一步一步用平衡小车走出 “我爱你”  ps     I U当然了,我做的还不是很好,大家如果做的比较好了,完全可以以一个工科生的方式给妹子表白嘛!

 

接下来我详细的说一下每一个步骤,相信大家看完都能明白其中原理并做出自己的图形。

我们的基本代码用的是卡尔曼滤波标准版本,我们都知道小车编码器的值和小车的速度成比例关系,假如在STM32 5MS中断函数中,将编码器的结果乘以0.005,一个和速度成比例关系的值乘以时间就是一个和距离有比例关系的值了,然后经过实地矫正,就可得到小车的距离。下面这段代码就是这段话的解释:

if(Encoder_Left>0)
        distance = distance + (float)Encoder_Left*0.005;
     else
        distance = distance - (float)Encoder_Left*0.005;

disSHow = distance*2.176542;

 

这里很明显我们可以看到左轮编码值被我们用来记录小车的行驶距离了,2.176542在这里就是实地矫正系数,而disSHow就是矫正后的真正小车位移了。我在多说一句,至于为什么Encoder_Left>0时是加否则是减呢,那是因为我们写代码是,需要小车不管前进还是后退,都需要位移值增大,这样我们才能方便的让小车走出我们想要的图形了。

转弯角度是同样的道理:

if((Encoder_Left-Encoder_Right)>0) 
        turning = turning + (float)(Encoder_Left-Encoder_Right)*0.005; 
     else 
        turning = turning + (float)(Encoder_Right-Encoder_Left)*0.005;
     turSHow = turning;

 

只不过转弯角度用上午是左右轮编码器差值罢了。

其实在I U这三个图形当中,最难的就是心形了,我做的不好,你们做好了,就可以找妹子表白了,哈哈,当然这是句玩笑话,回归正传,那么我是怎么设计这个心形的呢?


相信大家看完这图也一目了然了吧,虽然我画的有点丑!

那么说道现在,其实我们的核心思想已经出来了,就是当小车达到某个位移或者某个转弯角度时,我们让小车执行相应的动作就好了。

好吧,原理思想和部分代码我讲完了,具体的代码我就不一一分析了,如果有不懂得等下在下面我会将完整程序和视频打包给大家,给大家留点空间,还是希望大家能够通过自己的理解来完成了。

主要的改进在show.c minibalance.c里面,当然一些没有定义的全局变量也要定义一下,比如要在main.c中加入int turning; int distance;main.h中加入extern int turning; extern int distance; MiniBalance.h中放入extern int ThreeSecFlag;

声明:这次实验是我在xxjian大哥的帖子的基础上想到的,经他本人同意后所以写了出来, xxjian大哥也给了我一些指导,再次表示感谢,这里附上xxjian大哥的帖子的传送门:http://forum.eepw.com.cn/thread/273082/4#31  大家可以看看。

  最后,老规矩,我将本人拍的视频拿出来献丑了,大家看看就行,欢迎吐槽,如果做成这样的话去表白成功几率不大,革命尚未成功,同志还需努力啊。有什么可以交流的或者不太明白的地方欢迎大家跟帖交流或者私聊,也希望大家早日完成自己的diy秀。小车循线下期见!

     小车大胆秀出爱.zip
         



助工
2015-09-24 14:17:22     打赏
16楼


视频地址:http://player.youku.com/player.php/sid/XMTM0MzM0OTM4OA==/v.swf

视频奉上,欢迎吐槽!

这里看效果不好,还有优酷地址,点击即可观看:

http://v.youku.com/v_show/id_XMTM0MzM0OTM4OA==.html


助工
2015-09-25 08:58:39     打赏
17楼

因为版主可能最近比较忙,可能不能及时审批文件,大家如果下载不了的话我就发一下百度云的链接吧!

百度云链接:http://pan.baidu.com/s/1mg1qhKk

助工
2015-10-12 09:29:12     打赏
18楼

  实验十 CCD前瞻—DemokTool上位机上手

 好久不见,今天我们来上手看看DemokTool这款由岱默科技出品的专用摄像头调试上位机软件。

 首先,软件一打开就是岱默大片的广告,看着不太好,但没办法,谁让这是人家开发的呢!

 要想测试这款软件,我们必须先给小车装上CCD,大家可能都见过飞思卡尔光电组的车模吧,上面的摄像头都架的很高,因为只有架的足够高,才能让摄像头有足够的前瞻和进光量,而我们的小车相对于来说又非常的矮,所以我们就必须给小车装上一个支架将摄像头支起来,就像这样:

 我是这样做的,首先在小车中下方打孔(ps用烙铁秒秒钟就好了),然后找个塑料棒或者木条,同样用烙铁烫个洞,然后用螺丝拧紧,在接口处涂上502,事实证明这样摄像头很稳固,不会随着小车运动而晃动。还有一个问题很坑爹的是官网给我们推荐的岱默科技提供的CCD摄像头的接线和我们的小车接口根本插不进去,还好我机智的换了杜邦线,但是由于亚克力板没有开口,所以我们还需要将亚克力板开个小口,这样基本上小车部分就连接好了。

 接下来稍微改动一下程序:

 首先将顶配版main.c中的第45行“ccd_Init();”和第51行“CCD();”取消注释(程序部分修改完毕,是不是so easy)。

 然后转到adc.c中可以看到这样的引脚定义:

   #define TSL_SI   PAout(12)   //SI

   #define TSL_CLK   PBout(4)   //CLK

  岱默的CCD摄像头共有6个引脚: 分别是SISOAOAOOVCCGND

  所以很明显, VCCGND就不多说了;

   CCD摄像头的SI连小车上的A12口;

           CCD摄像头的CLK连小车上的B4口;

           CCD摄像头的AO连小车上的A7口;(AOA00是一样的,只是放大倍数不同,所以AOO不连)

 现在只需要把改好的程序烧录到小车,打开小车让其平衡,然后通过串口线连上电脑,打开DemokTool软件,将波特率调到最大(115200),选择对应的com口,然后打开串口,点击“黑白数据”,然后选中又上方的“根据界面尺寸放大像素”,然后连续采集,根据上位机图像效果,用梅花起子拧CCD摄像头背部的螺丝(调节放大倍数适应当前光线环境),直至识别到清晰的黑线即可。

 下面放上我已经调节好了的视频:(注意看好电脑屏幕哦)



视频地址:http://player.youku.com/player.php/sid/XMTM1NjgzNjI4OA==/v.swf
                      下一个实验:正式CCD循迹(正在优化,近期更新)!


助工
2015-10-26 09:12:06     打赏
19楼

   实验十一 CCD循迹小车

    今天终于忙完了这段时间手头上的琐事,可以继续折腾我的小车了,上次实验我们已经将摄像头架好了,基本的上位机操作大家也学会了,那么今天我们就来讲讲软件部分是如何让小车做到循迹的。

本次实验实在“大渣渣”(ps车友的ID,并非冒犯)同学的基础上完成,在这里感谢“大渣渣”同学,他已经讲解的很好了,能写出这样的代码还是很牛b的,所以我就从另一个角度来给大家分析,毕竟每个人都有自己的想法嘛!当然最后我仍然会将代码打包供大家下载来学习分析!

首先先聊聊线性ccd的原理对吧,TSL1401 线性 CCD 传感器包含 128 线性排列的光电二极管。每个光电二极管都有各自的积分电路,以下我们将此电路统称为像素。每个像素所采集的图像灰度值与它所感知的光强和积分时间成正比。所以我们的ccd摄像头能否提取清晰好看的黑线跟光强和积分时间有着很大的关系,那么这 128 个像素是怎么进行采集并输出的呢,这就用到了 SI CLK 信号。可以简单的了解它们的功能。在 128 个像素之外,还有一个开关逻辑控制和移位寄存器电路。SI 通过该电路,控制每一个像素的积分和复位操作;CLK 通过该电路控制每一个像素电压的值依次输出,每个像素的值可以在 CLK 的下降沿时从 AO 采集。

下面来看看采集的代码:

void RD_TSL(void) //CCD采样函数
{
 u8 i=0,tslp=0;
  TSL_CLK=1;
  TSL_SI=0; 
  Dly_us();
      
  TSL_SI=1; 
  TSL_CLK=0;
  Dly_us();
      
  TSL_CLK=1;
  TSL_SI=0;
  Dly_us(); 
  for(i=0;i<128;i++) 
  { 
    TSL_CLK=0; //将CLK置低电平
    Dly_us();
    ADV[tslp]=(Get_Adc(7)>>4);//将获取到的电压值存储在一个128元素的数组中
    ++tslp;
    TSL_CLK=1; //再将CLK拉高,形成上升沿
     Dly_us();
  }  
}
}

 


很明显,这段代码是CCD采样函数的一的流程,简要说明下,CLK是一个上升沿触发的信号,采样一次数据的时候,首先把CLK拉高,这时候AO上已经出现了第1(这里数数的方式是正常人数法不是程序员数法)像素的模拟电压,然后把SI拉低否则积分复位电路工作可能不正常,连续输入128CLK(指的是上升沿)以后,128个模拟电压已经传输完毕,

此时注意:必须再次输入至少一个CLK脉冲(129个脉冲),否则采样电容的开关无法回到正常采样位置,下次的数据将出现问题。

如果还不是很清楚的请看看下面的时序图:


至于曝光时间我们这里就不做深入研究了,应为我们只是做一个简单的循迹,我想大家也已经明白的线性ccd摄像头的工作原理和采样原理了吧!那么接下来我们就来探讨一下如何得到循迹算法呢!

接下来我们就进入这段代码:

void CCD(void)   
{  
	int i,j,Find_Left = 0;
	static u8 Mid_Cnt = 0,Find_Cnt = 0;
	extern u8 Flag_Mid; 
	extern int MID;
	usart1_send(0xff);
	
	for(i=0; i<10;i++) 
	{ 
		RD_TSL();        
		Flag_Mid = 0;
		Mid_Cnt=0;
		Find_Left = 0;
		j=0;
		for(j=0;j<128;j++)//利用串口发送数据到上位机
		{
			if(ADV[j] ==0XFF)  ADV[j]--;    
			usart1_send(ADV[j]);
		}   
		for(j=1;j<127;j++)
		{
			if((ADV[j] < Value) && Flag_Mid)
			{
				if((ADV[j+1] < Value) && (ADV[j] < Value) && (ADV[j-1] >= Value)) //找出黑线左边缘
				{
					Find_Left = j;
					Find_Cnt = 1;
				}
				if(Find_Cnt)
				{
					Find_Cnt++;
					if(Find_Cnt >=4)	 break;
				}
				
			}
			else if(Mid_Cnt <= 10 && ADV[j] > Value)//识别白色区域
			{
				Mid_Cnt++;
				Flag_Mid = 1;
			}
			else if(Mid_Cnt <= 10)	
			{
				Mid_Cnt = 0;
				Flag_Mid = 0;
			}
				
		}
		
		if(Find_Left != 0)
		{
			MID =  Find_Left+2;//找到黑线的中点
			BufMid[i] = MID;
		}
		else
		{
			
			BufMid[i] = BufMid[i-1];
			MID = BufMid[i];
		}
		if(MID >=127)	MID =127;  //限制中线范围
		else if(MID <=0)	MID = 0;
		
		if(MID > (Expect +15))//右转判断条件
		{
			Flag_Qian=0;Flag_Hou=0;Flag_Left=0;Flag_Right=1;
		}
		else if(MID < (Expect -15))//左转判断条件
		{
			Flag_Qian=0;Flag_Hou=0;Flag_Left=1;Flag_Right=0;
		}
		else
		{
			Flag_Qian=0;Flag_Hou=0;Flag_Left=0;Flag_Right=0;
		}
	}
	
}

 

 


第一次看完这段代码时我的脑袋懵了,完全不知从何下手,看了好长时间总算明白怎么回事,为了大家更好的理解,容我先介绍几个变量:

Value 我们所期望的阀值,就是比阀值大的肯定识别为白色,因此我们设置的值是100,这里的值是电压值(ps为了方便调试,所以经过了放大),定义在了sys.h里面;

Expect 我们所期望的线性ccd摄像头中心线所在的值,也就是128个像素列的中线,就是128/2左右,因此我们设置的值是60;这里的值是计数值,并非电压值,用来记录线性摄像头的像素列中心值,定义在了sys.h里面;

MID 表示实际上的黑线中心的值在线性ccd摄像头眼中的位置值(范围在0-128之间的任意值),这里的值是计数值,并非电压值;

Find_Left 我们的黑线左边缘在线性ccd摄像头眼中的计数值;

接下来我们用分几个点来解释这段代码吧:

(这里面其实最最关键的是怎样找出黑线的左边缘位置)

1.第一个子for 循环

for(j=0;j<128;j++)

{

if(ADV[j] ==0XFF)  ADV[j]--;

usart1_send(ADV[j]);

}

这段代码是通过串口将每个像素点传到上位机上面去显示

2.第二个子for循环的第一个if语句

if((ADV[j] < Value) && Flag_Mid)

第一个判断条件ADV[j] < Value是判断是否是黑色区域,Flag_Mid是一个标志位,而Flag_Mid初始化为0,所以不会进入循环,而会进入else判断,

else if(Mid_Cnt <= 10 && ADV[j] > Value)

else判断是识别白色区域

3.上一个if的嵌套if循环

if((ADV[j+1] < Value) && (ADV[j] < Value) && (ADV[j-1] >= Value))

{

Find_Left = j;

Find_Cnt = 1;

}

这个if语句意思为第j个和第j+1个像素点的电压值小于阀值Value,识别为黑色,第j-1个像素点大于阀值Value,识别为白色,因此第j个就是黑线的左临界点,Find_Left = j;,用Find_Left记录下来。

4. MID =  Find_Left+2;

因为一般一条黑线大概占用128个像素列中的56个像素点,因此Find_Left+2就可以近似看成实际的中线(MID)所在的位置;

5.    if(MID > (Expect +15))

{

Flag_Qian=0;Flag_Hou=0;Flag_Left=0;Flag_Right=1;

}

else if(MID < (Expect -15))

{

Flag_Qian=0;Flag_Hou=0;Flag_Left=1;Flag_Right=0;

}

else

{

Flag_Qian=0;Flag_Hou=0;Flag_Left=0;Flag_Right=0;

}

这段是用来判断左转右转的,假设我们现在需要右转,说明右边有黑线,那么实际黑线的中心必然远大于我们所期待的像素点中心,为了方便我们选择用MID < (Expect+15)作为判断条件;同理,假设我们现在需要左转,说明左边有黑线,那么实际黑线的中心必然远小于我们所期待的像素点中心,为了方便我们选择用MID < (Expect-15)作为判断条件。

看完这个,大家可能纳闷,那么控制向前的在哪里呢,大家看完这个就明白了:

原代码为:

Encoder_Least =(Encoder_Left+Encoder_Right)+0;

//===获取最新速度偏差==测量速度(左右编码器之和)-目标速度(此处为零)

我们将目标速度改为60,就像这样:

Encoder_Least =(Encoder_Left+Encoder_Right)+60;

这句代码在control.c中,这样小车就有了一个初始的向前的速度了。

讲完了这些,相信大家对线性ccd循迹有了一个比较清楚的认识了吧,那么大家就开始动手做吧,不需要太长时间,加油哦;

最后老规矩奉上代码打包和视频演示:

视频演示:


视频地址:http://player.youku.com/player.php/sid/XMTM1NjgyNTk4MA==/v.swf


代码打包下载:循迹平衡小车.zip


助工
2015-11-01 09:54:21     打赏
20楼

  写在结尾的一些话

帖子写到这里是时候要和大家说再见了,记得今天6月份那会儿,刚刚过一遍正点原子的stm32,过完还晕头转向的,感觉自己并没有学会多少东西,不知道怎么继续下去的时候,实验室的老师给我推荐了EEPW论坛的这个活动,让我可以系统的巩固一遍之前学习的知识,并开始接触更深层次的知识,小车上的每个模块,每个扩展功能都是一个个知识点的融合,在这里再次感谢EEPW举办这次对我意义非凡的活动。

在这次实验中,我也将版主要实现的功能一一实现了,从编码器数据采集实验、无线通讯实验、传感器驱动实验到多传感器数据融合、PID调试、实现平衡小车直立时处于静止状态 、实现平衡小车绕“I LOVE U”行走、实现小车自主避障、实现小车利用线性CCD巡线、实现体感控制等等,app做了一些小小的改动,应为确实对安卓app制作方面没有学习,在这里要和大家说声抱歉的是我没有按照官方的规则一一的制作标题,而是自己随心所欲的将一些相关功能的实验写在了一起,比如体感和自主避障、不走8字而走其他图形、PID调试和小车静止在桌面等等放在了一起,以及标题都是自己觉得好听就取得,相信大家应该也能看得出来,给大家的阅读带来了不便表示非常抱歉。

正因为老大(ps老王)举办了这么优秀的活动,版主杨哥(帕索尼passoni)的大量技术支持,是使我有信心完成这次活动重大原因,也为此,看到好多的童鞋到了八月份开始由于各种原因放弃了我表示深感惋惜,所以自那时起,我尽量将帖子写的详细清楚,每个知识点都看了几遍帖子改了又改才敢上传出来,每次到结尾都是老规矩放上所有代码和视频,从未有过隐藏回复之类的,之所以这样是希望大家能从中有所收获降低一些难度并坚持下去,不然谁没事花这么时间在这个上面呢,虽然活动临近结束,但还是希望大家不要轻言放弃,做一件事就坚持做完。

作为一名大学生,在这次活动中,我不仅学到了专业知识,还提升了文档的编辑能力,认识了许多的和我们一起坚持下去的人,很高兴认识你们,真的很荣幸有那么多人信任我和我讨论你们遇到的我问题,虽然我水平不是很高,但我也尽我所能的解答,每当你们说在我的帖子里能学到一些东西时我就无比的高兴,所以我希望能有更多的人与我们同在!

最后,仍就避免不了离开大家了,我也要开始准备我的基于stm32的课程设计了,还是老规矩奉上视频吧,没有新的视频,为了方便大家观看,就将以前的视频整理了一下放入一个专辑中,每个视频都做了稍微的处理,大家感兴趣的可以看看哦!

专辑地址:

戳这里http://www.youku.com/playlist_show/id_26187063.html


共22条 2/3 1 2 3 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]