Logitech F310
游戏手柄是Logitech公司生产的双模拟摇杆,动式方向按键游戏手柄。
游戏手柄的作用不只是可以用来玩游戏,还可以用于做一些机器人仿真,就比如最近MIT开源的Mini Cheetah
四足机器人,其中机器人仿真部分用的控制器就是罗技F310游戏手柄。但是其采用的方法是直接调用QT
中的QtGamepad库
操作手柄,对于没有安装QT的人没办法直接调用,为此我写了一份罗技F310的通用驱动,驱动也兼容F710,其他型号的游戏手柄还未测试。
代码目前只支持Linux
,可以实现读取所有遥感和按键的数值,最终效果如下:
驱动手柄并将各个按键值打印出来:
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; }
以上例程中的代码如下:
开发环境: