今回のマルチコプターでS.BUSを初めて使ったので信号をArduinoで読み出してみました。
S.BUSとは何かという詳しい説明はコチラ→https://ja.wikipedia.org/wiki/S.BUS
要はラジコン受信機から昔ながらのサーボ信号を出すのではなくシリアル通信にする事で全チャンネルを1本の信号線で制御するという物です。
飛行機の場合はサーボの位置が分散しているので結局それぞれに配線する必要があり、あまりメリットを感じませんでした。しかしマルチコプターでは受信機の信号は全てフライトコントローラ基板に接続するのでこれが一本で済むのは大きなメリットになります。
S.BUS信号はシリアル通信ですが、UARTでよく使う仕様とは微妙に違うところがあり面倒になっています。例えば次のところ・・・
- ボーレートが100Kbps。
なぜか115.2Kbpsではなく100Kbpsです。妙なボーレートですがArduinoではSerialBegin()のとき100000と指定する事で対応できます。
- 信号極性が逆転。
Arduinoに入れる信号はインバータで反転してやる必要があります(もしかするとArduino側に反転機能があるのかもしれませんが見つけられませんでした)。
あと受信後のデータが11bit区切りなので並べ替えがややこしいです。
S.BUSプロトコルに詳細はこちらを参考にしました。→https://os.mbed.com/users/Digixx/notebook/futaba-s-bus-controlled-by-mbed/→http://anarchy.hatenablog.com/entry/2014/12/07/181853
そして最低限の部分をスケッチに書きます。
int count;
long interval;
void setup() {
Serial.begin(115200); // Terminal
Serial1.begin(100000,SERIAL_8E2); // S-BUS
count=0;
}
void loop() {
int data[26];
int val[19];
int i;
if (Serial1.available() > 0) {
data[count]=Serial1.read();
interval=millis();
count++;
}
if ((interval+4 < millis()) && (0 < count) ) {
count=0;
val[0] =((data[1] & 0xff)<<0) + ((data[2] & 0x07)<<8);
val[1] =((data[2] & 0xf8)>>3) + ((data[3] & 0x3f)<<5);
val[2] =((data[3] & 0xc0)>>6) + ((data[4] & 0xff)<<2) + ((data[5] & 0x01)<<10);
val[3] =((data[5] & 0xfe)>>1) + ((data[6] & 0x0f)<<7);
val[4] =((data[6] & 0x0f)>>4) + ((data[7] & 0x7f)<<4);
val[5] =((data[7] & 0x80)>>7) + ((data[8] & 0xff)<<1) + ((data[9] & 0x03) <<9);
val[6] =((data[9] & 0x7c)>>2) + ((data[10] & 0x1f)<<6);
val[7] =((data[10] & 0xe0)>>5) + ((data[11] & 0xff)<<3);
val[8] =((data[12] & 0xff)<<0) + ((data[13] & 0x07)<<8);
val[9] =((data[13] & 0xf8)>>3) + ((data[14] & 0x3f)<<5);
val[10]=((data[14] & 0xc0)>>6) + ((data[15] & 0xff)<<2) + ((data[16] & 0x01)<<10);
val[11]=((data[16] & 0xfe)>>1) + ((data[17] & 0x0f)<<7);
val[12]=((data[17] & 0x0f)>>4) + ((data[18] & 0x7f)<<4);
val[13]=((data[18] & 0x80)>>7) + ((data[19] & 0xff)<<1) + ((data[20] & 0x03) <<9);
val[14]=((data[20] & 0x7c)>>2) + ((data[21] & 0x1f)<<6);
val[15]=((data[21] & 0xe0)>>5) + ((data[22] & 0xff)<<3);
val[16] = (data[23] & 0x1) ? 0x7ff : 0 ;
val[17] = (data[23] & 0x2) ? 0x7ff : 0 ;
val[18] = (data[23] & 0x8) ? 0x7ff : 0 ; // Failsafe
for (i=0 ; i<19; i++ ) {
Serial.print(val[i],DEC);
Serial.print(F(" "));
}
Serial.print(F("\n"));
}
}
S.BUSから取り込んだデータをUSB経由でシリアルモニタに表示したいので、シリアルポートが複数あるArduino MEGA2560で動かしてみます。
Arduino MEGA2560でS.BUSをモニター。
ブレッドボード上のICは信号極性反転のための74HC00。
こんな感じでデータが出てきました。
送信機が6CHなので7CH以降が正しいかどうかは確かめられていません。また19番目のデータはFailsafeが働いたときに1になるはずですが、これも確かめていません。
モニター中。
各データが11bitt幅なので0~2047が表せるはずで、どうやらニュートラルが1024の様です。
ところでCleanflightにも受信データを表示する機能があります。しかし今回のモニターとCleanflightの値が一致しません。そこで何ポイントか対応を取ってみました。
SBUSモニタ Cleanflight
102 943
697 1315
1024 1520 ←ニュートラル
1435 1776
1681 1930
グラフにすると・・・
SBUSとCleanFlightの読値対応
恐らくCleanflightの表示値は昔ながらのPWMサーボ信号のパルス幅に換算した値をμS単位で表示しているのだと思います。例えばニュートラルはS.BUSの生データは1024ですがPWMだと1520μSといった感じ。
ということでS.BUSの生の値にざっと0.625掛けて879.5を足すとほぼCleanFlightの値になる様です。