宜昌老张

【技术分享】自制体感手柄遥控Arduino二自由度浮动迷宫

0
阅读(4808)

图1 自制体感手柄遥控Arduino二自由度浮动迷宫实验全景图

    前段时间玩过一款“重力平衡球”手机游戏,英文名:Teeter,如图2所示,挺有意思的,游戏是这样玩的,用户轻微地摆动手机,屏幕上的重力球,也随之往摆动的方向滚动,您要让小球依托墙壁,不让它掉进“黑色”的陷阱,沿着设定的途径游走,一直达到目的地,落进绿色的孔洞。

图2 Teeter重力平衡球游戏

    我玩这个虚拟游戏时,就想到能不能做一个这个游戏现实版的作品。自己做个自制体感手柄,手柄中用上与手机类似的三轴加速度传感器,检测出体感手柄的空中姿态,然后通过无线通讯的方式,把手柄的姿态信息映射到一个“浮动迷宫”模型的两个舵机中,让Y轴和X轴两个方向上的舵机摇动迷宫平台,让其中的小球沿迷宫滚道,在出发地与目的地之间游走。这两天我把这个模型完成了!如图1所示。

实验视频:

  全屏观看,点击网址:http://player.youku.com/player.php/sid/XNDk4Nzc0NzA0/v.swf  

   这篇文章里的“浮动迷宫”模型电控设备里,除了常用的Arduino控制板、传感器扩展板,还用到了两个特别点的电控器件,1、XBee无线数传;2、MMA7361三轴加速度传感器,这个两个电控器件,我在前面文章都介绍过,一篇是《美国DIGI公司的XBee模块无线通讯实验》,网址:http://blog.chinaaet.com/detail/29230.html另一篇是《Arduino加速度传感器与Processing幻彩立方的互动》,网址:http://blog.chinaaet.com/detail/31465.html

    模型的机械部分采用的是乐高积木搭建,有“浮动迷宫”平台和舵机驱动底座两部分组成,舵机驱动底座里有控制Y轴和X轴旋转的两个180度舵机组成,如图3所示。电控部分由两套Arduino控制器、XBee无线数传和MMA7361传感器组成,全部由DFRobot公司出品。如图4所示。把“浮动迷宫”平台安装到舵机驱动底座上,就完成了整个模型的搭建。

图3 “浮动迷宫”平台的舵机驱动底座

图4 “浮动迷宫”模型的电控设备

图5 “浮动迷宫”模型的安装图

   安装舵机时,应该事先把舵机转角调整为90度后,再安装到底座上,尽可能使舵机U型支架保持如图3所示垂直位置,以使安装在其上的“浮动迷宫”平台水平,但是即使这样,也很难保证迷宫平台处于最佳位置,所以要依靠下面Arduino程序,采用电位计精确调整两个舵机的转角,通过观察Arduino串口监视器,来确定当迷宫平台为水平位置时,两个舵机转角位置应设置为多少角度为合适。

//程序任务:通过串口监视器显示的舵机实时转角,确定“浮动迷宫”平台水平时,
//用于控制Y轴和X轴旋转的两个舵机初始角度。
int potpin1 = 0;  // 模拟端口0连接一个电位计,用于控制Y轴舵机转动
int potpin2 = 1; //模拟端口1连接另一个电位计,用于控制X轴舵机转动
int val1;    // 定义变量,用于存储电位计模拟量读出值 
int val2; 
#include <Servo.h> //引用舵机库文件 
Servo myservo1;  // 申明舵机对象 
Servo myservo2; 
//初始化
void setup() 
  Serial.begin(9600);//启动串口通信,波特率为9600b/s
  myservo1.attach(9);  // 把Y轴舵机连接到数字端口9
  myservo2.attach(10); //把X轴舵机连接到数字端口10
//主程序
void loop() 
  val1 = analogRead(potpin1);      // 读取电位计模拟量值
  val2 = analogRead(potpin2);
  val1 = map(val1, 0, 1023, 0, 180); // 把电位计模拟量值转换为0~180舵机角度值
  val2 = map(val2, 0, 1023, 0, 180); 
  myservo1.write(val1);   //驱动舵机转动到指定角度         
  myservo2.write(val2);
  Serial.print("y_moter=");//把舵机角度实时传送到上位机串口监视器中显示 
  Serial.print(val1,DEC); 
  Serial.print("   "); 
  Serial.print("x_moter=");
  Serial.println(val2,DEC);   
  delay(800);              // 延时0.8s,以便观测舵机角度值变化 
  通过以上软件修正,我这个模型,修正的结果是Y轴和X轴舵机的初始位置分别为88和98度。
  “浮动迷宫”的电控系统由体感手柄的主机和驱动“浮动迷宫”的从机组成,体感手柄主机如图6所示。
图6 自制体感手柄   

  主机程序任务为:采集体感手柄中MMA7361三轴加速度传感器的加速度值,再把X轴和Y轴方向的重力加速度分量值转换为绕Y轴和X轴的0~180角度值,然后无线串口协议发送这两个角度值给用于控制“浮动迷宫”的Arduino从机。

//初始化
void setup() 
  Serial.begin(9600);//启动串口通信,波特率为9600b/s
//主程序
void loop() 
  //把MM7361加速度传感器的重力加速度X、Y、Z轴分量输出,分别接入
  //Arduino控制器的模拟量端子0、1、2。
  int xValue = analogRead(0); 
  int yValue = analogRead(1);
  int zValue = analogRead(2);
  /*当模拟量端子的工作电压为5V(实测为4.95v~4.97v)时,选择±1.5g量程
  先把加速度传感器放置水平,若定义前方是Y轴,那么传感器向左旋转至90度垂直位置,
  则重力加速度X轴分量xValue值标定为175,而传感器向右旋转至垂直位置,xValue值为500。
  */
  //把绕Y轴旋转180度的两个特定位置的xValue值500~175正比转换为角度值0~180
  //这里进行了一个反比换算,原因是要使绕Y轴转动方向与体感手柄倾角姿态协调一致。
  int yRotate=map(xValue,500,175,0,180);
  //把绕X轴旋转180度的两个特定位置的yValue值190~520转换为角度值0~180
  int xRotate=map(yValue,190,520,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
  Serial.print(255,BYTE); //发送“标志”字节,以标识将开始发送一次体感手柄两个方向上的角度值
  Serial.print(yRotate,BYTE);//以字节形式,发送体感手柄绕Y轴旋转的角度值
  Serial.print(xRotate,BYTE);//以字节形式,发送体感手柄绕X轴旋转的角度值
  delay(100);             // 延时0.1s,等待发送完成 
 
   从机程序任务:接受体感手柄主机发来的手柄旋转角度信息,判断体感手柄旋转角度是否超过某一位置,由此驱使“浮动迷宫”倾斜一个固定角度,以使小球沿某一方向的迷宫滚道游走。 


#include <Servo.h> //引用舵机库文件 
Servo myservo1;  //  申明舵机对象 
Servo myservo2;  
int yRotate;    // 定义变量,存储主机发送的体感手柄绕Y轴旋转角度
int xRotate;   // 定义变量,存储主机发送的体感手柄绕X轴旋转角度
int  Y_motor; // “浮动迷宫”舵机底座中Y轴舵机的旋转角度
int  X_motor; //“浮动迷宫”舵机底座中X轴舵机的旋转角度
void setup()  //初始化
  Serial.begin(9600);//启动串口通信,波特率为9600b/s
  myservo1.attach(9);  // 把Y轴舵机连接到数字端口9
  myservo2.attach(10); //把X轴舵机连接到数字端口10
  //由于舵机安装时,即使首先把舵机角度调整到90度再安装,也不可能保证
  //迷宫平台水平,所以“浮动迷宫”模型安装完,需通过软件修正,我这个模型,
  //修正的结果是Y轴和X轴舵机的初始位置分别为88和98度。
  myservo1.write(88);  //初始化Y轴和X轴舵机的转角位置,以使迷宫平台水平          
   myservo2.write(98);
   delay(100); //延时
void loop() 
   if (Serial.available()>2) //如果读缓冲区的字节大于2个字节
  {
    //如果从缓冲区读到了“开始发送手柄角度信息”的标志字节“255”
    if(255==Serial.read()) 
    {
    yRotate = Serial.read();//读体感手柄绕Y轴旋转的角度值
    xRotate = Serial.read();//读体感手柄绕X轴旋转的角度值
    }       

  /*

    由于体感手柄中三轴加速度传感器的采样值有跳动现象,所以采用软件容错的方法

    以防止“浮动迷宫”驱动舵机出现随之抖动的现象,例如对于Y轴舵机,当体感手柄

    绕Y轴姿态角度偏离中央位置90度,小于等于65度时,浮动迷宫的Y轴舵机才偏移

90度初始位置-5度,而在手柄姿态位于65~75度时,Y轴舵机保证现有状态不变。

如果体感手柄向水平状态恢复时,它的Y轴姿态角度大于75度,

则“浮动迷宫”平台才从倾斜-5度,恢复到水平状态。

由于有了65~75度的缓冲区,就不会在某个临界位置,出现抖动现象。

   体感手柄绕Y轴姿态角度偏离中央位置90度,向另外一个方向旋转时,数据处理方法与

   上述方法同理。

   */

   //绕Y轴方向上,体感手柄与“浮动迷宫”舵机的随动算法
   if(yRotate<=65) Y_motor=88-5;
   if(yRotate>65 && yRotate<=75) Y_motor=Y_motor;
   if(yRotate>=115) Y_motor=88+5;
   if(yRotate>105 && yRotate<115) Y_motor=Y_motor;
   if(yRotate>75 && yRotate<=105) Y_motor=88;
   //绕X轴方向上,体感手柄与“浮动迷宫”舵机的随动算法
   if(xRotate<=65) X_motor=98-5;
   if(xRotate>65 && xRotate<=75) X_motor=X_motor;
   if(xRotate>=115) X_motor=98+5;  
   if(xRotate>105 && xRotate<115) X_motor=X_motor; 
   if(xRotate>75 && xRotate<=105) X_motor=98;
   myservo1.write(Y_motor);    // 驱动舵机
   myservo2.write(X_motor); 
   // Serial.print(yRotate,DEC);//监控体感手柄的姿态角度信息
   // Serial.print(' ');
   //Serial.println(xRotate,DEC);
   }   
  delay(20);         
    以上主从机程序,有两点值得注意,1、多字节数据传送,多字节传送如果不在主从机通信协议方面下点功夫,会把主机的A字节发送到从机的B变量中,而主机的B字节却发送到从机的A变量中。所以我在传送两个0~180度角度字节前,加入了一个标志字节“255”,以使字节传送不致于混乱。主从机通信程序段,我用红色字体标识出来了。2、由于体感手柄中三轴加速度传感器的采样值有跳动现象,这是加速度传感器所固有的特点,所以采用软件容错的方法以防止“浮动迷宫”驱动舵机在特定位置出现随之抖动的现象,容错程序段,我用蓝色字体进行了标注。

     对于基于MMA7361加速度传感器的体感手柄,其电池盒供电电压要特别注意:要求电源电压应大于6.5V,因为小于6.5V的电源,Arduino控制板上的板载稳压电路不能把电压稳定于5V,实测电压是4.95V,而若稳压后产生电压值不同,我发现MMA7361传感器输出的加速度转换值也是不同的,而且电压越低,加速度转换值越大,所以如果想得到唯一不变的加速度值,则体感手柄应选择的电源应在6.5V到9V之间,这样在精准的4.95V电压下,加速度值与旋转角度的关系标定仅需一次即可,所以体感手柄Arduino主机的乐高technic电池盒里是装有6节镍氢充电电池。

    另外这次采用的舵机是MG995标准舵机,它并非高电压舵机,所以舵机供电电压不能超过6.5V,否则舵机运行时会发生震动,特别是舵机转角位于在0度和180度两个极限位置,震动更大,所以图5所示的Arduino从机乐高电池盒里面安装的镍氢充电电池数目不是6节,而是5节,5节充电电池标准电压为6V。

    从上述说明可以看出,只有动手实践,才能发现问题和解决问题,光看书,不会有问题,也无从去解决问题。


   随着以Arduino为代表的开源硬件的发展,颇具创新精神的Google公司自然不甘人推出了新的应用,名为Android Open Accessory(安卓开源配件),让Andorid手机、平板能与硬件装置连接,进行更多应用,可使用USB接口、或是蓝牙联机,对应系统为Android 2.3.4和3.1。

 除了API之外,Google还推出一款结合硬件和软件的ADK装置,基于Arduino这款开放式架构的微电脑控制板。透过ADK装置能就能使用Android进行体感操作,并同步对应到其它硬件装置上。

  在美国旧金山Moscone West中心召开2011年Google公司I/O全球开发者大会,现场示范用Android装置对应钢珠迷宫游戏,并秀了一段超巨大钢珠迷宫游戏的影片。 

 

Android装置透过ADK操作迷宫游戏体感控制。


透过ADK控制巨型迷宫游戏

摩托Xoom+Android Open Accessory操控重达2吨的巨型迷宫视频:


结束语
      对于成年创客来说,做模型的意义可能科技娱乐的成份多些,当然也用来产品原型设计,捣鼓出某种新产品。但如果您是在校青少年学生或者刚入职场的年轻人,通过制作科技模型和参加创客活动,就可以学习和实践多学科的知识,如机械、电子、计算机、自动化和艺术,这样的创客经历就会自然地用到将来的企业工作中去的。

      最近看了财经评论员叶檀女士主持的一档节目,谈到了机器人技术已经大量应用到沿海企业中的情况,对我很有启发,大家不妨看看。由创客制作训练出的技术能力在由劳动密集型向智力密集型过渡的企业中会很受用的。