一天精通无人机遥控器协议 S-BUS

今天我们来一起学习无人机遥控器常见通讯协议S-BUS的解析方法。S-BUS其实是一种串口通信协议,采用100000的波特率,数据位点8bits,停止位点2bits,偶效验,即8E2的串口通信。但是S-BUS采用的是反向电平传输,也就是说,在S-BUS的发送端高低电平是反向的,协议中的所有高电平都被转换成低电平,协议中的所有低电平都被转换成高电平。所以在S-BUS的接收端需要增加一个高低电平反向器来进行电平反转,如下图:

一天精通无人机遥控器协议 S-BUS

实际上,我们使用的Pixhawk飞控板上已经集成了这个反向器,所以对于使用Pixhawk的用户来说,可以忽略掉S-BUS的反向机制,但是对于其它没有集成S-BUS反向器的硬件平台上,就需要使用者增加一个反向器来处理数据,否则将无法读取协议数据。

另外,100000的波特率并不是标准的波特率,这在一些只支持标准波特率的系统上无法实现,好在Nuttx支持自定义的波特率,我们可以通过对设备节点的配置实现波特率的设定。在Pixhawk IO上,S-BUS总线的设备节点为/dev/ttyS2,于是我们可以编写一个程序对这个串口节点的波特率进行配置:

voidsbus_config(void){

intsbus_fd =open(“/dev/ttyS2”,O_RDWR |O_NONBLOCK );

if(sbus_fd <0)

{

return;

}

structtermios t ;

//设置100000波特率

tcgetattr(sbus_fd ,&t );

cfsetspeed(&t ,100000);

t .c_cflag |=(CSTOPB |PARENB );

tcsetattr(sbus_fd ,TCSANOW ,&t );}

设置好波特率就可以对标准文件设备进行读取了,也就是通过read函数来读取串口当中的数据。S-BUS协议在传输过程中还有两种不同的传输模式:

  1. 高速模式:数据发送周期为4ms,发送频率为250Hz;
  2. 低速模式:数据发送周期为14ms,发送频率为71.4Hz。

S-BUS协议数据格式如下:

S-BUS协议数据格式如下:

需要注意的是S-BUS中用11bits来表示一个遥控器通道的数值,22个字节就可以表示16通道(8 × 22 = 11 ×16)。11个bit可以表示的数值范围为0~2047。例如:我们的遥控器前4个通道数值分别为200、300、400和500,其它通道都为0。它们的二进制数据分别为:

200:000 1100 1000

300:001 0010 1100

400:001 1001 0000

500:001 1111 0100

其它通道都为:0

S-BUS的16个遥控器通道,每一个通道用11个bit表示,那么这16个通道的二进制数值拼接起来则为:

0001 1001 0000 0100 1011 0000 1100 1000 0001 1111 0100

[0F] 19 04 B0 C8 1F 40 …… 00 [00]

实际上遥控器发送每一个通道的数值在200~1800之间,用来表示遥控器通道的所有数值。但是PX4飞控程序中有效的通道值范围通常是1000~2000,所以就需要将原始数值进行一次转换。接下来我们就来编写S-BUS协议解析的驱动程序:

#defineSIZE_BUFF (100)//S-BUS协议中遥控器通道数值范围#defineSBUS_RANGE_MIN 200.0f#defineSBUS_RANGE_MAX 1800.0f//PX4中使用的遥控器通道数值范围#defineSBUS_TARGET_MIN 1000.0f#defineSBUS_TARGET_MAX 2000.0f//数值放大因子#defineSBUS_SCALE_FACTOR ((SBUS_TARGET_MAX – SBUS_TARGET_MIN) / (SBUS_RANGE_MAX – SBUS_RANGE_MIN))//数值放大偏移量#defineSBUS_SCALE_OFFSET (int)(SBUS_TARGET_MIN – (SBUS_SCALE_FACTOR * SBUS_RANGE_MIN + 0.5f))//S-BUS解析函数intsbus_read_parse(int_fd ,uint16_t *val ){

//读取遥控器通道数据

uint8_t _buf [SIZE_BUFF ];

intlen =read(_fd ,_buf ,SIZE_BUFF );

if(len <0)

{

return-1;

}

//略过协议包头、包尾、长度判断过程

//按11bits解析遥控器通道

val [0]=((buff [ind +1]|buff [ind +2]<<8)&0x07FF);

val [1]=((buff [ind +2]>>3|buff [ind +3]<<5)&0x07FF);

val [2]=((buff [ind +3]>>6|buff [ind +4]<<2|buff [ind +5]<<10)&0x07FF);

val [3]=((buff [ind +5]>>1|buff [ind +6]<<7)&0x07FF);

val [4]=((buff [ind +6]>>4|buff [ind +7]<<4)&0x07FF);

val [5]=((buff [ind +7]>>7|buff [ind +8]<<1|buff [ind +9]<<9)&0x07FF);

val [6]=((buff [ind +9]>>2|buff [ind +10]<<6)&0x07FF);

val [7]=((buff [ind +10]>>5|buff [ind +11]<<3)&0x07FF);

val [8]=((buff [ind +12]|buff [ind +13]<<8)&0x07FF);

val [9]=((buff [ind +13]>>3|buff [ind +14]<<5)&0x07FF);

val [10]=((buff [ind +14]>>6|buff [ind +15]<<2|buff [ind +16]<<10)&0x07FF);

val [11]=((buff [ind +16]>>1|buff [ind +17]<<7)&0x07FF);

val [12]=((buff [ind +17]>>4|buff [ind +18]<<4)&0x07FF);

val [13]=((buff [ind +18]>>7|buff [ind +19]<<1|buff [ind +20]<<9)&0x07FF);

val [14]=((buff [ind +20]>>2|buff [ind +21]<<6)&0x07FF);

val [15]=((buff [ind +21]>>5|buff [ind +22]<<3)&0x07FF);

//将原始数值转换到PX4所使用的范围

for(inti =0;i <16;i ++)

{

val [i ]=(uint16_t )(val [i ]*SBUS_SCALE_FACTOR +.5f)+SBUS_SCALE_OFFSET ;

}

return0;}

当然,我们需要在驱动程序中启动一个线程来读取并解析S-BUS协议,此进程将使用循环的方式调用int sbus_read_parse(int _fd, uint16_t *val)函数,之后将val数组中的内容使用input_rc.msg消息发布到uORB总线上为其它进程所使用。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至2161241530@qq.com 举报,一经查实,本站将立刻删除。如若转载,请注明出处:https://www.woiwrj.com/wurenjibaike/djiwurenzhishi/8323/

(0)

相关推荐