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个字节。通道数据是怎么塞进去的?
我画了一张图,你看一眼就明白了。
从图上可以看出来,字节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