Tag Archives: S.BUS

HOI-LINK-HR の遅延を減らせるか試す。

NONSAYAさんが販売されて以来、HOI-LINK-HRがドローンレース界隈で静かな話題になっている様です。このHOI-LINK-HRはSBUSから受けた11bitのデータを8bitに減らさず11bitのままPCに届けるので分解能が上がっていて、私には効果が体感できませんがプロには評判がいい様です。
そこで更なる改良として遅延を少しでも減らせないか試してみました。

どうやって遅延を減らすか

まあそんなに大幅に遅延を減らす方法などはそうそう無いと思いますが、多少でも改善できそうなのが次の点・・・。

まずSBUS信号はRCチャンネル18ch分を25バイトのデーターとして送ってきます。そして25バイトの転送に約3.5mSを要します(計算上3mSだと思っていたのに実測すると3.5mSなのでした。とりあえず3.5mSで話を進めます)。
その後数msの無信号期間を挟んでまた3.5mSのデータを送出するという事を繰り返します(無信号期間の長さは送受信機によって異なりますが、いくつか見た限り4mS~10mS程でした)。

このデータをPIC18F14K50マイコンで受取ります。この時、これまでは25バイトを全部受け取ってからRCチャンネルデータに変換し、USBに送り出していました。そしてUSB側ではPCが周期的にポーリング(問合せ)したタイミングでデーターを転送します。SBUS信号とUSBポーリングのタイミングは同期してはいないのでポーリングのタイミングがデータ転送期間の3.5mSの間に来る事もある筈です。この場合今までの処理だとその瞬間にSBUS転送中のデータは、ひとつ後のポーリング周期にUSBに送る事になります。


そして今回の変更ですが、HOI-LINK-HRは8CHまでのサポートなので約1.5mSの時点で必要なデータは受取っている訳です。なので「この時点で処理を開始してもええんちゃう?」というのが今回の考えです。
先頭から1.5mSの間にポーリングが来たら従来と同じですが、それ以降だと最新のデータを転送する事ができるので、従来の3.5mSと比べ1.5mSなのて2mSの期間は一周期前倒しができる事になります。なおUSBのポーリング周期は10mSらしい(この値、資料が見当たらないのですが、どなたかご存じでしょうか?)ので約20%のデータが今までより一回分(10mS)早く転送できるはず・・・なのです。

例によってこの変更がどの程度体感できるか不明ですし、私にはまずわからないと思いますが、少なくとも今までよりは早くなっているはず・・・。

あとUSBの処理をプログラムで周期的に呼び出す方式から割り込み方式に変更しました。これはμS単位では早くなっているかもしれませんが殆ど気分の問題だと思います。

その他の変更

一時期SBUSの区切りを検出する方法が色々と迷走していました。8bit版HOI-LINKの時は無信号期間が数mSあったら区切りと判断していましたが、11bit化したとき受信器によって不安定なことが分かり、参考に見たSBUSデコードプログラムでは最終バイトが’00’である事を手掛かりに判断していたのでそれに従っていました。
しかしBetaflightの処理をみたら無信号期間検出方式だったので安心して元に戻しています(不安定だったのはSBUSを受けるUSARTのオーバーフロー処理をしていなかったためで解決済)。
この修正は NONSAYAさん販売バージョンは適用済です。

またPIC18F14K50のRC3~RC7ポート(5~9pin)は今まで空きピンでしたがデバッグ情報を出力する様に変更しており、LEDをつないでおくとオーバーフローやパリティエラー発生時に点灯する様にしています。まあ特に何も接続していなければ影響はありません。

でVelociDroneで試したら・・・

やっぱり体感できません。でも理屈の上では今までよりも遅延が減っているはず(・・・ホンマか?)
このあたり、何か遅延量を測定する方法が必要と考えているのですが、いい案はありますか?

ファームウェア

例によってファーム(ソース・バイナリ)を載せておきます。
なお過去に何度か書いていますがUSBのベンダーID、デバイスIDは適当な値を書いているので使用される場合は自己責任でお願いします。0xffff/0x0012というありそうにない値なので重複する可能性は低いと思いますがもし重複した場合はPCがその機器を認識できない可能性があります。この場合以前このブログに書いた方法でPCに過去の接続を忘れさせる事ができると思いますが保証はできません(まずそんな事態にはならないと思いますが)。
なおNONSAYAさん販売のドングルはマイクロチップテクノロジー社からサブライセンスを受けているのでちゃんとしたIDが書かれています。

またソースはOpenStick Liteから流用した関係で色々と無駄なコードを含んでいるので、読まれる方は温かい心で見てください。

HOI-LinkHR20200822.zip

追記:20200820版は一部ミスっていて効果が出ていなかったので20200822版として再アップロードしました。

HOI-LINK高分解能化

以前我が家に来られた事のあるNONSAYAさん、当時はレーザー加工機の話題で盛り上がりましたが、今はドローンレース界の重鎮です。
そんなNONSAYAさんと最近Facebookでお話しする機会があり、コントローラーの分解能が何bit必要かという話になりました。
最近はVelociDrone(ドローンシミュレーター)を使ってオンラインのレース を開催されており、この時コントローラーからPCに送られる信号の分解能がプロレベルの速さでは影響するのではないかと。

OpenStickにしてもHOI-LINKにしても今のところ8bit幅でデータを送っています。一方実機のドローンでよく使われるS-BUS信号は11bit幅です。
私の素人的感覚では8bit幅(=256分解能)もあれば十分かと思っていましたが、レースのプロには影響するのかもしれません。

そこでHOI-LINKを高分解能化して試す事にしました。
HOI-LINKはラジコン受信機が出すS-BUS信号をPICマイコンで受け、USBのジョイスティック信号に変換してPCに送る仕組みになっています。
これを使えば実物のラジコン送信機を使ってドローンシミュレータの練習をしたり、PCに制御信号を送ったりできるモノなのです。

こんな仕組みです。

ここで先ほど書いた通りS-BUSからは11bit幅のデーターが送られてきます。これを8bitに変換するため下3bitは捨てて上位8bitだけをUSBに送っていました。これに対し高解像度版では11bit幅のデーターの下に5bit分の0を付加し、16bitデーターとしてUSBに送ります。
よってデーターは16bitで送りますがS-BUSの11bitから情報が増えるわけではないので結果的に11bit(=2048)分解能です。
なおラジコン送信機/受信機がスティック操作の変化を本当に11bit分解能で通しているかは不明です(ここで削られてたらどうしようもないのですが、どうなんでしょうね?)。

そして11bit版を使ってVelociDroneで飛んでみたところ・・・私レベルの感覚ではスムーズになった様な気もしますが自己暗示かもしれずよくわかりません。もうちょっとハイレベルな人に試してもらう必要があります。

実際にオンラインレースに出場されている方々の環境は8bitだったり11bitだったり様々だそうで、必ずしも11bitの人が勝つ訳でもない様です。

今回作成した高分解能版のファームとソースを下のリンクにアップロードしておきます(デバイス名の最後の’HR’はハイレゾのつもり)。
HOI-LinkHR20200615.zip

また受信機の機種によっては電源投入順序に制約がある問題(HOI-LINKをUSBに挿した後から送信機の電源を入れる順序でないと動作しない)が見つかったので修正しています。

なお以前はS-BUSに含まれる18ch分すべてをUSBに送り出していましたが今回のファームではチャンネル数を8bitに制限しています。
これには事情があって、ドローンシミュレーターで使うには問題ないのですが、Windowsの設定画面(下の図みたいなやつ)でみるとはアナログチャンネルは8chまでしか表示されず、一番大事なスティック操作が動いていない様に見えて気持ちが悪い上に、キャリブレーションができず、以前ARマーカーでドローン制御をしたときに影響があったので8CHにしてしまいました。

Windowsのこういう画面です

後半のチャンネルをデジタル値にしてやればいいのかも知れませんが、S-BUS信号は各チャンネルがアナログかデジタルかの見分けがつかないのでどれをデジタルにするか悩みます。で、実際には8chあればまず足りると思うので取り合えず8chまでにしています。
※もし18ch版必要な方がおられたらご連絡ください。

という事なのでもし8bitと11bitの違いを試してみようという場合は同じ土俵で比べるため下記のファームを比べてください。
HOI-LinkA20200614.zip ・・・8bit/8ch版
HOI-LinkHR20200614.zip ・・・11bit/8ch版 (上のリンクと同じ)

2020-06-15追記
HOI-LINKをPCに挿し送信機がONの状態でPCを立ち上げたときうまく動作しない問題が見つかったので修正しました。原因はUSBの通信が確立する前にSBUS信号を受けてUARTがオーバーフローしていたためで、初期化する処理を追加しました。
( 今回11bit版だけ修正しています。今後8bit版のメンテナンスは止めるつもり。)
HOI-LinkHR20200615.zip

HOI-Link:S-BUS→PC接続 完成

前回の続きです。前回は秋月電子のPIC18F14K50搭載基板をブレッドボードに挿して実験していました。今回は完成版として基板に収めるのでDIPパッケージで製作します。

まずKi-cadで回路図を書いて・・・

基板のパターンを作って・・・

片面基板なので表パターン(赤の配線)は実装時に導線で接続します。

CNCで削って基板を作ります。

FRISKケース(何年か前から大きくなった120%Booster版)に入れてみました。

寸法を合わせて作ったので当然ですがピッタリです。

ところでFRISKケースの場合ソケットを使ってマイコンを実装すると高すぎて蓋が閉まらなくなります。なので基板に直付けする前にブートローダーを書き込んでおきます(後からでも書けるけどブレッドボードに載せられる実装前の方がやりやすいので)。前に書いた9V電池書きこみ方式で・・・

006Pの9V電池書き込み方式

そして部品取り付け。
私のコントローラーはフタバのFASST方式ですが息子はFHSS方式なので受信機を取り替えられる様にします。最初はXHコネクタの3ピンを使うつもりでしたがL字型のポストが部品箱にありません。L字型でないとコネクタを刺す方向が縦になっておさまりが悪いのです。
代りにL字のピンヘッダがあったのでこれを基板にとりつけ、ここにRCサーボ等で使う3pinコネクタ(QIとかデュポンコネクタとか呼ぶやつ)で接続します。
但し逆刺しができてしまうのは要注意。

完成の図。

そして当初の目的であったドローンシミュレータ実行中。

参考のためマイコンに書いたファームウェアを載せておきます(例によってソースは試行錯誤の後が残ったままで汚いです)。コンパイルはMPLAB-IDEのバージョン8で行っていますが今となってはかなり古い環境だと思います。最新の環境でビルドできるかどうかは確かめていません。
また本来USB機器には固有のVID,PIDを書き込んでおく必要がありますがこのプログラムには適当な値を書いてあるのでそのまま使われる場合は自己責任でお願いします( 確率は低いですがもしVID,PIDがダブった機器を接続した場合に上手くつながらなくなる可能性あり)。
なおOpenStickLiteで使ったのと同じブートローダーから書き込む仕様でビルドしています。

HOI-Link:S-BUS→PC接続

PC上でドローンシミューレータを動かすとき、今までこんなコントローラーを使っていました。

10年くらい前、ムサシノ模型のモスキートモス号を作った時に練習用に買ったコントローラー

私レベルだとこれで問題ありません。しかし息子によると実物の送信機とは感覚が違うのでレースの練習はやりにくいとの事。
そこでトレーナーコネクタからPCに接続するインターフェースの購入も検討したのですが、その前に手元にあるものでなんとかできないか考えました。

まずトレーナーコネクタというのは送信機の裏についているこういう四角いコネクタ。ここからPWM信号が出ているらしいです。

右上の四角いコネクタがトレーナーポートです。

まずこのコネクタをどこで入手できるかというところから検討しなければなりません。またここから信号を取出せたとしてパルス幅をチャンネル数分カウントし、HIDデバイスとしてUSBに伝える処理も必要で何となく面倒です。

そこでRC受信機が出すS-BUS信号をマイコンで取り込んでUSBに伝えるのなら、OpenStickのファームウェアを少し改造して実現できそうです。しかもシリアル通信なのでパルス幅を数えるよりも精度が良い筈。但し受信機が一つ余分に必要なのと電波が出っぱなしになるのがちょっと気が引けますが、たぶんトレーナーコネクタから取り出す方式でも電波は出ているんではないですかね?(想像ですが)

こんな構造にしようと思います。

受信機はSBUSが出せれば何でもよいので、まずはこれで試してみます。

REDCON FT4X
ケースは外していました。

マイコンは秋月電子で買って放置していたPIC18C14K50搭載ボードです。このマイコンはOpenStickLiteでも採用しているので馴染みがあります。

そしてRAM領域の不足に悩まされましたが何とか動作し始めました。S-BUSは18チャンネル分のデータが含まれていますが私のT6EXで出せる6CHまでしか確認していません。あとで息子のT10Jで10chを試してみようと思います。


T6EXで実験中。ちょっと古いFASST方式ですが現役です。

実物のコントローラーだしケーブルをつなぐ必要もなく操作性は良いです。
何か他の事にも使えそうな気がします・・・今すぐ思いつきませんが・・ラジコン送信機でPCを操作する何か・・・
またPCの画面の前にカメラを置いてVTXで画像を飛ばし、ゴーグルで見ながらシミュレーターをやったらもっとリアルになるかも(かなりオタクだなぁ)。

現状はブレッドボードですが、この後ちゃんとした基板に載せ、ケースにも入れて完成させたいと思います。FRISKのケースあたりが良いかな?

どどーんはじめました。~その3~

今回のマルチコプターで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で動かしてみます。

S.BUSモニタ

Arduino MEGA2560でS.BUSをモニター。
ブレッドボード上のICは信号極性反転のための74HC00。

 

こんな感じでデータが出てきました。
送信機が6CHなので7CH以降が正しいかどうかは確かめられていません。また19番目のデータはFailsafeが働いたときに1になるはずですが、これも確かめていません。

S.BUS monitor

モニター中。

各データが11bitt幅なので0~2047が表せるはずで、どうやらニュートラルが1024の様です。
ところでCleanflightにも受信データを表示する機能があります。しかし今回のモニターとCleanflightの値が一致しません。そこで何ポイントか対応を取ってみました。

 SBUSモニタ Cleanflight
       102         943
       697        1315
      1024        1520 ←ニュートラル
      1435        1776
      1681        1930

グラフにすると・・・

SBUS-CleanFlight

SBUSとCleanFlightの読値対応

恐らくCleanflightの表示値は昔ながらのPWMサーボ信号のパルス幅に換算した値をμS単位で表示しているのだと思います。例えばニュートラルはS.BUSの生データは1024ですがPWMだと1520μSといった感じ。
ということでS.BUSの生の値にざっと0.625掛けて879.5を足すとほぼCleanFlightの値になる様です。