宜昌老张

MMA7361加速度体感手柄遥控乐高星战车

0
阅读(5836)

图1体感手柄遥控乐高星战车全景图 

一、前言

    乐高迷们达到一定的搭建水平后,总是不满足于照着现成的SET套件搭建图纸来制作模型,而是想办法改装些自己原创的作品,其中把原先静态的模型加上乐高Technic或者NXT电机,让模型动起来,是作品改装的一个重要项目。

 2 乐高STAR WARS系列的4481星战车模型

    这次我改造的是乐高STAR WARS系列的4481星战车模型,它是一个静态模型,原先打算采用乐高原厂电控产品,但乐高全系列的电控产品都相对个头较大,若加到模型上,会使模型显得臃肿而破坏原本的造型,所以我选用了产品更加丰富,更加灵活的Arduino电控产品。

    遥控器和星战车的电控都采用了Arduino控制器作为智能处理器。遥控器上还有飞思卡尔MMA7361加速度传感器,它能够把遥控器所处姿态反馈到控制器中,然后控制器主机会根据姿态倾角信息,通过XBee无线数传发送字符命令给星战车上的Arduino控制器从机,然后该从机会驱动四个360度连续旋转舵机,让星战车前后左右地行驶。

MMA7361加速度体感手柄遥控乐高星战车视频:


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

 

二、乐高星战车的结构组成

     遥控器采用的控制器是Arduino UNO,而乐高星战车采用的控制器是Flyduino,它是一款基于Arduino的微型控制器,尺寸仅用40X24mm,在这样小的电路板上,集成了12个数字端子(舵机控制端子),8个模拟端子,1个XBee无线数传接口。自身仅重7.5g,配上XBee模块也只有15g左右。非常适合嵌入到小型模型中,而不影响模型原本的造型。

    这次我用Flyduino控制器连接四个mini舵机,它们输出轴上的小齿轮与星战车两边的“巨轮”内齿啮合,使“巨轮”滚动起来,驱动星战车前后左右行驶。

     乐高星战车Arduino电控系统的电机是辉盛9克mini舵机,它并不是乐高公司出品的电机,所以如何把mini舵机安装到乐高积木上,而且要做到舵机输出轴与支撑它的乐高积木孔之间距离,在X和Y轴两个方向上,都为乐高孔距的整数倍(乐高标准孔距为8mm)。这就需要自制一个专门适配乐高积木的舵机连接板。如图3所示。

图3适配乐高积木的舵机连接板

    现在淘宝上已经有了这样的连接板,可以买到,大家不妨看看,

http://ardu.taobao.com/search.htm?spm=a1z10.3.w588618719.6.mOQA4c&scid=626612911&scname=wNa43w%3D%3D&checkedRange=true&queryType=cat

    哪位高手也可以自己花精力用雕刻机做几个,当然安装孔的间距和配合精度要做到位才行。

    有了专门的舵机连接板,不用任何机械加工,甚至不需要螺钉螺帽连接,仅用乐高积木,按照图4和5所示方法,就可以改造这个4481乐高星战车模型了。(注:4481星战车模型是乐高老型号的产品,国内淘宝应该不容易买到,我是海淘得到。即使您没有这个模型,也可以利用这篇文章提供的思路改造其它产品。)

图4 Flyduino控制器的安装

图5辉盛mini舵机的安装

 

三、乐高星战车的Arduino电控部件介绍

    乐高星战车的Arduino控制器是DFRobot公司出品的Flyduino,它比普通Arduino控制器体积小很多,但功能一点也不差。在40X24mm尺寸的电路板正面分布着12个数字端子,8个模拟端子,在电路板背面布置了1个XBee无线数传接口。所以它既具备逻辑运算、舵机控制、传感器信号采集的功能,又具备无线通信的功能。Flyduino电路板布局如图6所示。

图6  Flyduino电路板布局

    由于Flyduino控制器没有USB转串口TTL的电路,所以下载程序时,需要使用Arduino FTDI Basic程序下载器。Flyduino控制器的工作电压为3.3V,程序烧写时,注意把程序下载器的供电跳线帽插到3.3V端,否则使用5V电压会损坏您的设备。程序下载器与Flyduino控制器连接方法,见图7。

图7  Arduino FTDI Basic程序下载器与Flyduino控制器的连接

    另外本模型电控系统仅采用了一块7.4V,900mA的锂聚合物电池,而Flyduino控制器有两个电源端口,一个是舵机电源端口“Power In”,另一个是逻辑电源端口“Voltage supply”,见图6所示,所以要把两个端口通过数字端子“Digital I/O”的红色VCC引针和黑色GND引针与逻辑电源端口“Voltage supply”对应的引针,用杜邦线连接起来,以使控制器舵机部分和逻辑部分共用一套电源。

    星战车的四个驱动舵机的输出线分别连接在Flyduino控制器的2、3、4、5号“Digital I/O”数字端子。如图8所示。

图8 乐高星战车的电控组成

    值得注意的是,图8中7.4V锂聚合物电池不能直接连在控制器电源端口上给舵机供电,因为mini舵机的供电电压不能超过6V,否则会出现异常噪音,不能正常工作,所以锂电池要接上一个降压模块才能给舵机供电。我用的这个降压模块的型号为DPC-1,它的输入电压为6~8.4V,输出电压为5V,电流为2A,这样就达到了给四路舵机供电的要求。

    这个乐高星战车电控改造模型里的电控部件里,除了Flyduino控制器、Arduino UNO、传感器扩展板,还用到了两个特别点的电控部件,一是XBee无线数传;二是MMA7361三轴加速度传感器,这个两个电控部件,我在前面文章都介绍过,

一篇是《美国DIGI公司的XBee模块无线通讯实验》,

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

另一篇是《自制体感手柄遥控Arduino二自由度浮动迷宫》,

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

    XBee无线数传和MMA7361传感器在这里就不详述了。这两个电控部件都存在于遥控器电控系统中,如下图所示。

图9 遥控器上的XBee无线数传和MMA7361三轴加速度传感器

 

四、乐高星战车的程序设计

     遥控器主机程序任务:采集MMA7361传感器加速度信息,并把加速度信息通过标定的方法,转换为遥控器的前后、左右倾角姿态,再根据倾角姿态,向乐高星战车上的从机发送驱使星战车前后左右行驶的字符命令。

遥控器主机程序:


//初始化
char val='f';//定义变量,用于存储下达给从机的字符命令
void setup()
{
  Serial.begin(9600);//启动串口通信,波特率为9600b/s
}
//主程序
void loop()
{
  //把MMA7361加速度传感器的重力加速度X、Y、Z轴分量的输出线,分别接入
  //Arduino UNO控制器的模拟量端子0、1、2。
  int xValue = analogRead(0);
  int yValue = analogRead(1);
  int zValue = analogRead(2);
  /*当模拟量端子的电源供电电压为5V时
(注:供电电源超过6.5V,Arduino控制器的稳压电路才能输出5V电压),
 选择±1.5g量程,开始标定,先把遥控器放置水平,
若定义前方是Y轴方向,那么遥控器绕Y轴向左旋转至垂直位置,
 则重力加速度X轴分量xValue值标定为175,而遥控器向右旋转至垂直位置,xValue值为500。*/
  //把绕Y轴旋转180度的两个特定位置的xValue值175~500正比转换为角度值0~180。 
  int yRotate=map(xValue,175,500,0,180);
  //把绕X轴旋转180度的两个特定位置的yValue值520~190转换为角度值0~180
  int xRotate=map(yValue,520,190,0,180);
  if(yRotate<=0) yRotate=0;//如果绕Y轴旋转的角度值出现负数,则强制为0
  if(xRotate<=0) xRotate=0;//如果绕X轴旋转的角度值出现负数,则强制为0
  if(yRotate>=180) yRotate=180;//如果绕Y轴旋转的角度值大于180,则强制为180
  if(xRotate>=180) xRotate=180;//如果绕X轴旋转的角度值大于180,则强制为180
  /*由于体感手柄中三轴加速度MMA7361传感器的采样值有固有的跳动现象,所以采用软件容错的方法,
  以防止舵机驱动的星战车出现随之抖动的现象,例如,当体感手柄
  绕X轴姿态角度偏离90度中央位置(此位置为遥控器水平姿态),xRotate角度值小于等于70度时,
  才发出星战车前进的命令,而在手柄姿态xRotate位于70度~75度时,星战车舵机保证当前状态不变。
  如果体感手柄向水平状态恢复时,它的绕Y轴姿态角度大于75度,则星战车才从前进状态转变为停止状态。
  由于有了70度~75度的缓冲区,就不会在手柄某个倾角位置,出现星战车一会向前,一会停止的抖动现象。
  体感手柄绕X轴姿态角度偏离90度中央位置,向另外一个方向旋转时,数据处理方法与上述方法同理。*/
   //如果遥控器绕X轴,前倾或者后倾,则主机向从机发出前进或后退的字符命令
   if(xRotate<=70 && yRotate>75 && yRotate<=105)  val='a';//星战车前进
   if(xRotate>70 && xRotate<=75) val=val;//防止抖动,保持原来的命令状态
   if(xRotate>=110 && yRotate>75 && yRotate<=105)  val='b';//星战车后退
   if(xRotate>105 && xRotate<110) val=val; //防止抖动,保持原来的命令状态
   //如果遥控器绕Y轴,左倾或者右倾,则主机向从机发出左转或右转的字符命令
   if(yRotate<=70 && xRotate>75 && xRotate<=105) val='c'; //星战车左转
   if(yRotate>70 && yRotate<=75) val=val;
   if(yRotate>=110 && xRotate>75 && xRotate<=105) val='d';//星战车右转
   if(yRotate>105 && yRotate<110) val=val;
   //如果遥控器姿态接近于在水平状态,则星战车停止。
  //注意:绕Y轴和X轴角度为90度时,遥控器为水平状态。
   if(yRotate>75 && yRotate<=105 && xRotate>75 && xRotate<=105) val='f';
   Serial.print(val); //遥控器主机向星战车从机发出字符命令
   delay(300);     //延时0.1s,等待发送完成
} 


    星战车从机程序任务:接受遥控器主机发来的前后左右和停止的字符命令,并把字符命令转换成四个舵机的速度、方向值,驱动星战车行驶。

星战车从机程序:


#include "Servo.h"  //声明舵机函数库
Servo Rf_servo;  //定义星战车右巨轮前方舵机对象变量
Servo Rb_servo;  //定义星战车右巨轮后方舵机对象变量
Servo Lf_servo;  //定义星战车左巨轮前方舵机对象变量
Servo Lb_servo;  //定义星战车左巨轮后方舵机对象变量
int power1=85;//定义星战车前进、后退速度
int power2=10;//定义星战车转弯速度,转弯速度要慢些
int val; //定义变量,用于存放Arduino主机下达的字符命令
//初始化
void setup()
{
   Serial.begin(9600);//设置串行通信的波特率
   //定义2、3、4、5号数字量端子来控制星战车四个驱动舵机
   Rf_servo.attach(2); 
   Rb_servo.attach(3);
   Lf_servo.attach(4); 
   Lb_servo.attach(5);
   //连续旋转的舵机,执行myservo.write(90),舵机的速度可能不为0,
   //实际舵机零速值应该在90附近,需要实际测试确定。
   Rf_servo.write(92); //让四个舵机初始状态为零速
   Rb_servo.write(93);
   Lf_servo.write(94);
   Lb_servo.write(94);
}
//主程序
void loop()
{
  val=Serial.read();//读取Arduino主机下达的字符命令
  if(val=='a')//如果接受到‘a’字符,则星战车前进
  {
     Rf_servo.write(92+power1);
     Rb_servo.write(93+power1);
     Lf_servo.write(94-power1);
     Lb_servo.write(94-power1);    
  }
  if(val=='b')//如果接受到‘b’字符,则星战车后退
  {
     Rf_servo.write(92-power1);
     Rb_servo.write(93-power1);
     Lf_servo.write(94+power1);
     Lb_servo.write(94+power1);     
   }
  if(val=='c')//如果接受到‘c’字符,则星战车左转
  {
     Rf_servo.write(92+power2);
     Rb_servo.write(93+power2);
     Lf_servo.write(94+power2);
     Lb_servo.write(94+power2);    
  }
  if(val=='d')//如果接受到‘d’字符,则星战车右转
  {
     Rf_servo.write(92-power2);
     Rb_servo.write(93-power2);
     Lf_servo.write(94-power2);
     Lb_servo.write(94-power2);     
   }
  if(val=='f')//如果接受到‘f’字符,则星战车停止
  {
     Rf_servo.write(92);
     Rb_servo.write(93);
     Lf_servo.write(94);
     Lb_servo.write(94);     
   }   
  delay(10); //延时
}



五、结束语

    乐高Technic系列和NXT系列套件中本身自带的电控产品已经设计得相当不错了,而且还有许多第三方公司兼容乐高的电控产品可供选择,但是比较Arduino电控产品来说,在产品丰富度和性价比上,Arduino电控还是具备很强的优势,比如这个乐高星战车的电控改造,使用了Arduino电控,既做到了体感手柄遥控,又因选择了体积小巧的电控产品,所以也没有破坏4481模型原有的美观,而且这个模型由于使用的是Arduino控制器,所以还有功能扩展的空间,比如加装红外传感器来实现避障,或者加装指南针传感器来实现智能导航,这些还可以去尝试。