and 15 buttons (BtnA, BtnB, BtnC, BtnX, BtnY, BtnZ, BtnTL, BtnTR, BtnTL2, BtnTR2, BtnSelect, BtnStart, BtnMode, BtnThumbL, BtnThumbR).
Testing ... (interrupt to exit)
Axes:  0:     0  1:     0  2:     0  3:     0  4:-32767  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 11:off 12:off 13:off 14:off

备注:

on:标识手柄对应的按键按下

off:标识手柄对应的按键松开

一、分层说明:手柄 ↔ 机器人完整通信链路

分成三层协议,很多开发人员容易混淆:

层级 1:物理传输协议(手柄硬件 ↔ Ubuntu 主机)

手柄是 USB 游戏手柄(VID 0079 国产控制器) 通信标准:USB HID 协议

  • 手柄硬件内部:定时通过 USB 上报 HID 报告(原始二进制数据包)
  • 报文包含:所有摇杆模拟量、按键开关状态
  • 操作系统内核 hid 驱动 → evdev 子系统 → js 驱动

两个独立内核接口: 1)evdev(/dev/input/eventX,现代标准) 2)legacy joystick API(/dev/input/js0,jstest使用这套)

层级 2:Linux 内核 JS API 协议(/dev/input/js0,jstest 读取的数据)

当前 jstest 看到的所有数字,就是这一层解析出来的数据 内核持续向外输出 js_event 结构体:

c

运行

struct js_event {
    __u32 time;     // 时间戳
    __s16 value;    // 值范围 [-32767 ~ +32767]
    __u8 type;      // 轴事件 / 按键事件
    __u8 number;    // 【重点】轴编号/按键编号
};

number = 你看到的数字编号

层级 3:ROS2 应用层协议(joy_node)

joy_node 读取 /dev/input/js0,把内核 js 事件转换为 ROS 标准消息: sensor_msgs/msg/Joy

plaintext

std_msgs/Header header
float32[] axes        # 浮点 [-1.0 ~ 1.0],对应轴0~7
int32[] buttons       # 0=松开,1=按下,对应按键0~14

二、全部编号定义(js0 接口,唯一对照表,ROS 开发直接复制)

🎮 Axes 模拟轴 number【0 ~ 7】

表格

编号 number名称硬件部件取值规则当前初始值
0X

左摇杆:左右

前进后退

左 =-32767,居中 = 0,右 =+327670
1Y

左摇杆:上下

左移右移

上 =-32767,居中 = 0,下 =+327670
2Z

右摇杆:左右

左转右旋

左 =-32767,居中 = 0,右 =+327670
3Rz

右摇杆:上下

上旋下旋(俯仰)

上 =-32767,居中 = 0,下 =+327670
4GasLT 左线性扳机松开 =-32767,按到底 =+32767-32767
5BrakeRT 右线性扳机松开 =-32767,按到底 =+32767-32767
6Hat0X十字方向键 ←→左 =-32767,无操作 = 0,右 =+327670
7Hat0Y十字方向键 ↑↓上 =-32767,无操作 = 0,下 =+327670

⚠️关键:内核原始值 -32767 ~ 32767 ROS joy_node 自动线性映射 → [-1.0, 1.0]

🎯 Buttons 按键 number【0 ~ 14】

事件 value:1=按下 on0=松开 off

表格

编号 number标识物理按键
0BtnAA 键
1BtnBB 键
2BtnCC 键
3BtnXX 键
4BtnYY 键
5BtnZZ 键
6BtnTLLB 左上肩按键
7BtnTRRB 右上肩按键
8BtnTL2LT 扳机底部机械开关
9BtnTR2RT 扳机底部机械开关
10BtnSelectSelect 选择键
11BtnStartStart 开始键
12BtnModeMode 模式键
13BtnThumbLL3(左摇杆垂直按下)
14BtnThumbRR3(右摇杆垂直按下)

三、重要工程坑(机器人遥控必看)

1. LT/RT 扳机初始偏移问题

轴 4、轴 5 静止 =-32767 → ROS axes 读到 -1.0 如果你想用扳机控制速度,需要归一化矫正公式:

plaintext

# 原始值 [-32767,32767] → [0, 1]
output = (raw_value + 32767) / 65534.0

2. 两套接口编号不互通

  • /dev/input/js0:旧 JS 接口,编号如上表(jstest)
  • /dev/input/eventX:evdev 接口(evtest) 两套的轴 / 按键编号完全独立,不能混用映射表!

3. 通信延迟说明

USB HID 轮询频率通常 100Hz; Linux 增加少量内核调度延迟;ROS2 层总体延迟足够移动机器人遥控使用。

四、机器人常用映射方案(直接用于代码)

示例:差分底盘遥控

plaintext

axes[1] 左摇杆上下 → 前进/后退速度
axes[2] 右摇杆左右 → 转向角速度
buttons[11] Start键 → 启动机器人
buttons[10] Select键 → 紧急停止

五、补充建议

长远推荐改用 evdev(/dev/input/by-id/xxx-event-if01) 支持震动、陀螺仪拓展,joy_node 同样兼容 evdev 设备; 不要再依赖 js0 老旧接口。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐