今天我們來一起學(xué)習(xí)無人機遙控器常見通訊協(xié)議S-BUS的解析方法。S-BUS其實是一種串口通信協(xié)議,采用100000的波特率,數(shù)據(jù)位點8bits,停止位點2bits,偶效驗,即8E2的串口通信。但是S-BUS采用的是反向電平傳輸,也就是說,在S-BUS的發(fā)送端高低電平是反向的,協(xié)議中的所有高電平都被轉(zhuǎn)換成低電平,協(xié)議中的所有低電平都被轉(zhuǎn)換成高電平。所以在S-BUS的接收端需要增加一個高低電平反向器來進(jìn)行電平反轉(zhuǎn),如下圖:
實際上,我們使用的Pixhawk飛控板上已經(jīng)集成了這個反向器,所以對于使用Pixhawk的用戶來說,可以忽略掉S-BUS的反向機制,但是對于其它沒有集成S-BUS反向器的硬件平臺上,就需要使用者增加一個反向器來處理數(shù)據(jù),否則將無法讀取協(xié)議數(shù)據(jù)。
另外,100000的波特率并不是標(biāo)準(zhǔn)的波特率,這在一些只支持標(biāo)準(zhǔn)波特率的系統(tǒng)上無法實現(xiàn),好在Nuttx支持自定義的波特率,我們可以通過對設(shè)備節(jié)點的配置實現(xiàn)波特率的設(shè)定。在Pixhawk IO上,S-BUS總線的設(shè)備節(jié)點為/dev/ttyS2,于是我們可以編寫一個程序?qū)@個串口節(jié)點的波特率進(jìn)行配置:
voidsbus_config(void){
intsbus_fd =open(“/dev/ttyS2”,O_RDWR |O_NONBLOCK );
if(sbus_fd <0)
{
return;
}
structtermios t ;
//設(shè)置100000波特率
tcgetattr(sbus_fd ,&t );
cfsetspeed(&t ,100000);
t .c_cflag |=(CSTOPB |PARENB );
tcsetattr(sbus_fd ,TCSANOW ,&t );}
設(shè)置好波特率就可以對標(biāo)準(zhǔn)文件設(shè)備進(jìn)行讀取了,也就是通過read函數(shù)來讀取串口當(dāng)中的數(shù)據(jù)。S-BUS協(xié)議在傳輸過程中還有兩種不同的傳輸模式:
- 高速模式:數(shù)據(jù)發(fā)送周期為4ms,發(fā)送頻率為250Hz;
- 低速模式:數(shù)據(jù)發(fā)送周期為14ms,發(fā)送頻率為71.4Hz。
S-BUS協(xié)議數(shù)據(jù)格式如下:
需要注意的是S-BUS中用11bits來表示一個遙控器通道的數(shù)值,22個字節(jié)就可以表示16通道(8 × 22 = 11 ×16)。11個bit可以表示的數(shù)值范圍為0~2047。例如:我們的遙控器前4個通道數(shù)值分別為200、300、400和500,其它通道都為0。它們的二進(jìn)制數(shù)據(jù)分別為:
200:000 1100 1000
300:001 0010 1100
400:001 1001 0000
500:001 1111 0100
其它通道都為:0
S-BUS的16個遙控器通道,每一個通道用11個bit表示,那么這16個通道的二進(jìn)制數(shù)值拼接起來則為:
0001 1001 0000 0100 1011 0000 1100 1000 0001 1111 0100
[0F] 19 04 B0 C8 1F 40 …… 00 [00]
實際上遙控器發(fā)送每一個通道的數(shù)值在200~1800之間,用來表示遙控器通道的所有數(shù)值。但是PX4飛控程序中有效的通道值范圍通常是1000~2000,所以就需要將原始數(shù)值進(jìn)行一次轉(zhuǎn)換。接下來我們就來編寫S-BUS協(xié)議解析的驅(qū)動程序:
#defineSIZE_BUFF (100)//S-BUS協(xié)議中遙控器通道數(shù)值范圍#defineSBUS_RANGE_MIN 200.0f#defineSBUS_RANGE_MAX 1800.0f//PX4中使用的遙控器通道數(shù)值范圍#defineSBUS_TARGET_MIN 1000.0f#defineSBUS_TARGET_MAX 2000.0f//數(shù)值放大因子#defineSBUS_SCALE_FACTOR ((SBUS_TARGET_MAX – SBUS_TARGET_MIN) / (SBUS_RANGE_MAX – SBUS_RANGE_MIN))//數(shù)值放大偏移量#defineSBUS_SCALE_OFFSET (int)(SBUS_TARGET_MIN – (SBUS_SCALE_FACTOR * SBUS_RANGE_MIN + 0.5f))//S-BUS解析函數(shù)intsbus_read_parse(int_fd ,uint16_t *val ){
//讀取遙控器通道數(shù)據(jù)
uint8_t _buf [SIZE_BUFF ];
intlen =read(_fd ,_buf ,SIZE_BUFF );
if(len <0)
{
return-1;
}
//略過協(xié)議包頭、包尾、長度判斷過程
//按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);
//將原始數(shù)值轉(zhuǎn)換到PX4所使用的范圍
for(inti =0;i <16;i ++)
{
val [i ]=(uint16_t )(val [i ]*SBUS_SCALE_FACTOR +.5f)+SBUS_SCALE_OFFSET ;
}
return0;}
當(dāng)然,我們需要在驅(qū)動程序中啟動一個線程來讀取并解析S-BUS協(xié)議,此進(jìn)程將使用循環(huán)的方式調(diào)用int sbus_read_parse(int _fd, uint16_t *val)函數(shù),之后將val數(shù)組中的內(nèi)容使用input_rc.msg消息發(fā)布到uORB總線上為其它進(jìn)程所使用。
版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點僅代表作者本人。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請發(fā)送郵件至2161241530@qq.com 舉報,一經(jīng)查實,本站將立刻刪除。如若轉(zhuǎn)載,請注明出處:http://www.parklessenses.com/wurenjibaike/djiwurenzhishi/8323/