在ubuntu1604/2004环境下实现xbox one无线手柄遥+usb无线适配器控机器人运动。
sudo apt install xboxdrv
sudo apt install joystick
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
Xow是一个非官方的Linux版本Xbox one手柄无线适配器驱动,其底层基于libusb进行工作,通过Wifi与游戏手柄进行连接,其使用MT76xx的Wifi chip;
git clonet https://github.com/medusalix/xow.git
audo apt install curl libusb-1.0-0-dev cabextract
cd xow
make BUILD=RELEASE
sudo make install
sudo xow-get-firmware.sh
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
执行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
先运行./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 后,操作手柄操作杆查看数据是否有变化。
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;
}