xbox one无线手柄在ubuntu下的对接开发

在ubuntu1604/2004环境下实现xbox one无线手柄遥+usb无线适配器控机器人运动。

1. 安装xboxdrv和joystick

sudo apt install xboxdrv
sudo apt install joystick

2. 将usb无线接收器插入,查看设备信息

cat /proc/bus/input/devices
输出如下信息说明系统已经识别到了xbox的接收器

I: Bus=0003 Vendor=045e Product=0719 Version=0100
N: Name="Xbox 360 Wireless Receiver"
P: Phys=
S: Sysfs=/devices/virtual/input/input28
U: Uniq=
H: Handlers=event28 js3 
B: PROP=0
B: EV=b
B: KEY=f 0 0 0 0 0 0 7fdb000000000000 0 0 0 0
B: ABS=1b

3. 编译xow

Xow是一个非官方的Linux版本Xbox one手柄无线适配器驱动,其底层基于libusb进行工作,通过Wifi与游戏手柄进行连接,其使用MT76xx的Wifi chip;

3.1 下载xow源码

git clonet https://github.com/medusalix/xow.git

3.2 安装依赖

audo apt install curl libusb-1.0-0-dev cabextract

3.3 编译

cd xow
make BUILD=RELEASE
sudo make install

3.4 Download the firmware for the wireless dongle:

sudo xow-get-firmware.sh

3.5 运行xow

sudo ./xow
[sudo] password for sar:
2022-05-20 11:18:43 INFO - xow v0.5-36-gd335d60 ©Severin v. W.
2022-05-20 11:18:43 INFO - Waiting for device…
2022-05-20 11:18:43 INFO - Wireless address: 62:45:bd:05:8b:85
2022-05-20 11:18:43 INFO - Dongle initialized
2022-05-20 11:18:49 INFO - Controller ‘1’ connected
2022-05-20 11:18:49 INFO - Device announced, product id: 02d1
2022-05-20 11:18:49 INFO - Battery level: full
2022-05-20 11:28:10 INFO - Controller ‘1’ disconnected
2022-05-20 11:33:12 INFO - Controller ‘1’ connected
2022-05-20 11:33:12 INFO - Device announced, product id: 02d1

3.6 编译错误解决:

执行make BUILD=RELEASE报错:找不到uinput_setup、uinput_abs_setup的定义
报错原因:linux内核版本太低,xow不支持UINPUT_VERSION 5以下版本;
解决方法:从高版本的ubuntu中拷贝/usr/include/linux/uinput.h替换当前系统下的/usr/include/linux/uinput.h

xow驱动分析可以参考这篇博客:https://blog.csdn.net/YingbinLi/article/details/123268015

4. xbox手柄测试

先运行./xow,在按下xbox one手柄最前端的带x标识的圆形按键,按下按键后按键灯点亮,开始慢闪,配对成功后,按键灯常亮;
打开了一个linux终端,运行:

sudo jstest /dev/input/js4 
Driver version is 2.1.0.
Joystick (Xbox One Wireless Controller) has 8 axes (X, Y, Z, Rx, Ry, Rz, Hat0X, Hat0Y)
and 11 buttons (BtnA, BtnB, BtnX, BtnY, BtnTL, BtnTR, BtnSelect, BtnStart, BtnMode, BtnThumbL, BtnThumbR).
Testing ... (interrupt to exit)
Axes:  0:     0  1:     0  2:-32767  3:     0  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  9:off 10:off

注意:在/dev/input下可能会生成js0, js1, js2, js3, js4 5个文件,可以分别使用jstest 测试一下,运行sudo jstest /dev/input/js4 后,操作手柄操作杆查看数据是否有变化。

5. xbox手柄操作数据接收与解析

joystick_xbox.h

#include 
#include 
#include 

class JoystickXBox
{
public:
    JoystickXBox(const std::string &dev_name);
    ~JoystickXBox();
    bool Open();
    void Close();
    bool Read(struct js_event &js);
    unsigned char GetAxes()
    {
        return axes_;
    }
    unsigned char GetButtons()
    {
        return buttons_;
    }
    int GetFd()
    {
   		return fd_;
    }
    void PrintData();
    void ProcessData(const struct js_event &js);

private:
    bool debug_ = false;
    int fd_ = -1;
    std::string dev_name_ = "";
    int version_ = 0x000800;
    char name_[512] = "Unkown";
    unsigned char axes_ = 2;
    unsigned char buttons_ = 2;
    int *axis_ = nullptr;
    char *button_ = nullptr;
};

joystick_xbox.cpp

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "joystick_xbox.h"

JoystickXBox::JoystickXBox(const std::string &dev_name) : fd_(-1),dev_name_(dev_name)
{
}

JoystickXBox::~JoystickXBox()
{
    if (axis_)
    {
        delete axis_;
        axis_ = nullptr;
    }

    if (button_)
    {
        delete button_;
        button_ = nullptr;
    }
}

bool JoystickXBox::Open()
{
    int fd = -1;
    if (dev_name_.length() == 0)
    {
        return false;
    }
    // O_NONBLOCK open
    fd = open(dev_name_.c_str(), O_RDONLY | O_NONBLOCK);
    if (fd < 0)
    {
        fd_ = -1;
        printf("JoystickXBox open %s error, %d(%s)\n", dev_name_.c_str(), errno, strerror(errno));
        return false;
    }

    ioctl(fd, JSIOCGVERSION, &version_);
    ioctl(fd, JSIOCGAXES, &axes_);
    ioctl(fd, JSIOCGBUTTONS, &buttons_);
    ioctl(fd, JSIOCGNAME(512), name_);
    printf("JoystickXBox Driver version is %d.%d.%d.\n", version_ >> 16, (version_ >> 8) & 0xff, version_ & 0xff);
    printf("JoystickXBox (%s) has %d axes and %d buttons\n", name_, axes_, buttons_);
    fd_ = fd;
    axis_ = (int *)calloc(axes_, sizeof(int));
    button_ = (char *)calloc(buttons_, sizeof(char));

    return true;
}

void JoystickXBox::Close()
{
    if (fd_ > 0)
    {
        close(fd_);
        fd_ = -1;
    }
}

bool JoystickXBox::Read(struct js_event &js)
{
    int len = -1;
    if (fd_ < 0)
    {
        return false;
    }

    memset(&js, 0, sizeof(js));
    len = read(fd_, &js, sizeof(struct js_event));
    if (len != sizeof(struct js_event))
    {
        printf("JoystickXBox: error reading, %d(%s)\n", errno, strerror(errno));
        return false;
    }

    return true;
}

void JoystickXBox::ProcessData(const struct js_event &js)
{
    JoystickFrame frame;
    int joystick_angular_value = 0;
    int joystick_linear_value = 0;
    int button_angular_value = 0;
    int button_linear_value = 0;

    switch (js.type & ~JS_EVENT_INIT)
    {
    case JS_EVENT_BUTTON:
        button_[js.number] = js.value;
        break;
    case JS_EVENT_AXIS:
        axis_[js.number] = js.value;
        break;
    }
    if (debug_)
    {
        PrintData();
    }
}

void JoystickXBox::PrintData()
{
    if (axes_ && axis_)
    {
        printf("Axes: ");
        for (int i = 0; i < axes_; i++)
        {
            printf("%2d:%6d ", i, axis_[i]);
        }
    }
    if (buttons_ && button_)
    {
        printf("Buttons: ");
        for (int i = 0; i < buttons_; i++)
        {
            printf("%2d:%s ", i, button_[i] ? "on " : "off");
        }
    }
    printf("\n");
    fflush(stdout);
}

int main()
{
	bool ret = false;
    int err_cnt = 0;
    fd_set rfds;
    timeval timeout;
    struct js_event js;
    int fd = -1;
    std::string dev_name = "/dev/input/js4";
    std::unique_ptr<JoystickXBox> joystick_xbox = std::make_unique<JoystickXBox>(dev_name);

    ret = joystick_xbox->Open();
    if (!ret)
    {
        return -1;
    }
    fd = joystick_xbox->GetFd();

    while (1)
    {
        usleep(100);
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        FD_ZERO(&rfds);
        FD_SET(fd, &rfds);
        int ret = select(fd + 1, &rfds, NULL, NULL, &timeout);
        if (ret > 0 && FD_ISSET(fd, &rfds))
        {
            ret = joystick_xbox->Read(js);
            if (ret)
            {
                joystick_xbox->ProcessData(js);
            }
        }
    }

    joystick_xbox->Close();

    return 0;	
}

你可能感兴趣的:(ROS,ubuntu,linux)