4、SBUS通道映射:16个比例通道(11位精度)、2个数字通道(CH17/CH18)、通道值范围(192-1792)

好,咱们接着聊SBUS协议里最核心的部分——通道映射。

说实话,我第一次看SBUS协议文档时,也被这堆数字搞得有点晕。16个比例通道,每个11位精度,还有2个数字通道,通道值范围192到1792……这到底是怎么映射的?今天我就把这块彻底讲透。

4.1 16个比例通道:11位精度的秘密

SBUS协议里,比例通道占了16个。每个通道用11位来表示。

你可能会问:为什么是11位?不是8位,也不是16位?

嗯,这里有个历史原因。早期的遥控器系统大多用8位(0-255),但精度不够。飞固定翼还行,飞多旋翼就感觉舵机抖得厉害。后来大家发现,11位刚好能覆盖遥控器摇杆的物理行程,又不会浪费太多带宽。

11位能表示多少值?2的11次方,也就是2048个离散值。但SBUS协议并没有用满这2048个值,而是把有效范围限定在192到1792之间。

核心要点:

  • 每个比例通道占用11位(bit)
  • 有效值范围:192 ~ 1792
  • 中间值(中位):992
  • 16个通道共占用 16 × 11 = 176 位

我在项目中遇到过一个问题:有个飞友说他的舵机在中位附近总是抖动。排查了半天,发现是接收机输出的SBUS信号中位值漂了。正常中位应该是992,他那边输出的是1002。差了10个值,舵机就一直在微调。后来换了接收机就好了。所以,中位校准真的很重要。

4.2 通道值范围:192-1792 的由来

为什么是192到1792?不是0到2047?

说白了,这是为了留出保护边界。遥控器摇杆打到最边上时,物理上可能会有一些余量。如果直接用0和2047作为极限值,万一摇杆稍微过冲,通道值就溢出了。所以协议设计者留了192个值的余量。

含义 说明
最小值 192 摇杆最左/最下
中位值 992 摇杆居中
最大值 1792 摇杆最右/最上
理论范围 0 ~ 2047 11位完整范围
有效范围 192 ~ 1792 SBUS协议限定

你想想看,如果摇杆打到最边上,通道值刚好是192或1792。这时候舵机应该转到极限位置。如果摇杆再用力一点,通道值可能会跑到1800以上,但接收机内部会做限幅处理,不会让舵机超行程。

个人经验:

我在调试ArduPilot时,习惯把遥控器的行程校准到SBUS的192-1792范围内。有些遥控器默认输出的是0-2047,这时候需要在接收机或者飞控里做映射。ArduPilot的RCx_MIN和RCx_MAX参数就是干这个用的。

4.3 2个数字通道:CH17和CH18

除了16个比例通道,SBUS还带了2个数字通道——CH17和CH18。

这两个通道不是比例信号,而是开关量。说白了,就是0或1。用来控制开关、模式切换、解锁/上锁等。

为什么需要数字通道?

我记得有一次做无人机测试,客户要求用遥控器上的一个开关来切换飞行模式。如果用比例通道,还得在飞控里设置阈值,比如通道值大于1500算开,小于1500算关。但数字通道就简单了,直接读0或1,省心多了。

数字通道的特点:

  • CH17:第17通道,数字量(0或1)
  • CH18:第18通道,数字量(0或1)
  • 通常用于开关控制、模式切换
  • 在SBUS数据帧中占用最后2位

4.4 数据帧中的通道排列

SBUS的数据帧一共25个字节。通道数据是怎么塞进去的?

我画了一张图,你看一眼就明白了。

SBUS 25字节数据帧结构 0x0F 起始字节 通道数据(16个比例通道 × 11位 = 176位) 字节1 ~ 字节22 CH17 CH18 字节23 0x00 结束字节 每个比例通道值范围:192 ~ 1792(11位精度) 中位值:992 总长度:25字节 = 200位 比例通道占用:176位 | 数字通道占用:2位 | 标志位:6位 起始/结束字节:2字节

从图上可以看出来,字节0是起始标志0x0F,字节1到22是16个比例通道的数据,字节23的低2位是CH17和CH18,字节24是结束标志0x00。

4.5 位操作:如何从数据帧中提取通道值

这部分是实操重点。你拿到25个字节的SBUS数据帧后,怎么把每个通道的值提取出来?

因为每个通道是11位,不是整字节,所以需要做位操作。我直接给你代码,这是我项目里用过的,经过验证的。

// SBUS通道提取函数
// 输入:sbus_frame[25] - SBUS数据帧
// 输出:channels[16] - 16个比例通道值(192-1792)
void sbus_parse_channels(uint8_t *sbus_frame, uint16_t *channels)
{
    // 通道0:字节1[7:0] + 字节2[2:0]
    channels[0] = ((uint16_t)sbus_frame[1] & 0xFF) |
                  (((uint16_t)sbus_frame[2] & 0x07) << 8);
    
    // 通道1:字节2[7:3] + 字节3[5:0]
    channels[1] = (((uint16_t)sbus_frame[2] & 0xF8) >> 3) |
                  (((uint16_t)sbus_frame[3] & 0x3F) << 5);
    
    // 通道2:字节3[7:6] + 字节4[7:0] + 字节5[2:0]
    channels[2] = (((uint16_t)sbus_frame[3] & 0xC0) >> 6) |
                  (((uint16_t)sbus_frame[4] & 0xFF) << 2) |
                  (((uint16_t)sbus_frame[5] & 0x07) << 10);
    
    // ... 以此类推,直到通道15
    
    // 通道15:字节21[7:0] + 字节22[2:0]
    channels[15] = ((uint16_t)sbus_frame[21] & 0xFF) |
                   (((uint16_t)sbus_frame[22] & 0x07) << 8);
    
    // 提取数字通道CH17和CH18
    // CH17:字节23的bit0
    // CH18:字节23的bit1
    uint8_t ch17 = (sbus_frame[22] & 0x01) ? 1 : 0;
    uint8_t ch18 = (sbus_frame[22] & 0x02) ? 1 : 0;
    
    // 限幅处理:确保通道值在192-1792范围内
    for (int i = 0; i < 16; i++)
    {
        if (channels[i] < 192) channels[i] = 192;
        if (channels[i] > 1792) channels[i] = 1792;
    }
}

避坑指南:

我曾经在解析SBUS时犯过一个低级错误——忘了做限幅处理。结果有一次遥控器电池快没电了,输出信号不稳定,通道值跑到了1800多。飞控收到这个值后,直接让电机满油门旋转,差点炸机。从那以后,我每次解析SBUS都会加限幅,这是血的教训。

4.6 通道映射在ArduPilot中的配置

在ArduPilot里,SBUS通道映射是通过参数来配置的。你不需要自己写位操作代码,飞控固件已经帮你做好了。但你需要知道怎么把遥控器的通道对应到飞控的功能上。

ArduPilot参数 说明 典型值
RC1_MIN / RC1_MAX 通道1的最小/最大值 192 / 1792
RC1_TRIM 通道1的中位值 992
RCMAP_ROLL 横滚通道映射 1(对应CH1)
RCMAP_PITCH 俯仰通道映射 2(对应CH2)
RCMAP_THROTTLE 油门通道映射 3(对应CH3)
RCMAP_YAW 偏航通道映射 4(对应CH4)

举个例子,如果你的遥控器把油门放在了CH3上,那RCMAP_THROTTLE就设为3。ArduPilot会自动把SBUS的CH3值映射到油门控制上。

我的习惯:

我一般会在飞控的Mission Planner里先校准遥控器。校准过程中,飞控会自动读取SBUS通道的最小值、最大值和中位值。校准完成后,检查一下RC1_MIN是不是192左右,RC1_MAX是不是1792左右。如果偏差太大,说明遥控器行程没设对,需要重新校准。

4.7 总结一下

SBUS通道映射这块,说白了就是三件事:

  • 16个比例通道:每个11位精度,值范围192-1792,中位992
  • 2个数字通道:CH17和CH18,0或1,用于开关控制
  • 位操作提取:从25字节数据帧中按位拼接出每个通道的值

嗯,掌握了这些,你就能看懂SBUS数据帧里到底在传什么了。下次遇到遥控器通道不对的问题,你也能快速定位是映射问题还是值范围问题。


公众号:蓝海资料掘金营,微信deep3321