宜昌老张

【嵌入式】Andriod与Arduino共同作用下的MakeBlock智能小车

0
阅读(7994)

一、前言

    最近一直在琢磨带编码器的直流电机的应用机制,于是在淘宝中找到一款型号为JGA25-371的直流减速电机,它的编码器含有334线码盘,具有比较高的测转角精度,通过它做了Makeblock智能车作品。把两个这样的电机安装在小车的左右车轮上,通过PID比例调节让小车可以做到走直线。同时这个作品也用到了Andriod手机蓝牙无线遥控,采用了一款“蓝牙串口通信助手”的应用程序,控制着小车的前后左右行驶和速度切换。

    Andriod手机遥控MakeBlock金属小车的视频:


视频网址:http://player.youku.com/player.php/sid/XNTcwNDA1Mjk2/v.swf

 

二、MakeBlock智能车机械结构组成

    这个智能车的机械机构是由Makeblock公司出品的铝型材金属积木搭建而成,MakeBlock设计了一种独特的螺纹槽和孔的连接方式,使搭建作品时,更容易连接,就像使用乐高积木那样简单,只用螺钉和螺母,朝着您设想的思路方向,一路调试和搭建即可,不用什么专门的训练就可以上手。MakeBlock官网有许多PDF搭建指导手册可以参考,这个智能车的搭建手册,见网址:http://l25.yunpan.cn/lk/Q2bcNRbgu7PGa。它的机械结构的俯视图和底面图如下。

图1 MakeBlock智能车机械结构俯视图

图2 MakeBlock智能车机械结构底面图

    从图2可以看出,我采用梁类和板类零件组装了小车的机身,用支架、联轴器、同步带轮和轮胎构建了小车的车轮部件,小车的另一端是万向脚轮,它与两个车轮形成对地面的三点支撑。

    把铝合金智能车搭建完毕,拿在手中掂一掂,感觉有些份量,比起被“专家们”戏称为玩具的塑料积木,由Makeblock金属积木构建的作品就显得扎实可靠,刚性十足,更具工业感。

 

三、MakeBlock智能车电控系统组成

    智能车电控系统由几个部件组成,它们为:两个ASLONG公司的型号为JGA25-371的编码器减速电机、DFrobot公司的Arduino UNO控制器与BluetoothV3蓝牙模块,杰越科技的双路5A光电隔离MC33886电机驱动板,还有两块锂聚合物电池。

    如图3所示,JGA25-371的编码器减速电机工作电压为6-24VDC,额定电压为12V。它的外圆直径为24.4mm,输出轴直径为4mm,其端面安装孔位正好与MakeBlock的电机安装支架相吻合,电机轴上有坡口切面,方便通过锁紧螺钉与联轴器零件相固连。

图3 ASLONG JGA25-371的编码器减速电机

    这个型号的电机有多种输出转速可以选择,我选择是减速比为21.3,空载转速为201r/min的电机。为了保证了测速精度,与电机转子相连的编码器码盘为334线,也就是电机转子转一圈会输出334个脉冲。

    ASLONG JGA25-371的编码器减速电机有6根输出线,其中橙色和黄线两根线是电机引线,绿色和白色线是两组脉冲输出线,用一根线就能测量转速,双脉冲可以判断旋转方向,红色的线接3V至5V电源给测速芯片供电,黑色线接地。编码器芯片上已集成了脉冲整形触发电路,输出的是矩形波,用示波器检测相当稳定,直接连到单片机IO端口就OK了。

    DFRobot公司出品的Arduino UNO控制器有两块电路板层叠而成,底下的一块板子是Arduino UNO R3,上面的板子是Xbee传感器扩展板,它有专门的无线数传插槽,BluetoothV3蓝牙模块就可以插在其中。如图4所示。

图4 Arduino UNO控制器和BluetoothV3蓝牙模块

    用来驱动两台JGA25-371的编码器减速电机的是5A光电隔离MC33886电机驱动板。它采用飞思卡尔公司生产的电机驱动芯片MC33886,可同时驱动两个电机,输出电流达到5A,瞬时电流最高可达6.5A,可以实现电机PWM调速,正反转,制动等实时控制功能。并具有过流,欠压和温度过高自动保护,以及故障状态提示功能.

图5双路5A光电隔离MC33886电机驱动板

     上图中,MOTO1与MOTO2端子分别是两台电机的接线端子,MOTO POWER端子用于连接电机供电电源。电路板左侧的插槽是控制信号输入接口,它里面有10个引针,其中只用5个引针有效,如图6所示。

图6  MC33886电机驱动板控制信号输入接口

    控制信号输入接口中P1、P2分别为两路电机的PWM控制信号输入端,D1、D2分别为两路电机的旋转方向控制输入端。P1、D1、P2、D2和+5V引针分别用双母头杜邦线与Arduino控制器上的传感器扩展板数字端口的5、4、6、7信号引针以及VCC引针相连。

    3JGA25-371直流减速电机编码器的橙色和黄线两根电机引线连在图5所示MC33886电机驱动板的MOTO POWER端子,绿色、白色线两根脉冲输出线和红色、黑色线逻辑电源线用杜邦线与图4Arduino控制器的数字端口、VCCGND引针相连。

    智能车电控系统还有两块锂聚合物电池,一块电池电压为7.4V,容量为900mAH,给Arduino控制器供电,另一块电池电压为8.4V,容量为3500mAH,通过MC33886电机驱动板给电机供电。

 

四、Andriod手机蓝牙通信软件的下载和设置

    我在安智市场网页找到了一款“蓝牙串口通信助手”的应用程序,网页:http://tcl.anzhi.com/soft_113461.html,大家可以下载到自己的PC机上,下载后的文件格式为apk格式,这个格式的文件可以直接复制到Andriod手机中进行安装使用。具体安装步骤可参考我以前一篇博文,

网址:http://blog.chinaaet.com/detail/33089.html

     该软件为蓝牙客户端通信工具,能连接单片机及PC的蓝牙串口。软件功能:1、搜索蓝牙设备,并显示蓝牙设备的class与RSSI(信号强度);2、接收与发送数据;3、可设置ASCII与HEX的输入输出模式;4、可将数据结果保存到SD卡。

     它有三种使用模式:1、普通模式:基本的输入输出模式;2、键盘控制模式:可自定义9个按钮的输出值;3、命令行模式:可设定命令的结束符,用于通信调试。如图7所示,这次我采用的是键盘控制模式。

 “蓝牙串口通信助手”的应用程序请下载:http://yunpan.cn/Qe4u62U4cfbFJ(访问密码:114c)  

图7 蓝牙串口通信助手的使用模式

   安装好这个软件后,首先从手机的应用程序界面中找到该软件的图标,点击它,就会搜索周边的蓝牙设备,不久会找到DFRobot公司的BluetoothV3蓝牙模块,显示如图8。

图8 BluetoothV3蓝牙模块搜索

    点击图8中的“BluetoothV3”,会进入图7界面,选择“键盘模式”,进入图9界面。

图9 键盘使用模式设置的第一步

    这时上图的接受数据区会显示“设备连接中…”,当如图4所示Arduino控制器上蓝牙模块的“LINK”灯点亮时,就会接着显示“连接成功”,于是Andriod手机通过蓝牙就与Arduino控制器建立了无线串口联机。然后点击手机外壳的“MENU”按钮,手机屏幕下端会出现设置菜单,如图10所示。

图10 键盘使用模式设置的第二步

  先点击“设定IO模式”,把输入输出模式设置ASCII字符输出,如下图。

图11 键盘使用模式设置的第三步

   点击上图“确定”按钮,再按下手机外壳的“MENU”按钮,当屏幕下端又出现图10中设置菜单时,继续点击的“设置键盘”按钮,会出现图9界面,现在开始设置按钮名称和发送内容。比如想设置一个“前进”按钮,就九个按钮中选择一个合适位置的按钮,点击它,会出现图12界面。

图12 键盘使用模式设置的第四步

   把手机界面的光标切入到按钮名称设置栏中,把初始名称“点我”改为“前进”,再把发送内容设置为ASCII码’a’。设置完毕后点击“确定”,再按下外壳上的“MENU”按键,随后出现如图13所示的设置菜单,点击菜单中的“键盘设置结束”选项,从而完成整个设置工作。

图13 键盘使用模式设置的第五步

    在键盘模式界面的九个按钮中,我设置了七个按钮,它们为“前进”、“后退”、“左转”、“右转”、“停止”、“高速”、“低速”,对应的发送内容ASCII字符分别为’a’、’b’、’c’、’d’、’s’、’m’、’n’。当Arduino控制器接受到这些ASCII字符后,就会控制MakeBlock智能车执行相应的动作。

 

五、Arduino控制器的程序编制

    Arduino控制器的程序任务是:接受Andriod手机的前后、左右、停止以及高低速度切换控制字符,并通过直流电机驱动板,驱动智能车按照遥控指令运行。

    当小车前进和后退时,要求小车能走直线。这里是通过编码器、Arduino控制器和电机驱动板、直流减速电机形成的闭环控制系统来实现的。编码器这样的传感器是可以测量转速和转角的,如果把左右电机中编码器反馈的转速送入Arduino单片控制器中,控制器就会知道小车不能走直线的真正原因,并实时计算出两轮的转速差,然后可以设立一个PID比例算法,让转速慢轮子的电机功率值加大,从而消除车轮的转速差。

  下文介绍的Arduino程序中PID比例算式是:

  PWM_left=(float)PWM_left+(rpm_right-rpm_left)*2; 

    式子中rpm_right是右电机的转速;rpm_left是左电机的转速;PWM_left是左电机的PWM功率值。左右电机的转速差乘以比例调节因子2,再叠加上一次PID计算得到的PWM_left,就得到了当前左电机PWM功率值PWM_left。如果右电机转速rpm_right比左电机转速rpm_left要低,则从算式中可以看到,会自动减小左电机功率值PWM_left,反之亦然,通过循环执行Arduino程序中PID算式,便可达到两电机转速一致的目的。

Arduino程序:

//把小车右侧电机的编码器OUTA信号连接到Arduino控制器的数字端口2
#define PinA_right 2 ////数字端口2是Arduino的外部中断0的端口
#define PinB_right 8 //右侧电机的编码器OUTB 信号对于数字端口8
//把小车左侧电机的编码器OUTA信号连接到Arduino控制器的数字端口3
#define PinA_left 3 //数字端口3是Arduino的外部中断1的端口
#define PinB_left 10 //左侧电机的编码器OUTB 信号对于数字端口10
int E_right =5; //连接小车右侧电机的PWM控制端口到数字接口5
int M_right =4; //连接小车右侧电机的转向控制端口到数字接口4
int E_left =6; //连接小车左侧电机的PWM控制端口到数字接口6
int M_left =7;  //连接小车左侧电机的转向控制端口到数字接口7
int PWM_right=150;//设置电机初始PWM功率值
int PWM_left=PWM_right;
int flag;   //暂存变量,用于Arduino接受Andriod手机的控制字符
long count_right = 0;  //定义编码器码盘计数值(此编码器转一圈发出334个脉冲)
long count_left = 0;
long rpm_right = 0;    //每分钟(min)转速(r/min)
long rpm_left = 0;
unsigned long time = 0, old_time = 0;// 时间标记
 
//初始化
void setup()
{
  Serial.begin(9600);    // 启动串口通信,波特率9600b/s
  pinMode(M_right, OUTPUT);   //直流电机驱动板的控制端口设置为输出模式
  pinMode(E_right, OUTPUT);
  pinMode(M_left, OUTPUT);  
  pinMode(E_left, OUTPUT);
  pinMode(PinA_right,INPUT); //伺服电机编码器的OUTA和OUTB信号端设置为输入模式
  pinMode(PinB_right,INPUT);
  pinMode(PinA_left,INPUT);
  pinMode(PinB_left,INPUT);
  //定义外部中断的中断子程序Code(),中断触发为下跳沿触发
  //当编码器码盘的正交编码板OUTA脉冲信号发生下跳沿中断时,
  //将自动调用执行中断子程序Code()。
  attachInterrupt(0, Code_right, FALLING);
  attachInterrupt(1, Code_left, FALLING);
}
//对直流电机驱动板的使能端口和转向端口进行设置,以使小车
//执行前进、后退、左转、右转、停止和速度切换动作。
void advance()//小车前进
{ 
     digitalWrite(M_right,HIGH);
     analogWrite(E_right,PWM_right);
     digitalWrite(M_left,HIGH);
     analogWrite(E_left,PWM_left);
}
void back()//小车后退
{    
     digitalWrite(M_right,LOW);
     analogWrite(E_right,PWM_right);
     digitalWrite(M_left,LOW);
     analogWrite(E_left,PWM_left);
}
void left()//小车左转
{
     digitalWrite(M_right,HIGH);
     analogWrite(E_right,90);
     digitalWrite(M_left,LOW);
     analogWrite(E_left,90);
}
void right()//小车右转
{
     digitalWrite(M_right,LOW);
     analogWrite(E_right,90);
     digitalWrite(M_left,HIGH);
     analogWrite(E_left,90);
}
void Stop()//小车停止
{
     digitalWrite(E_right, LOW); //右电机停
     digitalWrite(E_left, LOW); //左电机停
}  
//主程序
void loop()
{
  //如果Arduino控制器读缓冲区中存在Andriod手机下达的字符命令
  if (Serial.available()>0)
  {    
      flag = Serial.read(); //读出Arduino控制器读缓冲区的字节
      delay(5);    
      if(flag =='a')      //如果读出的字节为“前进”标志字符'a'
      {            
         Stop();           //小车先暂停
         delay(10);
         PWM_left=PWM_right;
         advance();      //小车再前进
         count_right = 0; //恢复小车编码器初始计数状态
         count_left = 0;
         old_time=  millis();   
       }
       else if( flag =='b') //如果读出的字节为“后退”标志字符'b'   
       {                
         Stop();        //小车先暂停
         delay(10);
         PWM_left=PWM_right;
         back();           //小车再后退
         count_right = 0;  //恢复小车编码器初始计数状态
         count_left = 0;
         old_time=  millis();       
       }                   
      else if(flag=='m')
      {
        PWM_right=200;    //小车行驶速度切换为高速状态
        PWM_left=PWM_right;
        count_right = 0;  //恢复小车编码器初始计数状态
        count_left = 0;  
        old_time=millis(); 
      }
      else if(flag=='n')
      {
        PWM_right=150;   //小车行驶速度切换为低速状态
        PWM_left=PWM_right;
        count_right = 0;  //恢复小车编码器初始计数状态
        count_left = 0;  
        old_time=millis(); 
      }
      else if(flag=='c') //如果读出的字节为“左转”标志字符'c'
      {
        left();       //小车左转
      }
      else if(flag=='d') //如果读出的字节为“右转”标志字符'd'
      {
        right();       //小车右转  
      }
      else if(flag=='s') //如果读出的字节为“停止”标志字符's'
      {
        Stop();        //小车停止 
      }
  } 
 
  time = millis();//以毫秒为单位,计算当前时间
  //计算出每0.5秒钟内,编码器码盘计得的脉冲数,
  if(abs(time - old_time) >= 500) // 如果计时时间已达0.5秒
  {
    detachInterrupt(0); // 关闭外部中断0
    detachInterrupt(1); // 关闭外部中断1  
     //此直流减速电机的编码器码盘为334个齿,减速比为21.3。
    //把编码器每0.5秒钟计得的脉冲数,换算为当前转速值的计算式 
    rpm_right =(float)count_right*60*2/(334*21.3);
    rpm_left =(float)count_left*60*2/(334*21.3); 
    //根据左右车轮转速差,乘以比例调节因子2,获得比例调节后的左侧电机PWM功率值
    PWM_left=(float)PWM_left+(rpm_right-rpm_left)*2;      
//根据刚刚调节后的小车电机PWM功率值,
//及时修正小车前进或者后退状态,以使小车走直线
    if(flag=='a')
    advance();
    if(flag=='b')
    back();     
    count_right = 0;   //把脉冲计数值清零,以便计算下一个0.5秒的脉冲计数
    count_left = 0; 
    old_time=  millis();     // 记录每次0.5秒测速后的时间节点    
    attachInterrupt(0, Code_right,FALLING); // 重新开放外部中断0
    attachInterrupt(1, Code_left,FALLING); // 重新开放外部中断1
  }
}
 
//右侧电机编码器码盘计数中断子程序
void Code_right()
{  
  count_right += 1; // 编码器码盘计数加一 
}
//左侧电机编码器码盘计数中断子程序
void Code_left()
{ 
  count_left += 1; // 编码器码盘计数加一   
}

    直流伺服电机中的增量式编码器是将角度位移转换成周期性的电信号,再把这个电信号整形为计数脉冲,用脉冲的个数表示角位移的大小。我把编码器计数脉冲输出线与Arduino控制器中断引脚相连,当计数脉冲输出下跳沿时,会触发中断函数,在中断函数中,每产生一个脉冲,累加一次计数值。

    注意:由于编码器并不是与电机前段的减速器输出轴固连,而是安装在电机尾部,与电机转子轴相连,并且编码器码盘为334线,电机减速比为21.3,所以把每分钟计得的脉冲数要除以334,还要除以21.3,才是电机输出轴的转速。另外由于Arduino程序中,我是每0.5秒,统计一次脉冲数,所以要转换为每分钟的脉冲数,就要乘以60,再乘以2。综合以上两点因素,要得到每分钟电机的转动圈数,则左右电机的转速算式应为:

  rpm_left =(float)count_left*60*2/(334*21.3); 

  rpm_right =(float)count_right*60*2/(334*21.3);

 

六、结束语

    本文介绍的“蓝牙串口通信助手”应用程序,我认为还是蛮实用,可以免去学习Andriod编程之苦,而且它的键盘模式界面中有9个按键,排列成九宫格形式,方便布局和设置各按键的操作功能和发送内容,具有对各类智能装置遥控的很好适应能力。

    另外,本文用到的带编码器的直流减速电机,让智能车的移动可控性大大增强,多多使用这类伺服电机,可以使DIY爱好者的创意目标更方便达成。