树莓派 与 Xbox360手柄 基于pygame 的一次邂逅

49 篇文章 10 订阅
36 篇文章 1 订阅

前言

我一直都很想把游戏手柄作为树莓派的控制器,于是,我对飞智的八爪鱼下手了。。。
在这里插入图片描述
这手柄确实不错,可以连接多种设备,可以连接手机平板或电脑,连接电脑的时候支持Xbox360 模式

开始

硬件介绍:

  1. 树莓派3B+
  2. 飞智八爪鱼游戏手柄

一、安装软件

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/

在这里插入图片描述

这个event0js0 就是手柄设备,说明可以开始读取数据了

输入:

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

附链接:https://www.pygame.org/docs/ref/joystick.html

从官网的介绍以及示例代码中,并根据其一共有这几种事件状态:
在这里插入图片描述
于是就可以进行如下的编程了:


对于单手柄:

#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):
在这里插入图片描述

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诺亚方包

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值