文章目录
一. 简介
Logitech F310
游戏手柄是Logitech公司生产的双模拟摇杆,动式方向按键游戏手柄。
游戏手柄的作用不只是可以用来玩游戏,还可以用于做一些机器人仿真,就比如最近MIT开源的Mini Cheetah
四足机器人,其中机器人仿真部分用的控制器就是罗技F310游戏手柄。但是其采用的方法是直接调用QT
中的QtGamepad库
操作手柄,对于没有安装QT的人没办法直接调用,为此我写了一份罗技F310的通用驱动,驱动也兼容F710,其他型号的游戏手柄还未测试。
代码目前只支持Linux
,可以实现读取所有遥感和按键的数值,最终效果如下:
驱动手柄并将各个按键值打印出来:
使用QT将功能做UI显示:
二. 源码
1. 头文件
Logitech_controller.h :
/*========================= Logitech_controller ==========================*/
/* @file Logitech_controller.h
* @author lindongdong
* @brief 详情请看Logitech_controller.cpp
*/
/*========================= Logitech_controller ==========================*/
/* define ----------------------------------------------------------------*/
#ifndef Logitech_DRIVER
#define Logitech_DRIVER
/* Includes ---------------------------------------------------------------*/
#include <stdlib.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <string.h>
#include <stdio.h>
#include <map>
#define JSKEY_A 0x001
#define JSKEY_B 0x101
#define JSKEY_X 0x201
#define JSKEY_Y 0x301
#define JSKEY_LB 0x401
#define JSKEY_RB 0x501
#define JSKEY_BACK 0x601
#define JSKEY_START 0x701
#define JSKEY_HOME 0x801
#define JSKEY_LT 0x202
#define JSKEY_RT 0x502
#define JSKEY_CROSS_X 0x602
#define JSKEY_CROSS_Y 0x702
#define JSKEY_LEFTSTICK_X 0x002
#define JSKEY_LEFTSTICK_Y 0x102
#define JSKEY_RIGHTSTICK_X 0x302
#define JSKEY_RIGHTSTICK_Y 0x402
#define JSKEY_PRESS 0x001
#define JSKEY_RELEASE 0x0
#define JSKEY_CROSS_LOW_VALUE 0xffff8001
#define JSKEY_CROSS_HIGH_VALUE 0x7fff
using namespace std;
class Logitech{
private:
char *dev;
ssize_t n;
int fd;
int buf[2];
public:
Logitech(char* device);
map<int, int> Keystate_map;
int init();
void listen_input();
void print_key_state();
};
#endif //Logitech_DRIVER
2. 源文件
Logitech_controller.c :
/*========================= Gamepad Control ================================*/
/* Copyright (C) 2021 - ~, SCUT-RobotLab Development Team
* @file Logitech_controller.cpp
* @author lindongdong
* @brief 罗技遥控器的驱动库,库目前支持罗技遥控器型号:F710、F310。
* @note
* - 注意按键值所对应的意义。
* - 当手柄 Mode为黄灯时,左边上下左右按键与左边遥感值互换,按键按下为对应遥感边界值(+-1)
* 遥感推至极限为对应按键值。
* - 一般情况下使用非黄灯模式。
* @method
* - 1. 手柄驱动路径 : char path[] = "/dev/input/js0";
* - 2. 定义一个遥控器类 : Logitech Logitech(path);
* - 3. 遥控器类初始化 : Logitech.init();
* - 4. 线程中进行数据接受 : Logitech.listen_input();
* @warning
* - At least C++11 is required.
* - Only linux platform is supported for now.
*/
/*========================= Gamepad Control ================================*/
/* Includes ----------------------------------------------------------------*/
#include "Logitech_controller.h"
using namespace std;
Logitech::Logitech(char* device)
{
dev = device;
memset(buf, 0, sizeof buf);
}
int Logitech::init()
{
fd = open(dev, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Cannot open %s: %s.\n", dev, strerror(errno));
return EXIT_FAILURE;
}
/*Key Status*/
/* 0 is released */
/* 1 is press */
Keystate_map[JSKEY_A] =0;
Keystate_map[JSKEY_B] =0;
Keystate_map[JSKEY_X] =0;
Keystate_map[JSKEY_Y] =0;
/* 0 is released */
/* 1 is press */
Keystate_map[JSKEY_LB] =0;
Keystate_map[JSKEY_RB] =0;
/* 0 is released */
/* 1 is press */
Keystate_map[JSKEY_BACK] =0;
Keystate_map[JSKEY_START] =0;
Keystate_map[JSKEY_HOME] =0;
/* 0 is released */
/* -1 is the left or up button is pressed */
/* 1 is the right or down button is pressed*/
Keystate_map[JSKEY_CROSS_X] =0;
Keystate_map[JSKEY_CROSS_Y] =0;
/* the result is the value of the key(0~99)*/
Keystate_map[JSKEY_LT] =0;
Keystate_map[JSKEY_RT] =0;
/* the result is the value of the key(-100~100)*/
Keystate_map[JSKEY_LEFTSTICK_X] =0;
Keystate_map[JSKEY_LEFTSTICK_Y] =0;
Keystate_map[JSKEY_RIGHTSTICK_X] =0;
Keystate_map[JSKEY_RIGHTSTICK_Y] =0;
return 0;
}
void Logitech::listen_input()
{
while (1) {
memset(buf, 0, sizeof buf);
n = read(fd, &buf, sizeof buf);
n = n / sizeof(int);
if (n == (ssize_t)-1) {
if (errno == EINTR)
continue;
else
break;
}
unsigned short btn = buf[1] >> 16;
short val = (short)(buf[1] & 0xffff);
/*Test for button ID*/
//cout<<"0x"<<hex<<btn<<endl;
if (btn == JSKEY_LT || btn == JSKEY_RT)
{
unsigned short prs_val = val + 32768;
val = (unsigned short) (((long)prs_val)*100/65536);
Keystate_map[btn]= val;
}
else if (btn == JSKEY_LEFTSTICK_X || btn == JSKEY_LEFTSTICK_Y ||
btn == JSKEY_RIGHTSTICK_X || btn == JSKEY_RIGHTSTICK_Y)
{
/* y-axis reverse */
if(btn==JSKEY_LEFTSTICK_Y||btn == JSKEY_RIGHTSTICK_Y)
{val=(-1)*val;}
val = val*100/32767;
Keystate_map[btn]= val;
}
else
{
switch (val)
{
case JSKEY_PRESS:
Keystate_map[btn]=1;
break;
case JSKEY_RELEASE:
Keystate_map[btn]=0;
break;
case JSKEY_CROSS_LOW_VALUE:
Keystate_map[btn]=-1;
break;
case JSKEY_CROSS_HIGH_VALUE:
Keystate_map[btn]=1;
break;
default:
break;
}
/* y-axis reverse */
if(btn==JSKEY_CROSS_Y)
{Keystate_map[btn]=(-1)*Keystate_map[btn];}
}
print_key_state();
}
}
void Logitech::print_key_state()
{
cout<<endl;
cout<<"JSKEY_A = "<<Keystate_map[JSKEY_A]<<endl;
cout<<"JSKEY_B = "<<Keystate_map[JSKEY_B]<<endl;
cout<<"JSKEY_X = "<<Keystate_map[JSKEY_X]<<endl;
cout<<"JSKEY_Y = "<<Keystate_map[JSKEY_Y]<<endl;
cout<<"JSKEY_LB = "<<Keystate_map[JSKEY_LB]<<endl;
cout<<"JSKEY_RB = "<<Keystate_map[JSKEY_RB]<<endl;
cout<<"JSKEY_BACK = "<<Keystate_map[JSKEY_BACK]<<endl;
cout<<"JSKEY_START = "<<Keystate_map[JSKEY_START]<<endl;
cout<<"JSKEY_HOME = "<<Keystate_map[JSKEY_HOME]<<endl;
cout<<"JSKEY_LT = "<<Keystate_map[JSKEY_LT]<<endl;
cout<<"JSKEY_RT = "<<Keystate_map[JSKEY_RT]<<endl;
cout<<"JSKEY_CROSS_X = "<<Keystate_map[JSKEY_CROSS_X]<<endl;
cout<<"JSKEY_CROSS_Y = "<<Keystate_map[JSKEY_CROSS_Y]<<endl;
cout<<"JSKEY_LEFTSTICK_X = "<<Keystate_map[JSKEY_LEFTSTICK_X] <<" JSKEY_LEFTSTICK_Y = "<<Keystate_map[JSKEY_LEFTSTICK_Y]<<endl;
cout<<"JSKEY_RIGHTSTICK_X = "<<Keystate_map[JSKEY_RIGHTSTICK_X]<<" JSKEY_RIGHTSTICK_Y = "<<Keystate_map[JSKEY_RIGHTSTICK_Y]<<endl;
}
3. 测试代码
Logitech_controller_test.cpp :
#include "Logitech_controller.h"
using namespace std;
int main()
{
char path[] = "/dev/input/js0";
Logitech gamepad(path);
gamepad.init();
gamepad.listen_input();
return 0;
}
三. 源码下载链接
以上例程中的代码如下:
开发环境:
- ubuntu18.04
- Qt5.10.0