ROS下使用wii游戏手柄控制移动机器人

wii游戏手柄基于蓝牙技术,可以与带蓝牙模块的ARM主板或PC连接。得益于ROS系统强大的生态圈,wii的驱动已经有现成的可以使用。挑选手柄时认准「原版」「不带加密」「没有陀螺仪」「右手柄」

源码编译

驱动源码包地址:joystick_drivers
将源码包下载到ROS的工作空间下:

1
2
$ cd ~/catkin_ws/src/
$ git clone https://github.com/ros-drivers/joystick_drivers.git

进入到源码目录,切换到分支indigo-devel,这个根据你自己使用的ROS版本而定:

1
2
$ cd ~/catkin_ws/src/joystick_drivers/
$ git checkout -b indigo-devel

编译:

1
2
$ cd ~/catkin_ws/
$ catkin_make

模拟测试

在笔记本或者运行ROS的系统中模拟测试一下:

1
$ roslaunch wiimote turtelsim_cpp.launch

同时按住手柄的12键直到四个蓝灯不闪烁时再松开,不出意外系统会提示已经配对成功,这时就可以使用手柄去控制turtle的移动了。

可能出现的错误

错误一:

g++版本不够高,因此需要使用较高版本的g++
查看g++版本:

1
$ g++ -v

查看系统是否有其他的g++版本:

1
$ ls -lh /usr/bin/g++*

输出:

此时系统有两个版本,而且使用的是低版本的4.6,将系统使用的g++版本切换到4.8
如果没有较高版本可以手动安装:

1
sudo apt-get install gcc-4.8 gcc-4.8-multilib g++-4.8 g++-4.8-multilib

设置gcc各版本的可选项:

1
2
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 46
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 48

配置当前使用哪个gcc

1
$ sudo update-alternatives --config gcc

此时会出现选项:

按提示输入相应的数字即可。

设置g++

1
2
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.6 46
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 48

配置g++

1
$ sudo update-alternatives --config g++

如果想删除某个可选项执行:

1
sudo update-alternatives --remove gcc /usr/bin/gcc-4.6

错误二:

没有安装libbluetooth-dev

1
$ sudo apt-get install libbluetooth-dev

错误三:


需要安装libcwiid库:

1
$ sudo apt-get install libcwiid-dev

控制移动底座

在实际使用时,需要在ROS系统下编写一个节点程序,该节点订阅wii蓝牙手柄发布的cmd_vel话题,并且从移动底座接收里程计信息,发布odometry话题,这样才能正确的进行后续的SLAM建图与导航。用户的移动底座可能使用不同的处理器实现,为了统一,我们采用串口与底层通信,也可以采用效率较高的CAN通信。关于这方面的开发思路可以参考站内文章详解stm32串口到底如何与ROS实现信息交互
节点部分的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//订阅cmd_vel话题的回调函数,用于显示速度以及角速度
void cmd_vel_callback(const geometry_msgs::Twist& cmd_vel){
ROS_INFO("I heard linear velocity: x-[%f],y-[%f],",cmd_vel.linear.x,cmd_vel.linear.y);
ROS_INFO("I heard angular velocity: [%f]",cmd_vel.angular.z);
std::cout << "Twist Received" << std::endl;
//将控制命令打包通过串口发送到移动底座
data_pack(cmd_vel);
}
//订阅cmd_vel话题
ros::Subscriber write_sub = nh.subscribe("cmd_vel",1000,cmd_vel_callback);
//发布里程计话题 odom
ros::Publisher read_pub = nh.advertise<nav_msgs::Odometry>("odom",1000);
/**********************************************************
* 数据打包,将获取的cmd_vel信息打包并通过串口发送
* ********************************************************/
void data_pack(const geometry_msgs::Twist& cmd_vel){
//unsigned char i;
float_union Vx,Vy,Ang_v;
Vx.fvalue = cmd_vel.linear.x;
Vy.fvalue = cmd_vel.linear.y;
Ang_v.fvalue = cmd_vel.angular.z;
memset(s_buffer,0,sizeof(s_buffer));
//数据打包
s_buffer[0] = 0xff;
s_buffer[1] = 0xff;
//Vx
s_buffer[2] = Vx.cvalue[0];
s_buffer[3] = Vx.cvalue[1];
s_buffer[4] = Vx.cvalue[2];
s_buffer[5] = Vx.cvalue[3];
//Vy
s_buffer[6] = Vy.cvalue[0];
s_buffer[7] = Vy.cvalue[1];
s_buffer[8] = Vy.cvalue[2];
s_buffer[9] = Vy.cvalue[3];
//Ang_v
s_buffer[10] = Ang_v.cvalue[0];
s_buffer[11] = Ang_v.cvalue[1];
s_buffer[12] = Ang_v.cvalue[2];
s_buffer[13] = Ang_v.cvalue[3];
//CRC
s_buffer[14] = s_buffer[2]^s_buffer[3]^s_buffer[4]^s_buffer[5]^s_buffer[6]^s_buffer[7]^
s_buffer[8]^s_buffer[9]^s_buffer[10]^s_buffer[11]^s_buffer[12]^s_buffer[13];
/*
for(i=0;i<15;i++){
ROS_INFO("0x%02x",s_buffer[i]);
}
*/
ser.write(s_buffer,sBUFFERSIZE);
}

使用时可以将这个节点加在一个launch文件中,比如自定义一个myserial.launch文件,放到launch目录下,添加以下内容:

运行时一个命令即可:

1
$ roslaunch myserial myserial.launch

此时按下蓝牙手柄,即可将命令发送至移动底座,从而控制机器人运动。

公众号后台回复「9527」获取全部源码。

参考

joystick_drivers_wiki

joystick_drivers_github

您的支持是我原创的动力