图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://www.eefocus.com/zhang700309/blog/12-08/284065_cc230.html。
另一篇是《自制体感手柄遥控Arduino二自由度浮动迷宫》,
网址:http://www.eefocus.com/zhang700309/blog/13-01/291059_f3a81.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控制器,所以还有功能扩展的空间,比如加装红外传感器来实现避障,或者加装指南针传感器来实现智能导航,这些还可以去尝试。