查看: 8996|回复: 2

Makeblock搬运遥控车之直线导轨控制

[复制链接]
本帖最后由 yichangzhang 于 2014-4-23 16:57 编辑

   搬运车身前部安装了直线导轨装置,该装置由两根细长导轨、滑座、若干个小型滚轮以及直流伺服电机和同步传动带组成。位于装置顶部的电机通过同步带驱动滑座,在滚轮的约束下,相对导轨上下移动。滑座前端固定了一个用于搬运物料的夹持器,可以跟随滑座一起运动,以实现抬起和放下物料的任务。
    直线导轨上端还安装了一个触动开关,当夹持器上行到导轨最高处时,会触碰到这个开关。由于通过直流伺服电机尾部的编码器计数脉冲,可以获得电机转动角度,进而获得同步带拽动的夹持器移动距离,所以把这个触动开关作为原点开关,可以方便确定出夹持器相距原点开关的距离,从而也能知道夹持器离地高度。
搬运小车整车.jpg
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
1 搬运遥控车全景图

一、搬运车直线导轨部分的电控系统组成
    搬运车直线导轨部分的电控系统组成为:型号为JGA25-371直流伺服电机、Arduino MEGA2560控制器与XBee无线数传模块,一块MC33886电机驱动板,稳压电源模块,还有12V锂聚合物电池。这里的大部分电控部件已经在《Makeblock搬运遥控车之夹持器控制》一文讲解,就不再累述。现在重点讲讲JGA25-371编码器减速电机的应用。
带编码器的直流电机.jpg
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg
2 JGA25-371直流伺服电机的安装
    如图2所示,JGA25-371直流伺服电机就是一款带编码器的直流减速电机,它的工作电压为6~24VDC,额定电压为12V。它的外圆直径为24.4mm,输出轴直径为4mm,其端面安装孔位正好与MakeBlock的电机安装支架相吻合,电机轴上有坡口切面,借此可以方便地通过锁紧螺钉与同步带轮零件相固连。
    这个型号的电机有多种输出转速可供选择,我选择的是减速比为45,空载转速为95r/min的电机。与电机转子轴相连的编码器码盘有334线,也就是电机转子转一圈会输出334个脉冲,这种多线数编码器保证了测量的精度性。
    用来驱动JGA25-371编码器减速电机是MC33886驱动板。这个驱动板是一款大电流电机驱动模块,两路电机输出,可实现 PWM调速、正反转、制动功能等。外观图见图8所示。当然一个这样的编码器电机也只要用到MC33886驱动板一路控制及输出接口即可。
MC33886驱动板.jpg
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image006.jpg
3 MC33886直流电机驱动板接口功能图
    从图3中应该可以看出,12V锂电池通过稳压电源模块把电压降到8.5V,再把两根电压为8.5V的电源线接在电池输入端子,而直流伺服电机的橙色和黄线两根驱动线(如图4所示)接在电机接口端子。
    驱动一个直流伺服电机除了需要大电流的电源线和驱动线以外,还需要多少根起测控作用的信号线?从上文所述的电控配置来看,需要七根信号线。其中MC33886直流电机驱动板的控制接口有三根信号线,分别为IN11、IN12、GND,要用杜邦线连接到Arduino传感器扩展板的数字端口上。这三根线如何控制电机的转速和转向见《Makeblock搬运遥控车之夹持器控制》一文。
电机.JPG
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image008.jpg
4 JGA25-371直流伺服电机全景图
    七根信号线中,另外四根信号线就是用于编码器计数脉冲的,如图4所示编码器减速电机有6根输出线,其中绿色和白色信号线是两组脉冲输出线,用一根线就能测量转速,双脉冲可以判断旋转方向,红色的信号线接3V至5V电源给测速芯片供电,黑色线接地。这四根信号线直接连到Arduino控制板数字端口的信号引脚和电源引脚,就OK了。注意绿色和白色脉冲输出线一般要接到有中断功能的数字端口。
    直线导轨上端安装的触动开关也要用数据线接到Arduino控制板的某一数字端口。
针对直流伺服电机控制的Arduino控制板数字端口信号引脚分配表
  
信号线实际名称
  
信号线位变量名称
Arduino数字引脚号
功能备注
绿色脉冲输出线
PinA
2
外部中断0
驱动板控制线IN11
P11
6
支持PWM输出
驱动板控制线IN12
P12
7
支持PWM输出
触动开关数据线
Limit
12

  下面的Arduino程序,会根据该分配表,对测控JGA25-371直流伺服电机的这四根控制信号线进行定义。

二、Makeblock搬运车的直线导轨控制调试程序编制
    机械和电子硬件组装完毕后,我一步步通过LabVIEW软件来调试各执行部件的动作,并确定出来重要参数。这次调试的是直线导轨控制,确定出夹持器移动到相距原点开关特定距离时,伺服电机转过的角度值,以及电机转速多大时,夹持器的移动速度是合适的。
要控制直线导轨上夹持器的移动距离和移动速度,就要通过上位机LabVIEW软件来测控带动夹持器升降的伺服电机转速和转角以及转向。谈到测控,    就是控制对象是直流电机,而测量对象是电机尾部的编码器。Arduino控制板通过给MC33886驱动板发送控制信号来控制电机转向和转速,编码器给Arduino控制板的中断引脚发计数脉冲,来让控制板采集电机转角和转速。
    对于码盘有334线的编码器,减速比为45的电机,如果计数得到334*45个脉冲,就说明电机输出轴转了360度。而如果知道单位时间内,计数到多少脉冲,就可以换算出转速了。
直线导轨前面板.jpg
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image010.jpg
图5 直线导轨测控前面板
    上图前面板中右侧的旋钮控件作用是给下位机Arduino控制板下达电机控制的PWM信号值,这个值越大,则电机转速越快。左侧的仪表控件则是把由编码器单位时间的脉冲数转换而来的转速(r/min)显示在仪表盘上。同时前面板还可以设置电机转动的圈数,并且编码器反馈给上位机的电机实时转动圈数信息也会显示在前面板上。
    前面板后台程序是一种用图标代替文本行创建应用程序的图形化编程语言,又称为 “G” 语言。使用这种语言编程时,基本上不写程序代码,取而代之的是流程图或框图。它是前面板中输入、输出控件的程序逻辑,如图6所示。
直线导轨控制程序.jpg
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image011.jpg
图6 直线导轨测控框图程序的“正转”事件分支
    在这个框图程序中,我采用了事件结构,这个结构分为四个由按钮控件引发的事件分支和一个超时事件分支。四个按钮是分别指正转、反转、停止、退出按钮。图6展示的就是正转按钮分支,这个分支的功能是当前面板设置好控制电机转速的PWM值和电机转动圈数值后,点击正转按钮,有四个字节会通过 “创建数组”VI和“字节数组至字符串转换”VI,把它们以字符串格式借助“VISA写入”VI通过串口下达给下位机Arduino控制板。这个四个字节先后为“开始发送字符串”的标识字节0x11,电机正转的标识字节0xAA,以及转速PWM值和圈数10倍值。
     圈数10倍值发送到下位机程序后,Arduino会再除以10,来还原为真实的圈数值,这样做的目的是使发送字节总是以整数形式出现,而不直接表示为浮点数。比如1.5圈,先以10倍值15来发送,下达给Arduino程序后,再会把它转换为1.5圈。
直线导轨框图程序.jpg
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image012.jpg
图7 直线导轨测控框图程序的“超时”事件分支
    图7所示的是直线导轨测控框图程序的“超时”事件分支,当前面板没有按钮被按下时,就执行“超时”事件。这个事件分支的功能是先一个一个字节用“VISA读取”VI去读取,当发现有“开始上传字符串”的标识字节0x01后,接着再用另一个“VISA读取”VI去读取接下来上传的两个字节。这两个字节先后为编码器反馈的电机转速值和电机圈数值。
停止带事件分支.jpg
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image014.jpg
图8 停止带事件结构的While循环的正确方法
    值得注意的是,要退出一个包含事件结构的While循环,必须把退出按钮放在事件结构中,如图8所示。如果退出按钮放在事件结构外,事件结构将一直等待,无法退出程序运行。
     与上位机LabVIEW程序相配合的是Arduino程序,这个程序有四部分主要功能,一是接受和上传字节的串口通信程序段,通信程序段用红色字体在程序中标识出来,二是电机控制程序段,用蓝色字体标识,三是编码器脉冲计数程序段,用褐色字体标识,四是转速转换程序段,用黄色字体标识。
Arduino程序:

//把编码器正交编码板OUTA信号连接到Arduino控制器的数字端口2,
//数字端口2是Arduino的外部中断0的端口。
#definePinA 2 //外部中断0
intP11 =6; //直流电机驱动板的电机使能端口连接到数字接口6
intP12 =7; //直流电机驱动板的电机转向端口连接到数字接口7
//定义暂存数组,用于存储上位机发出的3个电机控制字节
//第一个字节用于控制电机是否启动;
//第二个字节用于控制电机是正转还是反转;
//第三个字节用于提供给电机PWM调数值。
intLimit=12;
intworking_state=0;
intval[4];
unsignedlong speed_count = 0;   //定义编码器码盘的计数值(此编码器转一圈发出12个脉冲)
unsignedlong pos_count=0;
byterpm = 0;    //定义每分钟(min)转速(r/min)
byteflag;     //定义上传给上位机的用于判断电机正转还是反转的标志字节
byte  ratate_number;
byteStart=0x01;
unsignedlong time = 0, old_time = 0; //时间标记
//初始化
voidsetup()
{
  Serial1.begin(9600);    //启动串口通信,波特率9600b/s
  pinMode(P11, OUTPUT);   //直流电机驱动板的控制端口设置为输出模式
  pinMode(P12, OUTPUT);
  pinMode(PinA,INPUT); //伺服电机正交编码板的OUTA和OUTB信号端设置为输入模式  
  pinMode(Limit,INPUT);   
  //定义外部中断0的中断子程序Code( ),中断触发为下跳沿触发
  //当编码器的正交编码板OUTA脉冲信号发生下跳沿中断时,
  //将自动调用执行中断子程序Code( )。
  attachInterrupt(0, Code, FALLING);  
}
//主程序
voidloop()
{
  if (Serial1.available()>0) //如果Arduino控制板的读缓冲区中存在上位机下达的字节
  {
     delay(30);
     for(int i=0; i<4; i++)//for循环次数与上位机下达的字节数一致
     {val = Serial1.read(); //读出Arduino控制板读缓冲区的字节      
      }
     if(val[0]==0x11)        //如果读出的第一个字节为启动标志字节0x11
     {
       if(val[1]==0xAA)        //如果读出的第二个字节为正转标志字节0xAA
       {
         working_state=1;               
         ratate_number=0;
         speed_count = 0;
         pos_count=0;
         old_time=  millis();  
       }
        if(val[1]==0xBB)  //如果读出的第二个字节为反转标志字节0xBB  
       {
       working_state=2;
        ratate_number=0;        
        speed_count = 0;
        pos_count=0;
        old_time=  millis();      
       }
     }
      else //如果读出的第一个字节不是启动标志字节0x11
      {
        working_state=0;
        ratate_number=0;        
        speed_count = 0;
        pos_count=0;   
        old_time=  millis();        
      }
  }
if(working_state==1)
  {
    analogWrite(P11,val[2]); //电机以第三个字节中PWM调速值的转速转动
     digitalWrite(P12,LOW); //电机正转         
  }
  else if(working_state==2)
  {     
    digitalWrite(P11,LOW); //电机反转
     analogWrite(P12,val[2]); //电机以第三个字节中PWM调速值的转速转动      
  }
  else if(working_state==0)
  {
     digitalWrite(P11, LOW); //电机停止
     digitalWrite(P12, LOW); //电机停止
  }
  //如果计得的脉冲数为电机转过0.1圈时编码器发出的脉冲数
  if( pos_count>=(float)334*45*0.1)
  {
     ratate_number += 1;  //电机转过0.1圈时,圈数值加0.1圈
     if( ratate_number==255)
         ratate_number=0;
     //脉冲计数变量清零,并开始记录下一个0.1圈做好准备
     pos_count=0;
  }
  //当编码器记录的电机圈数与LabVIEW软件设置的圈数一致时,
  if(val[3] == ratate_number)
  {
    digitalWrite(P11, LOW); //电机停止
    digitalWrite(P12, LOW); //电机停止        
    working_state=0;
  }  
  //如果电机反转带动夹持器上升,同时夹持器触碰到原点开关
  if (digitalRead(Limit) == LOW &&  working_state==2 ) {     
    digitalWrite(P11, LOW); //电机停止
    digitalWrite(P12, LOW); //电机停止        
    working_state=0;
  }
  time = millis();//以毫秒为单位,计算当前时间
  //计算出每一秒钟编码器码盘计得的脉冲数,
  if(abs(time - old_time) >= 500) //如果计时时间已达0.5秒
  {
    detachInterrupt(0); // 关闭外部中断0
    //把每一秒钟编码器码盘计得的脉冲数,换算为当前转速值
     //此编码器码盘为334个齿。
    rpm =(float)speed_count*60*2/(334*45);  
    Serial1.write(Start);
    Serial1.write(rpm);//向上位计算机上传电机当前转速的高字节
    Serial1.write(ratate_number);    
    speed_count = 0;   //把脉冲计数值清零,以便计算下一秒的脉冲计数
    old_time= millis();      
    attachInterrupt(0, Code,FALLING); // 重新开放外部中断0
  }
}
// 编码器码盘计数中断子程序
voidCode()
{  
  //当编码器正交编码板OUTA脉冲信号下跳沿每中断一次,
  speed_count += 1; // 编码器码盘计数加一
  pos_count += 1;  
}
   Makeblock搬运车的直线导轨动作调试程序介绍完了,下篇文章继续介绍搬运车行走控制调试程序的编制。

Rockets  NPC

发表于 2014-5-6 16:44:51

这个过程的记录确实是很精彩啊
回复

使用道具 举报

盖世吴双  学徒

发表于 2014-7-7 15:05:58

高手,技术精湛,学习中
回复

使用道具 举报

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

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2020 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail