前言
我一直都很想把游戏手柄作为树莓派的控制器,于是,我对飞智的八爪鱼下手了。。。
这手柄确实不错,可以连接多种设备,可以连接手机平板或电脑,连接电脑的时候支持Xbox360 模式
开始
硬件介绍:
- 树莓派3B+
- 飞智八爪鱼游戏手柄
一、安装软件
sudo apt-get install joystick
sudo apt-get install xboxdrv
若下载失败,请尝试update 一下:
sudo apt-get update
sudo apt-get upgrade
二、开始测试
Ⅰ
把手柄调为无线360模式,与树莓派连接成功后可以开始测试了
首先我们看看树莓派有没有识别出手柄:
lsusb
可以看到已经识别出来了。
Ⅱ
接着我们进入/dev/input
目录查看一下设备文件:
ls /dev/input/
这个event0 和js0 就是手柄设备,说明可以开始读取数据了
Ⅲ
输入:
jstest /dev/input/js0
通过操控手柄,可以看到数据源源不断进行更新(手柄上面的按键和轴还是挺多的):
或者使用:
jstest --event /dev/input/js0
来查看关键几个数据:
三、控制代码
首先看看joystick 的头文件/usr/include/linux/joystick.h
:
里面有这么一个关键结构体:
time:时间
value:当前触发的按键/轴的值
type:指明是按键还是轴
number:按键/轴的标号
由于八爪鱼的按键相对微软的手柄来说,多了几个按键,所以多出来的按键我没有做相应的映射。
① C语言版:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/joystick.h>
#define XBOX_TYPE_BUTTON 0x01
#define XBOX_TYPE_AXIS 0x02
#define XBOX_BUTTON_A 0x00
#define XBOX_BUTTON_B 0x01
#define XBOX_BUTTON_X 0x02
#define XBOX_BUTTON_Y 0x03
#define XBOX_BUTTON_LB 0x04
#define XBOX_BUTTON_RB 0x05
#define XBOX_BUTTON_SELECT 0x06
#define XBOX_BUTTON_START 0x07
#define XBOX_BUTTON_HOME 0x08
#define XBOX_BUTTON_LO 0x09 /* 左摇杆按键 */
#define XBOX_BUTTON_RO 0x0a /* 右摇杆按键 */
#define XBOX_BUTTON_ON 0x01
#define XBOX_BUTTON_OFF 0x00
#define XBOX_AXIS_LX 0x00 /* 左摇杆X轴 */
#define XBOX_AXIS_LY 0x01 /* 左摇杆Y轴 */
#define XBOX_AXIS_RX 0x03 /* 右摇杆X轴 */
#define XBOX_AXIS_RY 0x04 /* 右摇杆Y轴 */
#define XBOX_AXIS_LT 0x02
#define XBOX_AXIS_RT 0x05
#define XBOX_AXIS_XX 0x06 /* 方向键X轴 */
#define XBOX_AXIS_YY 0x07 /* 方向键Y轴 */
#define XBOX_AXIS_VAL_UP -32767
#define XBOX_AXIS_VAL_DOWN 32767
#define XBOX_AXIS_VAL_LEFT -32767
#define XBOX_AXIS_VAL_RIGHT 32767
#define XBOX_AXIS_VAL_MIN -32767
#define XBOX_AXIS_VAL_MAX 32767
#define XBOX_AXIS_VAL_MID 0x00
/* 手柄面板上所有可控制按键/轴(包括一个时间量) */
typedef struct xbox_map
{
int time;
int a;
int b;
int x;
int y;
int lb;
int rb;
int select;
int start;
int home;
int lo;
int ro;
int lx;
int ly;
int rx;
int ry;
int lt;
int rt;
int xx;
int yy;
}xbox_map_t;
/* 获得手柄设备输入流 */
int xbox_open(char *file_name)
{
int xbox_fd;
xbox_fd = open(file_name, O_RDONLY);
if (xbox_fd < 0)
{
perror("open");
return -1;
}
return xbox_fd;
}
/* 读取手柄数据 */
int xbox_map_read(int xbox_fd, xbox_map_t *map)
{
int len, type, number, value;
struct js_event js;
len = read(xbox_fd, &js, sizeof(struct js_event));
if (len < 0)
{
perror("read");
return -1;
}
type = js.type;
number = js.number;
value = js.value;
map->time = js.time;
if (type == JS_EVENT_BUTTON)
{
switch (number)
{
case XBOX_BUTTON_A:
map->a = value;
break;
case XBOX_BUTTON_B:
map->b = value;
break;
case XBOX_BUTTON_X:
map->x = value;
break;
case XBOX_BUTTON_Y:
map->y = value;
break;
case XBOX_BUTTON_LB:
map->lb = value;
break;
case XBOX_BUTTON_RB:
map->rb = value;
break;
case XBOX_BUTTON_SELECT:
map->select = value;
break;
case XBOX_BUTTON_START:
map->start = value;
break;
case XBOX_BUTTON_HOME:
map->home = value;
break;
case XBOX_BUTTON_LO:
map->lo = value;
break;
case XBOX_BUTTON_RO:
map->ro = value;
break;
default:
break;
}
}
else if (type == JS_EVENT_AXIS)
{
switch(number)
{
case XBOX_AXIS_LX:
map->lx = value;
break;
case XBOX_AXIS_LY:
map->ly = value;
break;
case XBOX_AXIS_RX:
map->rx = value;
break;
case XBOX_AXIS_RY:
map->ry = value;
break;
case XBOX_AXIS_LT:
map->lt = value;
break;
case XBOX_AXIS_RT:
map->rt = value;
break;
case XBOX_AXIS_XX:
map->xx = value;
break;
case XBOX_AXIS_YY:
map->yy = value;
break;
default:
break;
}
}
else
{
/* 若出错 */
}
return len;
}
/* 关闭手柄设备输入流 */
void xbox_close(int xbox_fd)
{
close(xbox_fd);
return;
}
int main(void)
{
int xbox_fd ;
xbox_map_t map;
int len, type;
int axis_value, button_value;
int number_of_axis, number_of_buttons ;
memset(&map, 0, sizeof(xbox_map_t));
xbox_fd = xbox_open("/dev/input/js0");
if(xbox_fd < 0)
{
return -1;
}
while(1)
{
len = xbox_map_read(xbox_fd, &map);
if (len < 0)
{
usleep(10*1000);
continue;
}
printf("\rTime:%8d A:%d B:%d X:%d Y:%d LB:%d RB:%d select:%d start:%d lo:%d ro:%d XX:%-6d YY:%-6d LX:%-6d LY:%-6d RX:%-6d RY:%-6d LT:%-6d RT:%-6d",
map.time, map.a, map.b, map.x, map.y, map.lb, map.rb, map.select, map.start, map.lo, map.ro,
map.xx, map.yy, map.lx, map.ly, map.rx, map.ry, map.lt, map.rt);
fflush(stdout);
}
xbox_close(xbox_fd);
return 0;
}
② Python 版
用python,就简单了,我们可以直接引入pygame
库
从官网的介绍以及示例代码中,并根据其一共有这几种事件状态:
于是就可以进行如下的编程了:
对于单手柄:
#coding:utf-8
import pygame
# 模块初始化
pygame.init()
pygame.joystick.init()
# 若只连接了一个手柄,此处带入的参数一般都是0
joystick = pygame.joystick.Joystick(0)
# 手柄对象初始化
joystick.init()
done = False
clock = pygame.time.Clock()
while not done:
for event_ in pygame.event.get():
# 退出事件
if event_.type == pygame.QUIT:
done = True
# 按键按下或弹起事件
elif event_.type == pygame.JOYBUTTONDOWN or event_.type == pygame.JOYBUTTONUP:
buttons = joystick.get_numbuttons()
# 获取所有按键状态信息
for i in range(buttons):
button = joystick.get_button(i)
print("button " + str(i) +": " + str(button))
# 轴转动事件
elif event_.type == pygame.JOYAXISMOTION:
axes = joystick.get_numaxes()
# 获取所有轴状态信息
for i in range(axes):
axis = joystick.get_axis(i)
print("axis " + str(i) +": " + str(axis))
# 方向键改变事件
elif event_.type == pygame.JOYHATMOTION:
hats = joystick.get_numhats()
# 获取所有方向键状态信息
for i in range(hats):
hat = joystick.get_hat(i)
print("hat " + str(i) +": " + str(hat))
joystick_count = pygame.joystick.get_count()
pygame.quit()
若连接多手柄(需要遍历每一个手柄):
#coding:utf-8
import pygame
# 模块初始化
pygame.init()
pygame.joystick.init()
done = False
clock = pygame.time.Clock()
joystick_count = pygame.joystick.get_count()
while not done:
# 遍历每一个手柄
for i in range(joystick_count):
joystick = pygame.joystick.Joystick(i)
joystick.init()
# Get the name from the OS for the controller/joystick.
name = joystick.get_name()
for event_ in pygame.event.get():
print(name)
# 退出事件
if event_.type == pygame.QUIT:
done = True
# 按键按下或弹起事件
elif event_.type == pygame.JOYBUTTONDOWN or event_.type == pygame.JOYBUTTONUP:
buttons = joystick.get_numbuttons()
# 获取所有按键状态信息
for i in range(buttons):
button = joystick.get_button(i)
print("button " + str(i) +": " + str(button))
# 轴转动事件
elif event_.type == pygame.JOYAXISMOTION:
axes = joystick.get_numaxes()
# 获取所有轴状态信息
for i in range(axes):
axis = joystick.get_axis(i)
print("axis " + str(i) +": " + str(axis))
# 方向键改变事件
elif event_.type == pygame.JOYHATMOTION:
hats = joystick.get_numhats()
# 获取所有方向键状态信息
for i in range(hats):
hat = joystick.get_hat(i)
print("hat " + str(i) +": " + str(hat))
pygame.quit()
最后
若使用C语言版的代码:
在树莓派上面把这个c文件编译成可执行文件就可以直接运行了:
编译(我选择把Xbox_Joystick.c
编译成名为Xbox_Joystick
的可执行文件):
gcc Xbox_Joystick.c -o Xbox_Joystick
运行:
sudo ./Xbox_Joystick
结果(C):
(Python):