树莓派 使用xbox360手柄

开始

树莓派可以控制很多硬件,最常见的就是做个小车什么的了。看了网上很多都是在网页上点来点去控制,感觉有点麻烦,如果能用手柄就好了。

想到躺在箱子里玩《巫师3》时买的北通阿修罗手柄,通关之后就再也没用过,如果可以用树莓派控制的话,那想想都觉得太cooooool了!

既然想到了,自然马上在小pi上搞起。


准备工作

1.树莓派3B,系统是Raspbian。性能强劲,自带无线网卡非常爽,省去了各种连线。

2.北通阿修罗TE无线手柄。支持xbox360模式,功能强大。




依赖软件

sudo apt-get install joystick
sudo apt-get isntall xboxdrv

连接手柄

我的Raspbian上,貌似已经加载了相关模块,所以无需再配置内核。

将手柄usb头查到小pi上,直接就可以驱动起来了,查看手柄的px灯同时亮,说明已经连接上了,默认是xbox360模式。


测试手柄

连接上手柄之后,可以在系统中查看一些信息,来确认手柄是否可以正常工作。

在shell下输入lsusb,可以看到,已经识别出来手柄 。

lsusb

Bus 001 Device 009: ID 045e:028e Microsoft Corp. Xbox360 Controller
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub


进入/dev/input目录,查看多出了event0和js0两个设备文件,这两个就是手柄设备,说明已经可以开始读取数据了。

ls /dev/input/

by-id  by-path  event0  js0  mice


在shell下输入jstest ,然后操作手柄,可以看到,数据已经读取成功了,稍微核对一下,按键映射应该都是正确的。

jstest /dev/input/js0

Axes:  0: -2194  1:   644  2:-32767  3: -3226  4:     0  5:-32767  6:     0  7:     0 Buttons:  0:off  1:off  2:off  3:off  4:off  5:off  6:off  7:off  8:off


也可以用下面这个命令,可以查看几个关键数值。

jstest --event /dev/input/js0 

Event: type 2, time 45840650, number 4, value -2711


验证到这里,手柄已经可以在我们的小pi上使用,手柄的输出也可以正常读取了。那剩下的就是怎么在代码中将手柄为我们所用了!!胜利就在彼岸!


代码部分

joystick的头文件在/usr/include/linux/joystick.h 这个位置,并且只有一个头文件可以使用,里面定义了一些宏和结构,我们也只需要使用这个头文件就可以了。

最重要的结构是下面这个,手柄输出的重要数据也就是这几个数值,在jstest测试时,可以看到手柄输出的详细值。

struct js_event {
    __u32 time; /* event timestamp in milliseconds */
    __s16 value; /* value */
    __u8 type; /* event type */
    __u8 number; /* axis/button number */
};

type:1为按键,2为轴向

number:按键名字

value:实际的值。

time:一个时间值。


以下是代码:实现了一个类似jstest的功能,我额外将xbox360的按键对照number值做了映射,方便以后直接使用。

#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_START   0x06
#define XBOX_BUTTON_BACK    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     start;
    int     back;
    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_START:
                map->start = value;
                break;

            case XBOX_BUTTON_BACK:
                map->back = 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
    {
        /* Init do nothing */
    }

    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 start:%d back:%d home:%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.start, map.back, map.home, 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;
}


实现的功能如下:用手柄测试一下,一切OK,到这我的小pi就可以用手柄控制了!

A:1 B:0 X:1 Y:0 LB:0 RB:0 start:1 back:1 home:0 LO:0 RO:0 XX:0      YY:0      LX:-388   LY:386    RX:-130   RY:1418   LT:0      RT:32767     


总结

xbox360手柄功能非常强大,wifi控制距离远,信号强,控制稳定,以后再做什么东西都可以使用手柄控制,而且是无线控制,想想就觉得充满各种可能性!


过程中查阅了大量的资料,走了很多弯路,最后实现确是很简单的。百度查到的东西都不是很靠谱,但还是要靠百度查,最后总结了很多论坛的资料找到了解决方法。

树莓派可以实现,那其他linux系统应该也是一样的道理,这里做一下记录留着自己以后方便研究学习了。






  • 9
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: Qt对Xbox手柄编程提供了丰富的支持和功能。通过Qt的输入处理模块,我们可以轻松地连接、配置和读取Xbox手柄的输入信号。首先,我们需要在Qt项目中添加相应的模块和库文件来处理游戏手柄输入信号。 Qt提供了一个名为QGamepad的类,它可以用于与游戏手柄进行交互。我们可以通过实例化QGamepad类并使用它的函数来读取手柄的输入状态,例如摇杆、按键等。与此同时,Qt还提供了一些信号和槽以实现手柄输入的实时处理。 为了使用Xbox手柄,我们需要将其连接到计算机。Qt可以与大多数手柄连接,包括Xbox手柄,只需简单的配置即可。一旦手柄连接成功,我们可以通过QGamepad类的函数读取手柄的输入状态。 在Qt中编程Xbox手柄,我们可以定义槽函数来处理手柄的不同输入信号。例如,我们可以为按键按下事件定义一个槽函数,以响应用户的输入。我们还可以使用摇杆的位置信息来实现游戏角色的移动。这些槽函数可以根据手柄输入的不同状态来触发相应的操作。 总之,Qt对Xbox手柄编程提供了简单且强大的功能。它可以帮助我们轻松地连接和读取Xbox手柄的输入信号,并实时处理这些信号以实现不同的交互操作。无论是游戏开发还是其他需要手柄输入的应用程序,Qt都是一个理想的选择。 ### 回答2: Qt是一种功能强大的跨平台开发框架,可以用于开发各种应用程序和界面。对于编程来说,Qt提供了一些功能来实现与Xbox手柄的交互。 首先,Qt提供了一个名为QGamepad的类,可以用来读取和处理手柄输入。使用QGamepad类,开发者可以轻松地获取手柄的按键和摇杆状态,并相应地对其进行处理。比如,可以检测手柄的按键按下和松开事件,并在相应的回调函数中执行相应的操作。 另外,Qt还提供了一些内置的图形界面组件,可以用于显示手柄输入的状态。通过使用这些组件,可以在应用程序中显示手柄的按键状态、摇杆位置等信息,使用户能够直观地了解手柄的状态。 除了基本的手柄输入处理外,Qt还提供了其他功能来增强与手柄的交互。比如,可以利用Qt的信号与槽机制,实现在手柄按键按下时执行指定的动作。同时,还可以通过Qt的多线程支持,将手柄输入的处理与应用程序其他部分的逻辑分离,提高应用程序的响应性能。 总的来说,Qt对Xbox手柄编程提供了丰富的功能和工具,使开发者能够轻松地实现与手柄的交互。通过使用Qt的各种功能,开发者可以编写出功能强大、易于使用的应用程序,提供丰富的手柄操作体验。 ### 回答3: Qt是一种功能强大的跨平台开发框架,可以用于开发各种应用程序,包括对Xbox手柄的编程。Qt提供了一个名为Gamepad API的模块,用于处理游戏手柄的输入。 首先,我们需要确保Qt版本支持Gamepad API。Qt 5.7及以上版本自带了此模块,可以直接使用。如果你使用的是较早版本的Qt,你需要通过安装qtgamepad模块来获取Gamepad API。 编程前,我们需要在.pro文件中添加gamepad模块的依赖。在.pro文件中添加以下代码: QT += gamepad 在源代码中,我们需要包含QGamepad头文件: #include <QGamepad> 然后,我们可以创建一个QGamepad对象来处理游戏手柄的输入: QGamepad gamepad; 创建QGamepad对象后,我们可以使用其成员函数获取手柄输入的状态,如按钮状态和摇杆状态。例如,可以使用以下代码检查A按钮是否按下: if(gamepad.buttonA()) { // 处理按下A按钮的操作 } 可以使用以下代码获取左摇杆的X和Y轴的值: double leftX = gamepad.axisLeftX(); double leftY = gamepad.axisLeftY(); 通过检测这些值,我们可以实现不同的游戏操作,例如移动角色或改变视角。 另外,我们还可以使用QGamepadManager类来监测和管理系统中连接的游戏手柄的状态。我们可以使用以下代码获取连接的手柄数量: int gamepadCount = QGamepadManager::instance()->connectedGamepads(); 使用以上方法,我们可以在Qt应用程序中轻松地处理Xbox手柄的输入。希望这些信息对你有所帮助!
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值