18721浏览
查看: 18721|回复: 17

说说我折腾DFR0182无线手柄遥控乐高ev3的过程

[复制链接]
本帖最后由 taelons 于 2016-12-8 17:07 编辑

    乐高EV3的遥控一般采用红外遥控器和传感器,合计400多毛大大。EV3本身带有蓝牙(2.1版本)功能,如果使用蓝牙,就不需要安装红外传感器了。同时红外遥控器的按键操控性不如手柄方便,所以我打算找一款带蓝牙功能的可编程手柄。问度娘古哥和某宝,目前看来,dfrobot是唯一选择。等拿到dfr0182手柄,感觉比预想的大,做工相当好,不过请允许我先吐几个槽点:
说说我折腾DFR0182无线手柄遥控乐高ev3的过程图11、贵!手柄加蓝牙模块508毛大大,蓝牙2.0居然卖到140毛大大,比BLE4.0的蓝牙贵了近一倍!和EV3红外比,没有优势了(当然蓝牙模块可以买第三方的,便宜一些)。另外还从dfrobot的另一家店铺买了DFR0008手柄,其实是一款带摇杆和按键的Arduino扩展板,以后再介绍。两个店铺看起来是同一个发货地址,收到两个包裹,运费免了一份;
2、上传程序的usb转换板插上去很松,容易脱落,不知道是否由于我曾拆开手柄装蓝牙模块,导致哪里没有卡到位?原包装不带mini usb线,买手柄的亲们要自己准备一根mini usb线;3、拆开手柄安装蓝牙后,发现手柄左上和右上四个按键容易脱落,而且按键内侧的小塑料圈也容易掉落,导致按键不起作用,琢磨了一会,发现窍门是,要从里往外按,才能卡住按键,然后再合上手柄外壳;
4、手柄内部的两根黑红电池线容易断,不方便调试,后来我干脆把线拔了,等电脑上程序调试通过,再找人焊线。

未完待续


taelons  中级技师
 楼主|

发表于 2016-12-8 13:47:49

接下来上传DFR提供的手柄按键检测程序,arduino ide里执行无误,串口监视界面里能显示按下了哪个键。14个键连接到arduino的数字口,低电平0表示按下,从串口监视器和代码里很容易看出。接下来要确定摇杆不同位置的键值分布(姑且称之为raw值),我不懂电路,摇杆是电位器,其raw值应该是模拟的电压值转换成数字值。为方便辨识,将程序中的延迟加大,经多次运行代码,记录如下摇杆raw值分布:


说说我折腾DFR0182无线手柄遥控乐高ev3的过程图1




由于乐高EV3使用特有的蓝牙数据包格式,为方便在蓝牙主从两端的程序中处理,我将17个按键按1-17编号,发送给EV3,EV3解包后,根据收到的数字,在EV3程序中做相应的处理,如前进后退转向加减速等等。数据包格式如下图:
说说我折腾DFR0182无线手柄遥控乐高ev3的过程图2


在arduino里,如何发送蓝牙数据包给EV3呢?请看下面程序片断,修改了DFR的按键检测程序:
  1. unsigned char hexS2[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x60,0x41};
  2. unsigned char hexS1[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x50,0x41};
  3. unsigned char hexUP[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0xa0,0x40};
  4. unsigned char hexLEFT[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0xe0,0x40};
  5. unsigned char hexDOWN[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0xc0,0x40};
  6. unsigned char hexRIGHT[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x00,0x41};
  7. unsigned char hex1[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x80,0x3f};
  8. unsigned char hex4[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x80,0x40};
  9. unsigned char hex2[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x00,0x40};
  10. unsigned char hex3[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x40,0x40};
  11. unsigned char hexRZ1[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x30,0x41};
  12. unsigned char hexRZ2[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x40,0x41};
  13. unsigned char hexLZ1[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x10,0x41};
  14. unsigned char hexLZ2[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x20,0x41};
  15. unsigned char hexJ1[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x70,0x41};
  16. unsigned char hexJ2[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x61,0x00,0x40,0x00,0x00,0x00,0x80,0x41};
  17. void printData(){
  18.   for(int i = 0; i < 17; i++)  Serial.print(buttonState),Serial.print(" ");
  19.   for(int i = 0; i < 4; i++)  Serial.print(joystick),Serial.print(" ");
  20.   for(int i = 0; i < 2; i++)  Serial.print(AnalogButton),Serial.print(" ");
  21.   Serial.println("");
  22.   Serial.print("Button Pressed:");
  23.   for(int i = 0; i < 2; i++)  
  24.   {
  25.       if(buttonState < 100)
  26.       {
  27.         Serial.print(Buttons),Serial.print(",");
  28.         if ( i == 0 )
  29.           Serial1.write(hexJ2,15);
  30.         else
  31.           Serial1.write(hexJ1,15);
  32.       }
  33.   }
  34.       
  35.   for(int i = 3; i < 17; i++)  
  36.   if(buttonState == 0)
  37.   {
  38.     Serial.print(Buttons);
  39.     Serial.print(",");
  40.     switch (i)
  41.     {
  42.             case 3:   
  43.               Serial1.write(hexS2,15);
  44.               break;
  45.       case 4:   
  46.               Serial1.write(hexS1,15);
  47.               break;
  48.       case 5:   
  49.               Serial1.write(hexUP,15);
  50.               break;
  51.       case 6:   
  52.               Serial1.write(hexLEFT,15);
  53.               break;
  54.       case 7:   
  55.               Serial1.write(hexDOWN,15);
  56.               break;
  57.       case 8:   
  58.               Serial1.write(hexRIGHT,15);
  59.               break;
  60.       case 9:   
  61.               Serial1.write(hex1,15);
  62.               break;
  63.       case 10:   
  64.               Serial1.write(hex4,15);
  65.               break;
  66.       case 11:   
  67.               Serial1.write(hex2,15);
  68.               break;
  69.       case 12:   
  70.               Serial1.write(hex3,15);
  71.               break;
  72.       case 13:   
  73.               Serial1.write(hexRZ1,15);
  74.               break;
  75.       case 14:   
  76.               Serial1.write(hexRZ2,15);
  77.               break;
  78.       case 15:   
  79.               Serial1.write(hexLZ1,15);
  80.               break;
  81.       case 16:   
  82.               Serial1.write(hexLZ2,15);
  83.           }
  84.   }
  85.   Serial.println("");
  86.   Serial.print("Analog Sticks:");
  87.   for(int i = 0; i < 4; i++)  Serial.print(joystick),Serial.print(",");
  88.   Serial.println("---");
  89.   for(int i = 0; i < 2; i++)  Serial.print(AnalogButton),Serial.print(",");
  90.   Serial.println("");
  91.   Serial.println("");
  92. }
复制代码


EV3程序里,用一个循环加一个名称为a,读取数字的mailbox块,就可以得到arduino发来的蓝牙按键对应的数字了。当然,事先要在EV3液晶屏里进行蓝牙配对,或程序里配对,应该能看到一个名为“bluetooth_xbee“的设备,就是手柄里的蓝牙模块了。

未完待续。。。。。。



回复

使用道具 举报

dsweiliang  初级技神

发表于 2016-12-8 16:35:24

楼主加油更新啊
回复

使用道具 举报

taelons  中级技师
 楼主|

发表于 2016-12-9 12:20:22

上面的程序是单个键的蓝牙数据发送,这里不需要考虑组合按键,因为手柄的17个键足够分配不同功能了,四个按键就可以完成前进后退左右转向,要玩些花哨功能,如原地打转或漂移等,手柄左上右上四个按键很适合,组合按键徒增操控和编码的复杂度。接下来是摇杆功能的设计,一个摇杆就能完成所有常用功能。此时要向EV3发送坐标值XY。按上面的raw值分布表,Y值代表速度,介意0-1023之间,0代表后退最高速度,在EV3里对应马达功率-100,1023是前进最高速度,在EV3里对应+100。很简单,EV3只需将收到的raw值转换成-100到+100就可以了。
同样,坐标X值代表转向,0-1023对应乐高转向功率-100到+100,偏离0功率越大,转向越急:
说说我折腾DFR0182无线手柄遥控乐高ev3的过程图1

由于XY是动态值,无法按前面17个按键那样分配固定的值,需要在arduino里用union类型,把XY值转换成32位浮点数:
  1. union data
  2. {    int i;
  3.      unsigned char c[4];
  4.      float f;  
  5. };  
  6. union data x;
  7. union data y;
复制代码

把XY坐标值赋给x.f、y.f,这样就可以得到坐标值的XY值对应的32位浮点数x.c、y.c,再按二楼的方式拼装一个16进制字符数组,将16进制字符数组发送到EV3上不同名称的mailbox程序块,比如将X坐标的16进制字符数组,发送到EV3中名称为x的mailbox将Y坐标的16进制字符数组,发送到EV3中名称为y的mailbox。蓝牙数据包中,以x078、0x79代替上面的0x61。EV3收到XY坐标后,分别转换成转向功率和速度功率。
注意由于摇杆XY值分布不均匀,中间值并非1023/2,需要在EV3程序里分两段进行raw值到功率的转换。
未完待续。。。。。。

回复

使用道具 举报

luna  初级技神

发表于 2016-12-9 14:17:28

大写的赞~
回复

使用道具 举报

Ash  管理员

发表于 2016-12-9 17:31:51

坐等楼主更新
回复

使用道具 举报

iooops  中级技匠

发表于 2016-12-10 22:22:13

666
回复

使用道具 举报

taelons  中级技师
 楼主|

发表于 2016-12-11 08:51:06

我的EV3 usb口貌似有故障,暂时不能调试程序,摇杆的程序先贴出来。

  1. unsigned char hexLJoystickX[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x78,0x00,0x40,0x00,0x00,0x00,0x00,0x00};
  2. unsigned char hexLJoystickY[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x79,0x00,0x40,0x00,0x00,0x00,0x00,0x00};
  3. unsigned char hexRJoystickX[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x76,0x00,0x40,0x00,0x00,0x00,0x00,0x00};
  4. unsigned char hexRJoystickY[15] = {0x0d,0x00,0x00,0x00,0x81,0x9e,0x02,0x77,0x00,0x40,0x00,0x00,0x00,0x00,0x00};
  5. int RJoystickY = joystick[2];
  6. int RJoystickX = joystick[3];
  7. int LJoystickY = AnalogButton[0];
  8. int LJoystickX = AnalogButton[1];
  9. union data
  10. {
  11.      unsigned char c[4];
  12.      float f;  
  13. };  
  14. union data x;
  15. x.f = RJoystickY;
  16. hexRJoystickY[11] = x.c[0];
  17. hexRJoystickY[12] = x.c[1];
  18. hexRJoystickY[13] = x.c[2];
  19. hexRJoystickY[14] = x.c[3];
  20. Serial1.write(hexRJoystickY,15);
  21. x.f = RJoystickX;
  22. hexRJoystickX[11] = x.c[0];
  23. hexRJoystickX[12] = x.c[1];
  24. hexRJoystickX[13] = x.c[2];
  25. hexRJoystickX[14] = x.c[3];
  26. Serial1.write(hexRJoystickX,15);
  27. x.f = LJoystickY;
  28. hexLJoystickY[11] = x.c[0];
  29. hexLJoystickY[12] = x.c[1];
  30. hexLJoystickY[13] = x.c[2];
  31. hexLJoystickY[14] = x.c[3];
  32. Serial1.write(hexLJoystickY,15);
  33.   x.f = LJoystickX;
  34. hexLJoystickX[11] = x.c[0];
  35. hexLJoystickX[12] = x.c[1];
  36. hexLJoystickX[13] = x.c[2];
  37. hexLJoystickX[14] = x.c[3];
  38. Serial1.write(hexLJoystickX,15);
复制代码


然后在EV3上测试是否能收到摇杆值:
说说我折腾DFR0182无线手柄遥控乐高ev3的过程图1


运行后,在EV3液晶屏上显示左右摇杆数据:

LX:484
LY:505
RX:498
RY:497

拨动摇杆,显示随之变化。

未完待续。。。。。。。
回复

使用道具 举报

taelons  中级技师
 楼主|

发表于 2016-12-11 21:23:15

经过以上几步,EV3已能通过蓝牙接收手柄按键和摇杆数据,剩下的事情就简单了,在LEGO MINDSTORMS EV3 Home Edition中用程序块拖放编程,这里就不打算说了。

开头提到还入手了一块便宜DFR0008手柄,带四个按建和一个摇杆,足够用了,arduino程序相对简单,我就不重复了,只贴一张靓照。

说说我折腾DFR0182无线手柄遥控乐高ev3的过程图1


手柄插上蓝牙模块,再插在arduino上,arduino固定在乐高搭成的支架里,下面绑一块电池供电,非常牢固。
如果能找一个便宜的xbee 2.0蓝牙模块,全部加起来不超过200元,便宜实惠。:lol

等有时间再上传操控乐高EV3小车的视频。

接下来准备加一个红外模块,用手柄遥控乐高PF马达 :lol
回复

使用道具 举报

Rockets  NPC

发表于 2016-12-12 11:05:02

arduino的便利性就在这里,如果玩的溜,乐高都是给arduino打工的……
回复

使用道具 举报

Ricky  NPC

发表于 2016-12-14 11:35:47

这个帖子要赞一下。  把乐高并入到Arduino的世界。
回复

使用道具 举报

taelons  中级技师
 楼主|

发表于 2016-12-15 11:36:50

同样的方法可以实现用任天堂wii chuck手柄(俗称鸡腿)配合arduino操控,前天拿到dfrobot的wii 转接板,记录下鸡腿的摇杆XY轴坐标值:

Y轴(上下):25~131~228

X轴(左右):34~128~232

鸡腿还有一个三轴加速传感器,任意摇动鸡腿时(不是摇杆),XYZ三个坐标值会变,不过这种方式操控ev3有点别扭。

回复

使用道具 举报

Robotforyou  初级技师

发表于 2016-12-21 07:49:17

真心不错呀
回复

使用道具 举报

砖头墙  初级技师

发表于 2017-1-6 21:17:00

叼                       牛                       资料不错
回复

使用道具 举报

凌风清羽  中级技匠

发表于 2017-1-27 14:23:06

质量不错,就是略贵啊~~~~
回复

使用道具 举报

mauree  学徒

发表于 2017-3-16 16:58:07

可以设置和EV3的配对密码吗?连接稳定吗?
回复

使用道具 举报

Ember  见习技师

发表于 2018-8-19 15:39:42

xbee和ev3的通信速率设为多少?
回复

使用道具 举报

gada888  版主

发表于 2018-10-29 15:19:07

学习下
回复

使用道具 举报

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

本版积分规则

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

硬件清单

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

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

mail