【STA23】Teensy Interval Timerではまった<Priorityと現合調整>

スキーオフシーズン用の計測では、歩行とかインラインスケートをやる予定ですが、運動サイクル周期がスキーより速いので、RTKでは、取り逃すデータがでてくるので、そこをIMUで補間しないといけないので、BNO055をしっかりと測定できるようにしないといけません。
※注意:BNO055のAdafruitライブラリのフルパラメータ測定では、変換速度が5msecかかるので、測定時刻がその間ということで、センサとしては、時間精度が悪いです。加速度測定で、5msecも取得時間がかかっていては、使えない用途がたくさんあるので、BNO055の用途は遅い現象専用です。私の場合は、人間の運動なので、遅いですが、自動車、機械などの動作だと厳しいと思います。仕様でもEuler角は25Hz上限なのでそのレベルです。
※今回は、基板もガチガチ小型化してしまって、スペースに余裕がないのですが、スペースに余裕がある場合は、インターバルタイマーを使う弊害(その他関数への障害)ゼロで、超正確(1ppm)クロックが得られる外付けTCXOタイマーを取り付けることをお勧めします。4年前に苦労して開発した高精度クロックがあります。インターバルタイマーを使っても所詮12ppm程度の精度しか出ませんので、苦労して損しました。
【パワーメーター2019】割り込みタイマー精度測定結果<TCXOは計測の必需品>

●Teensyの時間関係の機能は、こちらにあります。
https://www.pjrc.com/teensy/td_timing.html


●インターバルタイマーにした
 スキー用のシステムは、ソフトタイマーで、GPSのタイムパルスを記録しておいて、後で補正するつもりでしたが、BNO測定周期は、プログラムLOOPの成り行きまかせでしたので、40msec±10msec程度のばらつきがありました。IMU単体として計測誤差としては、NGなので、精度向上のためにHARDWAREタイマー割り込みを使ってみました。

●Teensy解説では、危ないから高度なプログラミングが必要と書いてある。
https://www.pjrc.com/teensy/td_timing_IntervalTimer.html

▼主な被害は、変数が化けるらしい。

●やはりハマった
タイマー割り込みでBNO055のライブラリーでサンプリングすると計測モジュールだけで5msec食うので、その間、システムを止めてしまうので、RTKのサンプリングとログ出力がめちゃくちゃになってしまいました。初期数分はいいのですが、30分くらい経過するともうどうしようもないほど乱れます。ハングしてくれればいいのですが、出力はどんどんしてきます。
上の表が最初の正常な出力、下の表が乱れまくった状態、これでもかというほどデータが飛びまくってます。悲惨な状態でめったにみられない惨劇でした。

●対策が大変でした。

ソフトタイマーに戻そうかとも思いましたが、Teensyの解説をみると、Priority指定がありました。
https://www.pjrc.com/teensy/td_timing_IntervalTimer.html

主要な関数の優先順は、128番目以内なので、時間を食ったりする割り込みは、優先を後回しにすべきだと書いてある。ということで192番目に設定しました。
myTimer.priority(number);

Set the interrupt priority level, controlling which other interrupts this timer is allowed to interrupt. Lower numbers are higher priority, with 0 the highest and 255 the lowest. Most other interrupts default to 128. As a general guideline, interrupt routines that run longer should be given lower priority (higher numerical values).

一行追加しただけ   myTimer.priority(192);//BNOreadの優先をさげておく
コードはGISTに備忘録しておきます。
https://gist.github.com/dj1711572002/849de59a81493f47fb918efe198fd136

◆Priorityを下げても、別のトラブルが次々と発生してモグラたたき状態になりました
①Priorityを下げると、逆に無視されて、データ抜けが発生しました。モニターのSerial.pirntfのほうが優先されて、データが1個必ず消えてしまいました。
②上記①の対策として、モニター出力で、BNOデータを出力するのに工夫しました。モニター関数に入ったときのBNO測定データで出力してない新しいものだけSerial.print出力するfor ループを作って、逃げたのですが、
③何と、forループが2回回るはずが、3回まわって、未だ測定してないデータがでてきました。forループを回している間に、割り込み関数内で、カウンタをいじってしまっているようです。
④そこで、forループに入る直前に、別の変数を作って、forループ用のカウンタ類を代入して、割り込み関数が書き換えても、ループ内のカウンタが変化しないようにしました。
これで、何とか落ち着きましたが、1行でもSerial.printをいれたりすると、バランスが狂って、おかしくなりますので、現合もいいとこで、統計的評価しないとプログラム使えるかわからないという代物になってしまいました。割り込みタスクを管理するのは、AdvancedProgrammingとは
よく言ったもので、相当詳しくないときちんとしたプログラム作れないということで、素人は避けたほうがいいと言われていることが実際に体験して納得しました。

※BNO055プログラムデバッグのTIPS
センサを動かさないとサンプリング状態がいいかどうかわからないことが多いので、
 動かすのですが、これが大変なので、私の場合は、eX[],eY[],eZ[]の測定データに
 millis()を代入して、Euler角の代わりに測定時点の時刻を代入してます。こうすれば
 データがキチンと配列の順番で正確な周期で測定できているかも判りますので、デバッグの
 効率があがります。プログラムができてから、実験で、センサの値を評価すればいいので
  プログラムデバッグ中には、実データは必要ありません。

●確認実験結果
劇的に改善しました。

不良データ 不良率
priority指定なしの場合 5763個/109829個中 5.2%
priority 192番でその他
変数保護とタイミング調整して
1個/44000個 0.003%

ほぼ完ぺきにデータ飛び抜けが無い状態になりましたが、絶対時間精度は、マイコンクロックが
12ppm程度なので、時間とともにずれていきます。だいたい、1分で1msecずれますので、40分で1周期狂うので、データ測定時間は、30分以内とします。TIMEPULSEで補正しようとしたのですが、インターバルタイマーをリセットすると1周期データが欠けてしまう現象が断念しました。1回だけスタートさせて後は、マイコンクロックの精度でインターバルタイマーが回るだけなので、ソフトタイマーのほうがうまく作れば、累積誤差は減るかもしれません。

●以後
未だ、全て完成したわけではないので、完成してから、今回のPriorityの影響が良かったのか
悪かったのか、評価していきますが、割り込みの優先順がすごく効くということはわかりました。
※2023年4月27日追記
やはり、弊害が未だありました。SD書き込みでハングします。怪しいのは、モニターとSD書き込みを動作させると20msecくらい食うので、割り込みタイミングとぶつかる確率が上がるのかもしれません。SD中は、モニターを止めるなど対策してみます。いずれにせよ、インターバルタイマーを採用するとプログラム全体を現合で調整しないとちょっとした書き換えでもハングするという課題を背負わないといけなくなります。

●恒久策
最初からなら、外部発信機をとりつけて、ピン割り込みでBNOの測定タイミングを発生させれば、インターバルタイマー関数を使わないので、プログラム内で他の関数に迷惑をかけることもなかったと思います。スーペース的に外付けクロックが入らないのですが、どうしてもだめだったら春夏で、基板改造して外付けクロックをいれます。
外付けクロックの威力は、こちらの記事にあります。

【パワーメーター2019】割り込みタイマー精度測定結果<TCXOは計測の必需品>

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です