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

共47条 2/5 1 2 3 4 5 跳转至
助工
2015-08-13 19:34:29     打赏
11楼

                       实验五   编码器控制

       抱歉,这一次的更新让大家等待了这么久,好在我又回来了,今天我们来看看小车的编码器,来仔细分析一下我们是怎么控制电机的运转的,还是那句话,有什么说的不对的或者有好的见解地方希望大家跟帖指正交流。

       首先,既然要来分析编码器,我们得先看看编码器长啥样在哪里不是、、、

       在了解了编码器长啥样了之后,我们接下来看看PWM电机调速的工作原理:

       对于电机的转速调整,我们是采用脉宽调制(PWM)办法,控制电机的时候,电源并非连续地向电机供电,而是在一个特定的频率下以方波脉冲的形式提供电能。不同占空比的方波信号能对电机起到调速作用,这是因为电机实际上是一个大电感,它有阻碍输入电流和电压突变的能力,因此脉冲输入信号被平均分配到作用时间上,这样,改变在输入方波的占空比就能改变加在电机两端的电压大小,从而改变了转速。简单点说就是输入方波占空比越大,小车速度越快,当我们将电源直接接在电机两端时,就相当于100%的占空比时,小车速度也就达到极致了。至于PWM信号打哪儿来的,我们稍后继续讨论!


       当然了,这只是个示意图,看完了编码器上的接线说明,我们继续分析电机的驱动,因为我们这里的直流电机是需要足够的电流才可以驱动,而主控芯片的IO口所提供的电流显然达不到这个要求,所以我们就需要一块电机驱动芯片来对电流进行放大。我们这次的小车用的驱动芯片是TB6612FNG,它的原理图如下:

                                         

   可能大家看到这个原理图会说,然而这并没有什么卵用,应为大家都知道它的实质其实基于MOSFETH桥集成电路,其效率高于晶体管H桥驱动器

             

   大家都知道,电流经过直流电机的方向不一样是,转动的方向是相反的,那么假设S1和S4闭合时直流电机是正向转动的,那么S3和S2闭合时直流电机显然就是反向转动的。

void Set_Pwm(int moto1,int moto2)
{
	   if(moto1<0) AIN2=1, AIN1=0; else AIN2=0, AIN1=1;
           PWMA=myabs(moto1); 
           if(moto2<0) BIN1=0, BIN2=1; else BIN1=1, BIN2=0;
           PWMB=myabs(moto2); 
}

这段代码就能很好的证明了。

那么接下来我们看看TB6612FNG这款驱动芯片的真值表吧:



   首先,STBY很明显是使能端信号,高电平有效的。

   其次,IN1IN2是控制电流流过的方向,可以控制电机的正反转。

   最后,PWM信号为低电平时,可以短暂制动,脉冲输入信号被平均分配到作用时间上,因此通过占空比的调节可以调整转速,前面也已经讲过了。

   好了,前面的基本知识我们也已经讲解的比较仔细了,现在我们来解析一下代码是怎么写出来的。在motor.c这段代码中(ps710号版本),我们可以很看到通过TIM3(定时器3)作为电机的PWM源信号产生,并且都工作早PWM1模式下,而在PWM1模式下,变化的计数器不断与CCRy进行比较。假设计数器采用加计数方式,当计数器的值TIMx_CNT小于TIMx_CCRy时,PWM信号保持高电平。当TIMx_CNT不断增加,直到大于TIMx_CCRy时,PWM变成低电平。TIMx_CNT继续增加,当达到TIMx_ARR预设的值后,复位返回0值。在第15行代码中:

           TIM3->ARR=arr;//设定计数器自动重装值

   可以看到,TIM3->ARR决定了PWM信号的周期

   在encoder.c中,TIM2TIM4被初始化为编码器接口模式

int Read_Encoder(u8 TIMX)
{
   int Encoder_TIM;    
   switch(TIMX)
	 {
	 case 2:  Encoder_TIM= (short)TIM2 -> CNT;  TIM2 -> CNT=0;break;
	 case 3:  Encoder_TIM= (short)TIM3 -> CNT;  TIM3 -> CNT=0;break;
	 case 4:  Encoder_TIM= (short)TIM4 -> CNT;  TIM4 -> CNT=0;break;
	 default:  Encoder_TIM=0;
	 }
		return Encoder_TIM;
}     


   在这段程序中,很容易看出来,TIM2 -> CNT决定了PWM信号的占空比,也就是决定了速度,因此,返回值Encoder_TIM如注释所说为速度值。

通过这里的Read_Encoder函数,我们就可以的到左右轮的编码值了,这个可以在最重要的控制文件control.c中的第13行和第17行中看到:

        Encoder_Right=Read_Encoder(4);  
        Encoder_Left =-Read_Encoder(2);


   得到的左右轮编码值会作为速度PI控制函数的入口参数。

   在上位机中,我们得到的左右轮编码值空转时都接近600左右,基本保持一致:



   这次的编码器实验我没能写的太清楚,可能自己理解的还不够透彻,有什么问题希望大家不吝赐教,谢谢。







助工
2015-08-13 19:56:14     打赏
12楼

大家都来这里交流交流啊!



助工
2015-08-19 09:17:01     打赏
13楼

                   实验六 2.4G无线通信控制小车

      本次实验我们来简要的讨论如何利用nrf24l01+来控制小车的运转,因为后面我们会重点关注体感小车的制作,所以本节主要以程序分析为主,稍后会奉上接受发送端源代码以及运行视频,谢谢大家关注和指正。

首先,我们要准备的工具有两块nrf24l01+芯片一块stm32的最小系统板,stm32的开发板也行,我用的就是正点原子的战舰stm32mini板。有了这个我们就可以看我们的实验了。因为stm32mini板和小车都带有nrf24l01+的接口,所以这里就不讲芯片原理图和接口配置了,大家的如果不一样的话改改IO口的配置就好了嘛。

我们先看看接收端(也就是小车) 的程序,小车的接收程序显然就在24l01.c里面:

 if(mode==0)//RX模式
{
    RX_Mode();   
    while(1)
     {               
     if(NRF24L01_RxPacket(tmp_buf)==0)//一旦接收到信息,则显示出来.
     {
          printf("%d\r\n",tmp_buf[1]); 
          if(tmp_buf[1]>120)Flag_Left=1,Flag_Right=0;
          else if(tmp_buf[1]<60)Flag_Left=0,Flag_Right=1; else Flag_Left=0,Flag_Right=0; }else delay_us(100); }; }



        这就是接收端的控制核心代码了,在nrf24l01.c里面的169到183行。

从程序中我们清楚的看到,控制小车左右的是接收到的tmp_buf[1]的值决定的,当tmp_buf[1]<60时,Flag_Right=1,那么右转。tmp_buf[1]>120时,Flag_Left=1,那么左转。

       我们做如下修改,修改后代码如下:


if(mode==0)//RX模式
{
RX_Mode();   
//while(1)
{               
if(NRF24L01_RxPacket(tmp_buf)==0)//一旦接收到信息,则显示出来.
{
    printf("%d\r\n",tmp_buf[1]);
    if(tmp_buf[1]==30)       
         {Flag_Left=0,Flag_Right=0,Flag_Qian=0,Flag_Hou=0;} 
    if(tmp_buf[1]==40)   
         {Flag_Left=0,Flag_Right=0,Flag_Qian=1,Flag_Hou=0;}
    if(tmp_buf[1]==50)
         {Flag_Left=0,Flag_Right=0,Flag_Qian=0,Flag_Hou=1;}
    if(tmp_buf[1]==60)
         {Flag_Left=1,Flag_Right=0,Flag_Qian=0,Flag_Hou=0;}
    if(tmp_buf[1]==70)
         {Flag_Left=0,Flag_Right=1,Flag_Qian=0,Flag_Hou=0;}
 }
    else 
    delay_us(100);    
};



       在这里,我们注释掉了while(1)语句,不注释的话显示屏就不会显示,然后我还将接受控制函数稍作修改,为后面的体感小车做铺垫。

最后我们移步到Minibalance.c(7.10更新的最新代码)中看看,

首先将第38行的 “NRF24L01_Init(); ”NRF24L01模块初始化函数取消注释;

然后将第40行的“NRF24L01_FindMyself(); ”NRF24L01自检程序取消注释;

首先将第45行的 “NRF24L01(); ”     NRF24L01模块收发函数取消注释;

好了,接收端函数就先讲这些了,接下来我们看看发送端程序:

        发送端程序我采用的是在正点原子的stm32系列教程中关于无线通信实验的例程的基础上进行修改的,现在简要说下主要思想:

while(1)
{         
if(NRF24L01_TxPacket(tmp_buf)==TX_OK)
{
     key=KEY_Scan(0);
     if(key==KEY0_PRES)
      {
      tmp_buf[1]=70; 
       }
     else if(key==KEY1_PRES)
       {
        tmp_buf[1]=60;
       }
     else tmp_buf[1]=30; 
}else
    LED0=!LED0;
    delay_ms(1000);     
};



       这里是两个很简单的if语句就可以实现我们的方向控制了。那么最后就放出整个发送端和接收端的程序打包给大家:

STM32无线遥控小车源代码.zip

然后还有一段演示视频。


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

大家有什么好的建议或者疑问可以留言哦,我一定尽我所能给大家答复。


菜鸟
2015-08-19 12:24:04     打赏
14楼

这贴一定要顶下!


助工
2015-08-20 19:51:13     打赏
15楼

实验七 基于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     打赏
16楼

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

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

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

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


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


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

这几天在回家了,没来更新帖子,不过我也经常关注群里有关大家的一些动态,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     打赏
18楼
      这个视频里面的配乐是我最喜欢听的歌之一,大家猜猜歌名是什么?猜对有奖哦

助工
2015-09-08 21:57:02     打赏
19楼
老街,快送我辆车╰( ̄▽ ̄)╭

工程师
2015-09-09 20:48:22     打赏
20楼
楼主  你那个视屏可不可以发个完整的连接呀

共47条 2/5 1 2 3 4 5 跳转至

回复

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