HOILog・・無人航空機の飛行日誌を自動化

最近M5Stackにハマっていました。
M5Stackというのはまあ簡単に言うとESP32マイコンにLCDディスプレイやバッテリーを含んだ電源管理回路などをつけて一式をケースに入れたものです。
私が購入したのはCore2という機種で外観はこんな感じ・・・

M5Stackは数年前から出ていて気にはなっていたのですが、値段がちょっとお高めだったりして手を付けていませんでした。で、今更ながら購入してみたら結構便利なんですよね。 特に電源管理回路とかイチから作るとそれだけで何かにハマりそうですが、これなら最初から入っています。

HOILog

という事で何を作っていたかというと「無人航空機の飛行日誌を自動でとるシカケ」です。命名:HOILog。
M5Stack Core2を選んだのは内部に時計(RTC)を持っているので時刻を記録し易いのです。

構造は ざっと下の通り・・・

RC受信機が信号を受けるとSBUSやCRSFプロトコルでM5Stackに伝えます。
(SBUSはフタバ系、CRSFはELRS等で使われるプロトコルです。両方対応しています。)
M5Stack側では信号が来たら飛行開始と判断し、マイクロSDカードに時刻を記録します。そして信号が途絶えたら飛行終了ということでまた記録します。

更にM5StackにはWiFi接続機能があります。これを利用してWiFiが利用できる環境であればASAKICHI先生作の飛行日誌システム( 詳細 はこちら) にもアップロードできるので、Googoleドライブ上のスプレッドシートに記録が残っていきます。

動作しているところはこんな感じ→Twitterに上げた動画

ハードウェア

M5Stack Core2の裏にピンソケットがあります。新品の状態ではここにフタを兼ねた気圧センサー基板がついていますが、今回は不要なので取り外して+5V電源、GND、UART2のRX/TXを引き出し、RC受信機に接続します。
ELRS受信器には入力(RX)信号があり、現在は使っていませんが将来何かに使うかもしれないので繋いでおきます。SBUS受信機の場合は入力信号がないのでM5StackのG14(UART2-TX)端子はオープンにしておきます。

ブレッドボード上に組んだセット(回路図にはないですが分かりやすい様に電源にLEDをつけています)。

ソフトウェア

M5StackはULFlow、ArduinoIDE、Micropython等の開発環境が選択できます。私はこの中から一番なじみのあるArduinoIDEを使用しました。
ところがやり始めて気づいたんですけど、コンパイルが結構遅いんです。ググってみると皆さん同じ問題により、PlatformIOに乗り換えられている様です。PlatformIOとはVisualStudioCode(以後VSCode) に入れるプラグインで、たぶん一言で言い表すと各種マイコンに対応した開発環境だと思います。
確かにPlatformIOでビルドするとかなり早くなり快適です。またベースがVSCodeなので入力補完があったり、キーバインディングをEmacs風に変更したりできて便利です。(余談ですがEmacs風キーバインディングにしたとき、VSCodeの仕様によりEscキーを使用できず、代りにAltキーを使う事になるのが弱点です)。

ところがPlatformIOで作ったスケッチが大体安定した動作になった頃、このブログで公開しようかなーと思い、その前に一旦ArduinoIDEに戻してビルドしたところ何だかうまく動作しません。(M5Core2ライブラリはどちらも同じバージョン(0.1.5)なのですが、もっと奥の方のライブラリのバージョン違いが原因かもしれません。)

とりあえずハマったのは下記の2点。
・タイマーの一旦停止後再起動する場合の動作の違い。
 timerStop(timerxx)で停止した後に再起動するとき、 PlatformIOはtimerRestart(timerxx) で再起動できていたのがArduinoIDEだと止まったまま。
 →対策:timerAlarmDisable(timerXX)で止めて timerAlarmEnable(timerXX) で復帰させる。ただし復帰直後のカウントアップが嫌だったので timerAlarmEnable(timerXX) 直前にtimerRestart(timerxx) も実行した。

・HTTPにPOSTした後同じオブジェクトでGETできない問題。
 Googleドライブへアップロードするとリダイレクト指定が返ってきます。このため一旦POSTでアクセスした後、今度はGETでアクセスするという2段階のアクセスが必要となります。そこでPlatformIO上では、HTTPClient http;で作ったオブジェクトを使いまわして接続していました。しかしArduinoIDEだとエラー(エラーコード400が返る)となりました。
色々試したところ、どうやらArduinoIDE上では GET→GETなら できますがPOST→GETはダメでした。
 → 対策: HTTPClient http2; の様にもう一つオブジェクトを宣言し、POSTはhttpオブジェクト、GETはhttp2オブジェクトで使い分けた。

使い方~セットアップ編~

  1. ArduinoIDEとM5Stack Core2の開発環境を準備する。私はこちらのページを参考にしました。
  2. この投稿の一番下からM5Stack Core2用のスケッチをダウンロードして解凍する。
  3. PCとM5Stack Core2の間をUSBケーブルで接続する。
  4. 「2.」で解凍したフォルダ内のHOILog.inoをダブルクリックするとArduinoIDEが開く。
  5. ArduinoIDEのツールメニュー→ボード名を”M5Stack-Core2″、シリアルポートを該当するポート名(不明な場合はWindowsであればデバイスマネージャーで調べる)に設定する。
  6. 書込みボタンを押して書き込む(若干時間が掛かります)。書き込みが完了したら電源ボタンを長押し(約6秒)して一旦電源を切る。
  7. 上の「ハードウェア」に書いた様にM5StackとRC受信機を接続する。
  8. 設定ファイル”hoilogini.txt”を作成して マイクロSDカードのトップディレクトリに置く。※SDカードの使用は必須です。
  9. 電源ボタンを押して起動!!

設定ファイルについて

SDカードのトップディレクトリに”hoihoiini.txt”の名前で作成します。
内容は1行に1パラメータを設定。1行は256バイトまで。行先頭にディレクティブ、その後1文字以上の空白を置いて設定値を書きます。#記号より右側はコメントです。

設定ファイルの例・・・

# HOILog 設定ファイル 

LOGFILE /hoilog.txt # File name
SCREEN 60 # Screen save time.(Seconds)
RCTYPE SBUS # SBUS or CRSF
RCJUDGE RSSI # RSSI or RCSIGNAL
RCRSSICH 16 # Channel number
RCRSSITH 1000 # Threshold value
RCCONTTIME 3 # Signal continue time
BAUDRATE 100000 # SBUS:100000 CRSF:420000
WIFITIMEOUT 20
SSID XXXXXXXX
PSWD XXXXXXXXX
LOGURL https://script.google.com/macros/s/XXXXX/exec
LOC1 ASO
LOC2 AMAKUSA
LOC3 KOSHI
MODEL1 Tyro99
MODEL2 Switch
MODEL3 Five33

各ディレクティブの説明:

LOGFILE:SDカードに残すログファイルの名前です。
SCREEN:指定の秒数イベントがないと画面を暗くします。ボタンを押したりRC信号が変化すると表示を再開します。値が0の場合は常に表示です。
RCTYPE:RC受信機の信号フォーマットがSBUSかCRSFかの指定です。
RCJUDGE:飛行中の判定をRC信号の有無で判定するか、RSSIで判定するかの指定です。受信機によっては電波が途絶えても最後の状態を維持するので単に信号が途絶えたかどうかでは判別できません。その場合でもRSSI(信号強度)がどこかのチャンネルに出ていればこれを基に判別可能です。
RSSICH:RSSI によって飛行中である事を判定をする場合、RCチャンネルの何番がRSSIを示すかを指定します。
RSSITH:RSSI によって飛行中である事を判定をする場合、 RSSICHで示すRCチャンネルの値が幾つ以上なら信号ありとするかを指定します。CRSFの信号範囲が172~1811、SBUSも大体その程度なので1000あたりを入れておけば大体OKだと思います。
RCCONTTIME:瞬間的な信号の切断やノイズによる入感を除去するため、
(立上り/下り共) 信号が何秒間連続で続いたら変化したと判断するかを指定します。
BAUDRATE:RC信号のボーレートを指定します。SBUSは100000固定。CRSFは420000がよく使われる値です(115200も使われる様ですが手元に確認する環境がなく、動作を確認していません)。
WIFITIMEOUT:WiFi接続時、何秒以内に接続できなかったらあきらめるかを指定します。
SSID:WiFi接続のSSIDを指定します。
PSWD:WiFi接続のパスワードを指定します。
LOGURL:Googleドライブにアップロードする為のGoogleApplicationScriptへのURLです。こちらのASAKICHI先生の動画の8分20秒頃に説明があるURLです。
LOC1~5:飛行場所を5つまで設定できます。M5Stack上のメニューでこの中から一つを選択してログに残せます。電源投入直後はLOC1が選択されています。MODEL1~5:機体名を5つまで設定できます。 M5Stack上のメニューでこの中から一つを選択してログに残せます。 電源投入直後はMODEL1が選択されています。

※LOCxやMODELxの値に日本語等の2バイト文字を入れるとどうなるかは試していません。

使い方~操作編~

電源を入れるとまずWiFiに接続した後、下の基本画面になります。
WiFiに接続できなかった場合はSDカードへの記録のみ行い、Googleドライブへのアップロードはしません。
この状態でRC電波を受けるとRCCONTTIMEに設定した値の秒数信号が続く事を確認後、SDカード、およびGoogleドライブのログに記録を残します。
Googleドライブへ記録する間、飛行状態表示部に「START UPLOAD」又は「STOP UPLOAD」と表示し、この間RC信号モニタや時計は動作しません。
Googleドライブへの記録は失敗すると3回までリトライします。最終的に成功したか失敗したかはSDカードに記録します。なお稀にですがサーバが正常に受付けて成功した旨の通知を返したのにM5Stackまで届かなかった時はリトライするので複数回の記録が上がってしまいます。その場合はSDカードのログを参照しながら手動でGoogleドライブ上のデータを修正する必要があります。

M5StackのCore2にはボタンがA,B,Cの3つ搭載されています(このボタンは物理的な接点ではなくタッチセンサーになっていて、押した感触が伝わりにくいですがちゃんとボタンとして機能します)。
基本画面ではボタンCを長押しすると設定画面に移ります。
ボタンA,Bには機能を割り当てていませんが、スクリーンセーバーからの復帰には反応します。

設定画面(MAIN MENU)
上から時計設定、電源OFF、機体選択、飛行場所選択、メニュー終了です。
反転文字になっているところが現在対象となっている行で、ボタンAを押すと上、Bを押すと下の行に移動し、Cを押すと選択されます。
「電源OFF」を選択するとシステムの電源を切ります。「EXIT MENU」を選択すると基本画面に戻ります。
時計設定、機体選択、飛行場所選択の各画面を以下で説明します。

時刻設定画面
ボタンA,Bを押すと反転文字になっている部分の値が上下に変化します。ボタンCは決定ボタンで次の値に進みます。年月日~秒まで進み、次にボタンCを押すと図に「NEXT」と表示された部分に移ります。ここではボタンA,Bを押すと「NEXT」、「SAVE&EXIT」、「EXIT:NonSAVE」と順に変化して行きます。それぞれの状態でボタンCを押すと以下の動作をします。
・NEXT:最初の「年」の設定に戻ります。
・EXIT:NonSAVE:時刻は変更せずにメインメニューに戻ります。
・SAVE&EXIT:内臓時計に設定時刻をセットし、メインメニューに戻ります。

機体選択
ボタンA,Bで対象行を上下させ、ボタンCで選択すると機体が選択されてメインメニューに戻ります。

飛行場所選択
ボタンA,Bで対象行を上下させ、ボタンCで選択すると飛行場所が選択されてメインメニューに戻ります。

ログ

実行後はSDカードのLOGFILEで指定したファイル名に以下の様なログが残っています。

TakeOff,2023-03-05 22:46:36                  ←離陸時刻
Upload success,2023-03-05 22:46:36 ←離陸をGoogleドライブにアップロード成功
Landing,2023-03-05 22:47:13 ←着陸時刻時刻
Upload success,2023-03-05 22:47:13 ←着陸ををGoogleドライブにアップロード成功

Googleドライブ上には(アップロードしていれば)次の様なログが残ります。

スケッチ

HOILog20230306.zip

※このソフトウェアを使用されてもし問題が発生しても責任は持てませんのでそのあたりはよろしくお願いします。

自動金ノコ

気がついたら前の投稿から3か月が過ぎていました。
この間も色々とやってはいたのですが、更新をサボってしまったんですよね。
で、最近作ったのはこれ。自動金ノコ。

鉄を切るなら高速切断機が早いですがアルミを切る場合や外で作業できない時、いままで金ノコを使って人力で切っていました。でも時間はかかるし疲れるんですよね。

そこでみら太さんのブログに以前書かれていたのを参考に作ってみました。

ほぼ手持ちのガラクタから作りましたがギヤードモーターだけAliexpressで購入しました。12V167rpm、ブラケット付きで¥1,103-。

早速動作中の動画です・・・まだセンサーもスイッチも付ける前の画像。

その後、切り終わった事を判別するリミットスイッチと・・・

ノコ刃が引っかかってロックした場合を検出するフォトインタラプタを取り付けました。3秒以上変化がないとモーターへの通電を止めます。

センサーの信号をこの箱の中のArduinoで読み、パワーMOSでモーターをコントロールします。ボタンはスタートとストップ。

電源入力はXT60コネクタなのでドローン用3セルリポでも動くかも。
(野外で使う事はないですけど)。

使わない時、こんな感じで立てておくと邪魔になりません(多少)。

RotorHazard

NonsayaDroneWorksにRotorHazardの記事が載っていました。

私はドローンレースを主催する事はありませんが、練習の時にはラップタイムを計測したくて、この記事と同じ様にARマーカーを試したりしましたがやっぱり時々読み取りミスが発生するんですよね。また、かつてこんな記事を書いたこともありましたがその後まったく手を付けていません。
そこでこのRotorHazardなるラップタイマーを試してみようと思います。

RotorHazardはRX5808レシーバーが受信したFPV信号強度をArduinoを経由してRasberry Pi(以下ラズパイ)に渡します。ラスパイはWebサーバーとして動作し、PCのブラウザーで接続して操作できます。
RX5808とArduinoは受信するチャンネル数だけ必要なので最終的には3セット欲しいところですが、取り合えず手元にある1セット分で、またラズパイ3がおすすめらしいですが無いので手持ちのラスパイ2でやってみます。

最初RotorHazardのリリース版(RotorHazard-2.2.0)だとエラーが出たのでRotorHazard-2.3.0-beta2で実行できました。ライブラリバージョンとのからみっぽいです。
まあ何はともあれ上手く動作している様なのでAliexpressにRX5808モジュールを追加注文して2チャンネルにしてみました。
なおシールドしておかないと離れていても電波を受信してしまうのでお菓子の空き缶に収めています。

そして庭でTinyレース。庭だとどうしても計測ゲート以外を飛んでいる時の電波を拾いやすくなるのでコース設定に工夫が必要です。

こうなると野外に出て3インチや5インチの機体で試したくなります。その為にはちゃんとした基板とケースに収めたいと思います。
基板はRotorHazardのサイトにガーバーデータが掲載されているのでこのまま作ればよいと思ったのですが・・・

どうやら最小のビアサイズが小さすぎて約500円の激安仕様では作れず、見積もり価格が3000円を超えてしまいます。また基板の元データが無くてガーバーのみなので簡単には修正できないのです。

ならば新たに基板パターンを作ってみようと思った訳です。
日本では大抵3チャンネルで足りるしArduinoNANOを載せるのも勿体ないので直接ATmega328のフラットパッケージ版を載せたらコンパクトにできそうです。
また屋外のインターネットがつながらない場所で使うならリアルタイムクロックも搭載すると便利です(ラズパイ標準ではリアルタイムクロックを持っていないので電源を切ると時計がリセットされるのです)。

そして10枚500円仕様で作った基板がこれ。 。

マイコンの上を跨いで受信モジュールを実装する立体構造。

今回メタルマスクは注文せず、紙をレーザーカットしたマスクでハンダペーストを塗ってみました。ちょっと塗り辛いけど何とかなります。もしかすると塗り辛いのはハンダペーストが乾き気味だったせいかもしれません。
ただ何枚も塗るだけの耐久性はありません。

メタルだとそうでもないのに紙だと何だか汚く見える。

そしてリフロー

やっぱりリフロー炉作って良かったですねー。
表面実装できると何かと便利です。

リフローの結果。
一か所抵抗が立ち上がっています。これがマンハッタン現象ってやつですかね。
ハンダペーストの塗りが薄かったのかも。ここはコテで修正しました。

そしてブートローダー書込み×3回。

基板の裏に書き込み用パッドを設けているのです。

次にファームウェア書き込み×3回。

一旦ファームを書き込めば以降のアップグレードはラスパイからできる仕様になっています。(試してませんが)

ここでミスに気づきます。RX5808のピン並びが逆になっていて裏返しでしか実装できません。ま、とりあえず裏返しに実装します。

ラスパイに載せて動作確認OK!
ラスパイはメルカリで格安だったラズパイ3にアップグレードしています。

ボタン電池が載っているモジュールがリアルタイムクロック。

先日のMP1854ENモジュールを取り付けてリポから電源を取れるようにしました。

ケースに使う空き缶を探しましたがちょうど良いのがなかったので、2.5mm厚のMDFをレーザーで切って箱を作り、ダイソーの0.3mm厚アルミ板(裏面テープ付き)を貼り付けてシールドしました。

ケースのアルミシールドは回路のGNDに接続。

電源の入り口

XT60コネクタで給電

蓋を一部切って電波を取り入れます。ここの開き具合で感度を調整する予定。

ここの空け具合は色々調整してみます。

なおWi-Fiのアクセスポイントがない屋外で使うときは 、ラスパイとPCとの間をアドホックモードでつなごうと思いましたが設定変更が面倒です。
結局リサイクルショップに行ったらWi-Fiルーターが¥770だったのでこれを使う事にしました。

Wi-Fiルーター。中古とはいえ安くなったもんです。

これで完成かな。今度練習する時に使ってみようと思います。

ところでいまRotorHazardのページを見たらこんな基板がリリースされています。Arduinoの代わりにSTM32を使い、マイコン1個でRX5808モジュール8枚(ドミノ倒しみたいに縦に実装!)を制御するという構造。進化してます。
しかし8台同時にレースできるんですね、海外って。

フライトコントローラーを自作してみる。~その7~ リフロー炉

細々と続けているフライトコントローラー自作の続きです。
部品が一通り揃ったのでリフローの準備を始めます。

フライトコントローラーはすべて表面実装部品を使うので手ハンダでは難しく、リフローで実装したいのです。
また35mm角の基板に部品を載せていくと両面実装になるので、ホットプレートを使ったリフローでは裏側実装のとき密着できない懸念があり、ここはやはりリフロー炉を使う必要がありそうです。

という事でオーブントースターを改造してリフロー炉を作る事にします。
内容的にはスイッチサイエンスさんのこのキットを真似して作ります。
(キットはずっと品切れなのでバラで部品を集めます)

まずオーブントースターを入手。リサイクルショップで適当なものを¥1800で買ってきました。TIGERのKAM-A130という機種で1300Wの品です。どれだけのパワーがいるか不明なので、足りないとどうしようもないので強めの機種を選びました。

ヒーターは3本備えていますが、この内2本は並列につながっています。常温で抵抗値を測ったところ並列状態の2本と単独の1本が同程度の値になっていて、2系統の配線が半分ずつのパワーを受け持つ様に制御しています。

前面にはタイマーと温度設定つまみがあります。タイマーはゼンマイ式で0まで戻ると「チン」となるアレです。温度設定つまみはバイメタル式サーモスタットらしき機構につながっています。
タイマーの方はそのまま安全タイマー(なにかトラブルがあって通電を続けても時間が来たら止まる)として使いたかったのですが、カバーが金属のツメを折り曲げて止めてあり、一度外すと元に戻せなくなりそうなので諦めました。
結局ヒーターに接続する電線だけを引き出して利用することにします。

回路はこれ。
オリジナルのスイッチサイエンスのキットはATMega328Pを3.3Vで動作させていて、これはたぶん温度センサーのMAX31855が3.3V動作の為だと思います。でも今回はAdafluitのMAX31855モジュール基板(秋月電子で入手)を使うので内部に5V→3.3Vレギュレータを持っているし、更にSSRは入力が4V以上となっているので5V系のArduino UNOの方が都合が良いのです。

温度を測定する熱電対は秋月電子で買ったステンレス管に入ったタイプでやってみます。
オーブンの内部に突っ込むので電線がピラピラしているよりもしっかりした棒状のセンサーを突っ込む方が保持しやすいと思ったのです(が、これは失敗だった事に後で気づきます)。

では改造です。
オーブントースターの筐体に穴をあけて電線を引き出します。穴の縁が鉄板そのままだと電線を傷つけそうなのでハトメを打ちました。 でもハトメの穴も案外ギザギザしているんですね。これだと効果が薄いので結局ハトメは外して他の方法を探します。

そして見つけたのがこれ「ダイソーのシリコーンマット」。230度までOKとなっています。これを適当に切り電線の周りに巻いて穴にツッコミました。


これで電線を傷つける心配はないと思います。

制御回路はまだバラックです。

ファームをGithabから取ってきてリフロー条件もそのままでArduinoに書き込みました。
そしてとりあえず何か焼いてみます。以前基板を発注したら間違って届いたものを使い、適当なランドにクリームはんだを塗って適当なチップ抵抗を載せます。


まずはソースコードに最初から書かれていた温度プロファイルそのままでやってみます。これは130℃まで上がるとで15秒待ち、その後230℃まで上がると目標を225℃に下げ、更に100秒経過するとすべてのヒーターを止めるという動作です。

ではスタートスイッチをポチッと。
最初の段階は1系統のみヒーターONで130℃を目指して温まっていきます。 そして130℃で一旦ヒーターが切れますがそれでも暫く温度が上昇し140℃まで上がりました。そして15秒のタイムアップ後2系統共ヒーターONとなり230℃を目指して上昇していきます。230℃に達するとヒーターOFFになり目標温度が225℃に下がるのですがまだまだ温度が上昇し240℃を超えてしまいました。基板からは時々プチッという音が聞こえてきます。その後225℃まで下がるか下がらないかの間に100秒の待ち時間が過ぎて一通りの処理が終了しました。

扉を開けると・・・

何か色が濃い・・・

結果・・・基板が黒くなっていて過熱しすぎっぽいですね。

左はリフロー前, 右がリフロー後。
過熱により黒くなりました。

ならば温度センサーがちゃんと温度を取れているのか、熱電対温度計と並べてヒートガンで過熱してみます。

結果、温度はまあ一致するのですが、ステンレス管に入った方は温度が伝わるのに時間がかかり、遅れて追いつく様な感じになります。
ステンレス管の熱電対を選んだのは失敗ですねー。さっき温度読みが240まで上がりましたがこれは遅れた表示なので実際はもっと上がっていたと想像できます。
まあちょっと予想はしていて、電線直接の熱電対が何本か手持ちが あるのでステンレス管がダメならこっちに変えようと考えていました。

電線直接の熱電対だと固定しずらいのでどうするかですが・・・3Dプリンタで使ったテフロンパイプがまだあった筈。これを適当に切ってその中に熱電対を通し庫内まで貫通させてみます。

次は制御回路と温度計、二つの熱電対を基板のほぼ同じ位置に貼り付けて動作させてみます。

こうすると制御回路と温度計の表示がほぼ同じで動作しているので測定自体は大丈夫みたいです。しかし通電を止めてから10℃くらい上がるのは変わりません。ヒーターからセンサーまで熱が伝わるのに時間がかかるのでしょう。

このファームは設定値に温度が達したら通電を切り、設定値よりも下がったら通電するというシンプル制御です。そこでPIDを追加してみたりと迷走したのですが結局止めました。最大温度に達する直前に過熱をゆるめるので温度の跳ね上がりはなくなりますが、最大温度付近にいる時間が長くなってしまうのが気に入らなくなったのです。

で、結局元通りのファームを使って温度プロファイルだけ調整する事に落ち着きました。

なお庫内でピロピロしない様、こんな感じでセンサーを固定しようと思います。この状態で基板に貼り付けた温度計と比べると、温度計の方が最大10℃くらい高い温度となるのでその分と跳ね上がり分を差し引いた上限値にします。

こんな感じで横からセンサーが出っ張ります。

更に何度か試してほぼ目途がたったので、次はいよいよフライトコントローラー基板に部品を実装しようと思います。

ArduinoIDEが保存するスケッチの改行コードが変わった?

最近ArduinoIDEでスケッチを保存し、gitにコミットする前にdiffを取ってみたら、数行しか変更していないはずなのに全行が不一致として表示されました。
どうやらArduinoIDEのバージョンを上げたのが絡んでいて、以前は改行コードがLFのみだったのが今はCR+LFに変っている様です。

リリースノートにはそのあたりの記述は見当たりません(英語なので見落としているかもしれないけど)。

そこでArduinoのサイトから旧バージョンのIDEを取ってきて色々試したところ、バージョン1.8.5から1.8.6になる時に変った様です。

Arduiooのフォーラムで検索すると次のやり取りが見つかりました。そのうち治してくれるんちゃう?っぽい会話みたいですが最新の1.8.12でも戻っていない様です。
https://forum.arduino.cc/index.php?topic=575025.0

致命的な問題ではないんですが、できれば統一したいところです。
どなたか、このあたりの経緯をご存じですか?

FPV LAPタイマーを作ってみる。

先日のドローンレースのタイムアタックではFPV LAPタイマーなる物を使っていました。これはドローンが出すFPVの電波を (ゲート近くの) 受信機が受けて通過した時間を測定するというもの。スタート前にこんな感じで受信感度を調整します。

これ作れないかなーと考えています。そこで手元にあってあまり使っていない受信機RC832のフタを空けてみました。ここから電界強度を示す信号が取り出せないかと。

中身はこんなの。高周波のフロントエンドはシールドされたモジュールになっています。

表側
裏側

このモジュールはおそらくこちらで紹介されているRX5808というモノだと思います。だとするとRSSIという端子が信号強度を出しているはず。電波を受信しながらテスターで当たってみると確かにその様です。

ならばこの端子から電線を引っ張り出します。

リード線をはんだ付けして・・・
プレートに穴をあけて・・・
電線を引き出しました。

引っ張り出した信号の電圧を測定しながらVTXを近づけたり遠ざけたりすると無信号時は約0.5Vで信号が入ると最大1.5V程度に上がります。アンテナを外した状態でVTXを部屋の端まで離しても信号が1.5Vに上がり切ってしまうので最も近づいた瞬間を検出するのは結構難しそうです。受信機全体をアルミホイルで包んでもまだ強力に受信しています。

当初は微分回路でピークを検出できるかと考えていましたが1.5Vに貼り付いてしまうとこの方法が使えません。そこで立上りと立下りの中間時刻を採用しようと思います。途中で速度が変ったり受信機のすぐ近くに墜落したりすると正確に測れないですが、まずは練習用には使えるかと。

またどっちみち信号が飽和するならとコンパレータでデジタルにしてしまってArduinoに入れます。オペアンプをブレッドボードに乗っけて実験・・・

まだ試行錯誤中の回路

まずはどんな感じで受信できるか試す為、 庭に持ち出して信号の立上りと立下りで割り込みが掛かった時刻(millis()関数の結果)をSerial.printでPCに表示させてみます。

・・・が、庭程度の広さだと一番離した位置でも電波を受信してしまいまうのでもっと広いところで試す必要があります。また近づいたときでも結構揺れがあり、H/Lを細かく繰り返していて判定が難しそうです。
本当は広いところでドローンが通過する時の波形をオシロで取りたいのですが、野外で使えるオシロを持っていません。
当面はソフト側で一定時間以上信号アリが続いたらドローンが通過したと判断する方式でやってみます。

・・・という事で練習場に持っていきました。ところが上手く受信できません。
調べたところRC832から引き出した信号線を間違って5V電源につないでいました。マズイ!
これくらいでは壊れないだろうと思いましたが・・・その後RSSI信号が出てこないし画像も受信できていません。
やっちまいました。

この後どうしましょう。折角ここまでやったのに止めたくないし、でもわざわざ受信機を買うか?とも思うし。。。
結局RX5808モジュール単体をAliexpressに発注しました。送料込みで¥1070円、あーもったいない。


どどーんはじめました。~その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の値になる様です。

フライトシムのモーションシミュレータ化~5~

モーションシミュレータの座席にラダーペダルを固定するため、金具を切り貼りしたいのですが、先週の雨に続き今週末も台風がやってきて降ったり止んだりしているので外での作業が出来ません。
そこで近所のホームセンターハンズマンにある工作室で金具のカットと穴あけをしてきました(工作室での写真は撮り忘れました)。
切り終えたのがこれ。

Mostionsim6

座席に取付ける金具(切ったあと)。
3mm厚で幅40mm、各辺270mmのL型金具(1本170円)。
元々は建築用みたいです。

現状の座席にも同様の金具をフレームとして使っており、これに溶接する予定ですがハンズマンの工作室でも溶接はできないので晴れたら庭でやろうと思います。が、雨が止んだかなーと思って準備を始めるとまたポツポツと降ってきます。

てるてる坊主

 

晴れるのを待ちながら制御基板の続きを作る事にします。先日故障した基板切削CNCも調子よくなっており切削完了。

MotionSim6-2

切削を終えた基板の両面テープをスクレーパーで剥がします。

部品を実装しました。(一か所回路図段階でミスっておりパターンを修正しましたがこちらの面からだと見えないのでナイショ)

MostionSim6-3

実装も完了。

これくらいの配線量だとユニバーサル基板の方が手っ取り早いかもしれません。でもそこは趣味の世界です。 またArduino標準のピンヘッダ配置はユニバーサル基板がピッタリ納まる様になっていないという問題もあります。

基板を作った後で気づいたのですが、手元の古いArduinoUNOには無い端子を使う配線になっていました。I2C通信で使うSDA,SCL端子は現在のUNOでは端子が追加されて2か所にありますが古いUNOには1か所しかありません。

MotionSim6-4

ArduinoUNOのピンヘッダ新旧比較
(左の新しい方はバッタ物ですが・・・)
左下のAD4,AD5端子がSDA,SCLと兼ねており昔からある端子です。これに対し今のUNOでは右上にも同じ信号がSDA、SCLとして追加されています

仕方ないので新しい方(バッタ物)を使う事にします。

とかやっている間にAliExpressに何となく注文していた基板が届きました。
1枚108円で送料無料です。こんなのを使うのが一番簡単でした(いまさら今回のには使いませんが)。

MotionSim6-5

Arduinoシールド用ユニバーサル基板

 

何はともあれ基板が出来たのでブレッドボードを取り外して交換します。
だいぶスッキリしました。
基板上のトグルスイッチはマニュアルとオートの切替です。オート側にするとPCから仮想COMポート経由で制御でき、マニュアルにしておくと基板上の4つのタクトスイッチで動作させる事が出来ます。

MotionSim6-6

ブレッドボードから基板に変更してスッキリした図

そうこうしている内に雨が止んだ様です。日没まであまり時間がありませんが少しでも溶接作業を進めます。
といっても2本を接合しただけで日が暮れました。座席のフレームとの接合は後日行います。

MostionSim6-7

2本を接合。

少しずつしか進みませんが続けていきます。

フライトシムのモーションシミュレータ化~4~

前回FlightSimulatorXからデータを取出して座席の傾きを計算しArduinoに送るところまで来ました。引き続きArduino側でのスケッチを書いていきます。

PCからArduinoに送るデータフォーマット

PCからArduinoへはシンプルに下のフォーマットでデータを送ります。

ピッチ,バンク\n

第一フィールドが座席のピッチ、第二フィールドがバンク角で、それぞれ’度’単位の角度を10倍した整数で表します。10倍しているのは小数以下一桁までを整数で表し、少しでもArduino側の計算負荷を減らす目的です。

Arduino内での処理

Arduinoのスケッチではシリアルポートを定期的にチェックし、1行分のデータが来たらピッチとバンク角を取出します。そしてこの値を元にリニアアクチュエータの目標とする長さを左右それぞれ算出します。

また加速度センサーの値も定期的にチェックします。加速度センサーは座席裏側に取付けてあるので座席の傾きを示しており、この値から現在のリニアアクチュエータの長さを推定します。

あとはモータードライバーに対し、目標長と現在長の差が無くなる方向に動かす信号を送ればアクチュエータが動作して座席が目標角度になるという算段です。

実際にはアクチュエータが停止状態から動き出す時はPWMで徐々に加速し、目標に近づくと徐々に減速する事でなるべくスムーズな動作を目指しています。

なお当初、加速度センサーは座席の背板付近に取付けていました。しかしこれでは重力加速度による傾き検出以外に本当の加減速も検出してしまいます(軸から遠いので特に上下には大きく動く)。今回は傾きの情報だけ欲しいのでなるべく軸の近い場所に移動しました。

動かしてみる。

まだモニターもペダルもコントローラーも取り付けていませんが、とりあえず動作させてみます。
PC側でFSXを起動し、DOS窓から先日作ったデータ抽出プログラムを起動し、リダイレクトで仮想COMポートに送ります。

動画で・・・

最低限のところが動いた感じですが、なかなか楽しいです。
ペダルやコントローラを取付けていきます。

フライトシムのモーションシミュレータ化~3~

引き続きソフトを作っています。

SimConnectから得られる値について

モーションシミュレータではシミュレータ世界で体が受けるであろうGの方向を実世界の重力の方向に合わせる様に制御しようと思います。例えば離陸のために加速する時は後ろ向きにGが掛かるので座席を上向きに傾ける事で体にそれっぽい力が加わります。しかし以前の投稿で体にかかるGの方向がSimConnectから上手く取れない話を書きました。

SimConnectから得られる変数に「ACCELERATION BODY X(同様にY,Z)」と「ACCELERATION WORLD X(同様にY,Z)」という変数があります。
ドキュメントに詳しい説明が見当たりませんが、名前からするとこれらが体にかかる加速度およびワールド座標での加速度かと思います。しかしこれらの変数を表示させても妙に小さな値ですし思った様な変化をしていません。

下の4つのグラフは出来るだけ水平を保って右旋回を続けた時の変化です。
一番上のグラフは機体のピッチ、ロール、ヘディングを表します。単位はラジアンでヘディングの0(又は2π)は北を示しており、ノコギリ状のグラフになっているのは右方向に2回転した事を示します。

2番目のグラフは各方向への速度(単位はFeet/s)を示します。東西がvX、南北がvZなのでこの二つが90度位相がずれたサインカーブをほぼ描いており回転している事が判ります。

そして3番目のグラフが加速度を示すと思われる変数「ACCELERATION WORLD X(及びY,Z)」の値ですが、何を示しているのかよく分かりません。

そこで4番目のグラフに速度から算出した加速度をプロットしてみました。横軸が1秒ステップなので2番目のグラフの値を元に、それぞれ一つ前からの差を計算すればFeet/S2(フィート/毎秒毎秒)になるはずです。これだと最大120feet/S2で速度を90度ずらしたそれっぽい波形になっています。

・・・という事で速度の変化から計算した加速度を用いる事にします。
なお、この加速度に重力は含まれていないのでY軸方向に32.174feet/S2(=1G)足した上で機体座標に変換して座席の姿勢を決める事にします。

SimConnectの座標

SimConnectが出す値を調べた結果、各座標は下の様に表しているみたいです(座標変換するとき何度もこんがらがるので覚書き)。

MotionSim4-2

SimConnectの座標

以上で求めた座席の傾きをUSBのCOMポートに書き出し、後はArduinoでの処理となります。