首页 - 文章教程 - 正文

1.控制手柄的硬件及固件代码介绍

0x00 控制手柄简介

目前在ROS中可以使用的游戏控制手柄很多,例如罗技F710无线蓝牙手柄、北通USB手柄、Sony PS3手柄、xbox360的游戏手柄等,现在都可以在ROS下使用了。我们可以利用手柄上的摇杆可以开发出很多功能,例如控制ROS小车的移动,这样我们就不用使用键盘遥控程序teleop_twist_keyboard了。下面让我们来看看各个控制手柄的样子吧:

1540794280747397.png

1540794299582984.png

1540794737116487.jpeg

timg (1).jpeg

通过这几张图片我们就能了解现在的手柄造型都差不多,基本上就是摇杆加按钮。这些手柄的价格还都不便宜,大概要100-200多块左右。如果我们要设计一款ROS下专用的控制手柄的话,应该也不会很难。因为现在arduino和按钮、摇杆、旋钮什么的都很容易买到。下面我们就自己动手来做一个简单的ROS下可以使用的控制手柄吧!


0x01 硬件模块介绍

对于该控制手柄的主控板,我们准备选用arduino。因为开发比较简单,而且要外接的元器件也比较少,所以选用arduino就很合适了。这里的arduino主控板我选用DFRobot的beetle,如下图所示:

1540800124280625.png

Beetle是Arduino Leonardo的极简版本,具备和Leonardo类似的强大应用能力,特别适于一次性的DIY项目制作和可穿戴电子应用。Beetle与Arduino Leonardo兼容,在使用Arduino IDE开发环境时注意选择“Arduino Leonardo”。下面我们来详细查看该板的IO口介绍:

Screenshot from 2018-10-29 16:10:01.png

下面来介绍自锁按钮,就是按下去不会自动弹起来的按钮,需要再次按一下才行,这样我们就可以把它作为一个开关来使用。该按钮是一个数字型接口的模块,在使用时需要将其信号线与arduino的数字IO口连接才行。该自锁按钮的图片如下:

Screenshot from 2018-10-29 16:39:50.png

下面来看一下模拟角度传感器,其实有点像电位器的感觉。当在旋转按钮的时候,可以获得旋转的角度。我们可以利用这个功能来控制小车移动的速度,就跟摩托车的油门差不多。该模块的输出是模拟信号,因此需要将其接在arduino的模拟IO口上,该模块图片如下:

Screenshot from 2018-10-29 16:42:58.png

最后我们来看一下摇杆模块,该模块有5根引脚,如下图所示:

1540805192522914.jpg

最后,让我们来看一下所有的模块:

1540805620839427.jpg


0x02 电路连接图

在介绍完制作控制手柄所需的所有模块后,我们就需要将自锁按钮、摇杆、模拟角度传感器和Beetle主控板的IO口连接起来。在前面已经介绍过每个模块的输出是模拟还是数字的了,所以我们只需要根据需要将引脚焊接在Beetle上即可。下面我们来规划下电路图,如下图所示:

1540808218434696.png

根据该设计电路连接图,我们来实际动手焊接,下面是焊接好的实物图,如下所示:

1540808317722383.jpg

1540808356796873.jpg


0x03 编写arduino代码

在根据电路图焊接好各模块后,我们就可以来使用Arduino IDE开发程序了。下面先来查看完整的Arduino代码,后面再来对代码进行下解析说明:

/********************************************************************
   Copyright: 2016-2018 ROS小课堂 www.corvin.cn
   Author: corvin
   Description:
     ROS控制手柄的arduino部分代码,主要就是获取各传感器信息.将其组装好后通过串口
     发送给上位机部分的ROS python代码来解析.
   History:
     20181024:initial this code.
     20181030:修改为发送各模块的原始数据到上位机,数据解析处理在上位机进行,尽可能
         保持该固件代码结构简单,易于调试维护.
*********************************************************************/

#define BAUD_RATE     57600
#define ROTATE_RANGE  100
#define SEND_RATE     10

/*
   define sensors pin
*/
int self_lock_pin = 11;
int handle_x_pin  = A2;
int handle_y_pin  = A1;
int handle_z_pin  = 10;
int rotation_pin  = A0;


void setup() {
  pinMode(self_lock_pin, INPUT);
  pinMode(rotation_pin,  INPUT);
  pinMode(handle_z_pin,  INPUT_PULLUP);

  Serial.begin(BAUD_RATE);
}

void loop() {
  int lock_status    = digitalRead(self_lock_pin);
  int rotation_value = analogRead(rotation_pin);
  int rotate_percent = map(rotation_value, 1023, 0, 0, ROTATE_RANGE);

  //turn left or right
  int handle_x = analogRead(handle_x_pin);

  //move forward or back
  int handle_y = analogRead(handle_y_pin);

  //click handle
  int handle_z = digitalRead(handle_z_pin);

  //output all value by serial port
  outPutData(lock_status, handle_x, handle_y, handle_z, rotate_percent);
  delay(1000 / SEND_RATE);
}

/*
   formate output data
*/
void outPutData(int lock_status, int handle_x, int handle_y, int handle_z, int rotate_percent)
{
  Serial.print(lock_status, DEC);
  Serial.print(" ");
  Serial.print(handle_x, DEC);
  Serial.print(" ");
  Serial.print(handle_y, DEC);
  Serial.print(" ");
  Serial.print(handle_z, DEC);
  Serial.print(" ");
  Serial.println(rotate_percent, DEC);
}

下面来对上述代码进行下解析:

(1)首先最开始的三个宏定义,先是定义了串口通讯的波特率为57600。然后定义了模拟角度传感器旋转的一个范围,由于该模块的安装方式导致它在最左边位置默认输出是1023,最右边是0。但是我们希望在最左边为0,最右边为一个最大值,但是不想设置为1023这么多了,这里就定义100。意思是说把1023->0给转换成0->100了,即平均分成100份了。最后一个宏定义是定义了数据的发送频率,设置为10,表明发送频率是10Hz,每100ms通过串口发送一次数据。

(2)下面初始化了各模块连接的引脚,首先是自锁按钮,由于其输出为数字型,所以连接在11引脚。下面三个分别是摇杆的x轴,y轴,z轴的连接引脚,其中x轴,y轴这两个是模拟输出,所以分别接在A2,A1引脚上。z轴是数字型输出,接在10引脚上。最后一个是模拟角度传感器,模拟输出,所以接在A0引脚上。

(3)setup函数就是初始化函数,这里就是配置了arduino的引脚模式和串口通讯的波特率。这里需要注意对于摇杆的z轴引脚,该数字型引脚的配置需要配置成INPUT_PULLUP上拉,不然电平不稳,输出的数据不稳定。

(4)loop函数是一直不断循环执行的函数。在该函数中,我们就需要不断的读取各模块的输出数据,然后将数据整合成我们指定的协议类型,再通过串口将数据帧输出即可。我们这里定义的数据帧格式非常的简单,省略了那些数据帧校验,不包含帧头,帧序号,校验和,帧尾什么的。因为我们这里的数据传输不必保证数据的完整性,因为应用场景没必要保证那么高的可靠性。但是如果是一些对数据的完整性、稳定性要求较高的场景,我们就需要设计较为完整的数据帧格式来传输数据了。这里我们定义的数据帧格式如下:

1.png

(5)最后的outPutData函数就是我们用来格式化我们数据帧并且发送的函数。可以看到我们在发送前四个数据时,使用的是Serial.print()函数,这样就不会有换行。在发送最后一个数据rotate_percent时,我们使用的是Serial.println()函数,这样我们就能保证在发送完这五个数据后发送一个换行符,表明一帧数据发送完毕。这样就方便我们上位机代码在解析数据时,可以区分什么时候是一帧完整的数据。可以设想一下,如果我们最后也不加换行的话,那么所有的数据都是在一行上,我们发送的数据帧又没有定义帧头、帧尾,那么在上位机收到数据后,就无法截取出各模块的数据了。


0x04 运行测试

在编写好代码,下面我们就可以将代码上传至beetle中了。在这里需要注意,在Arduino IDE中需要选择Leonardo板。当使用microUSB线连接到电脑上时,选择如下:

1540869171763850.png

1540869209435105.png

然后将该代码上传至beetle板中,接下来我们就可以通过IDE提供的"串口监视器"来查看输出的数据是否正确了。首先来测试一下自锁按钮,摇杆的x轴测试。当我们按下自锁按钮时,可以发现第一个数字变为1,当弹起来后又变为0。当往左边推摇杆时,发现第二个数字变为0,推到最右边为1023。如下图所示:

1.gif

接下来测试摇杆的前后,当往最下面推时,可以发现第三个数字变为0。当往前推动时,数字又变为1023。当往下按摇杆时,可以发现第4个数字变为0。具体如下图所示:

2.gif

最后来测试一下模拟角度传感器的输出,可以发现当扭动到最左边时,串口输出的第五个值为0。当扭动到最右边时,值逐渐变为100。如下图所示:

3.gif

如果上面查看串口数据不够直观的话,我们就可以利用IDE自带的“串口绘图器”来将数据绘制出来,这样查看更为直观。如下图所示,可以查看摇杆左右移动和上下移动时的数据图效果:

4.gif

最后来测试下旋钮的数据图,当往右边逐渐旋转时,发现右下角的图也逐渐升高。当我们稍微往左边旋转时,图也跟着下降。具体效果如下图所示:

5.gif

当现在我们已经测试了手柄的各模块,它们可以正常工作,数据发送正常。接下来我们就可以编写解析该数据帧的驱动程序了,在驱动程序中,我们就可以将数据重新封装成ROS下的Twist消息,这样就可以控制小车的移动了。


0x05 Reference

[1].ROS Wiki上joystick的主页. http://wiki.ros.org/joy

[2].ROS Wiki上ps3joy的主页. http://wiki.ros.org/ps3joy

[3].DFRobot设计的微型Arduino控制器Beetle. http://www.dfrobot.com.cn/goods-839.html

[4].Beetle控制器的产品资料库.

http://wiki.dfrobot.com.cn/index.php/(SKU:DFR0282)Beetle_%E6%8E%A7%E5%88%B6%E5%99%A8

[5].DFRobot设计的模拟角度传感器. http://www.dfrobot.com.cn/goods-108.html

[6].DFRobot设计的自锁按钮模块. http://www.dfrobot.com.cn/goods-1274.html

[7].自锁按钮的产品资料库. http://wiki.dfrobot.com.cn/index.php?title=(SKU:DFR0423)%E8%87%AA%E9%94%81%E6%8C%89%E9%92%AE%E6%A8%A1%E5%9D%97_Self-Locking_Switch

[8].淘宝上双轴按钮摇杆传感器. https://detail.tmall.com/item.htm?spm=a230r.1.14.6.4b8d777dVK7LEd&id=529728518075&cm_id=140105335569ed55e27b&abbucket=10

[9].Arduino摇杆程序开发. https://blog.csdn.net/sdlgq/article/details/50386197?utm_source=blogxgwz0


0x06 Feedback

大家在按照教程操作过程中有任何问题,可以直接在文章末尾给我留言,或者关注ROS小课堂的官方微信公众号,在公众号中给我发消息反馈问题也行。我基本上每天都会处理公众号中的留言!当然如果你要是顺便给ROS小课堂打个赏,我也会感激不尽的,打赏30块还会被邀请进ROS小课堂的微信群,与更多志同道合的小伙伴一起学习和交流!

1516851765432601.jpg

发表评论