2020年1月29日水曜日

小ネタ

 国際単位系ライブラリを、少しずつ充実させながら試用してる(もっと言えば、衛星追尾カメラを作り直してる)。

 とりあえず、モータの制御部分を書き始めてる。目標値が方位・仰角で与えられて、現在のモータの位置と比較して誤差をフィードバックする、という流れ。インターフェース部分ではTurn, Radian, Degree(およびそれらの角速度)、といった、複数の単位系が組み合わさるので、型で単位を拘束できるのは便利。例えば、ヒューマンインターフェース部分はDegree、内部処理はRadian、モータードライバに渡すのはTurn、みたいな感じ。
 ただ、モータードライバの低レベル部分はステップ数で計算するので、TurnとStepsのやり取りが面倒。
 GainやOffsetの入出力は同じ単位系である、という拘束があるので、モーター位置(ステップ数)→モーター位置(ラジアン)への変換とかで無理が生じてしまう。ステップ数をラジアンに型変換してからGainを適用して実際にラジアンに補正するか、ステップ数にGainを適用してからラジアンへ型変換するか、どちらにしろ「今はその単位ではない」状態を経由する。
 もともと、GainやOffsetは単純な1次関数による補正を想定していたので、Gainを経由すると単位が変化する、といったことは想定していなかった。

 そもそも、モーターのステップ数からラジアンへの変換、とかは、疑問の余地も無くprivateな処理なので、型による単位の拘束が必要か、というと、そんなことはないわけで。int32_tとかfloatとか、好きなスカラ型を使えば済むわけで。
 しかし、やはり入力や出力がSI_units::Radian<T>やSI_units::Turn<T>で拘束されているなら、中間処理でも同じように型拘束を使いたい……とも思ってしまう。
 Gainに関しては、単純な補完であれば乗算で足りるけど、Turn-Stepsの相互変換とかだと、Turn→Stepsの場合は乗算、Steps→Turnの場合は除算、みたいな使い分けが必要になる。ただ、普通Gainは乗算を想定するはずで、それが除算にも使えるというのはなぁ。

 便利なところでいうと、例えば回転数のリミット値を決定したい場合に、Rad_per_sec<float> max_turn_speed(Degree<float>(360) / Second<float>(5))みたいな感じで、「1回転するのに5秒かかるのが最高速度です」みたいなのを、直感的に設定できる。
 float max_turn_speed_rad_per_sec = 360 / 5 / 180 * 3.14みたいな感じで同じ値を作れるけど、それぞれの数字がどんな意味を持つのかが直感的に理解しづらい。と、思う。変数名も長いし。
 とはいえ、最近の開発環境だとオートコンプリートがデフォだし、変数名が長いのはあまりデメリットではない、というのが通説だしなぁ。もっとも、max_turn_speed_deg_per_secとmax_turn_speed_rad_per_secみたいな、接尾辞で区別してたりするとオートコンプリートで知らない間にバグ埋め込んでる危険性もあるけど、そういうのは設計の問題だし。

 まぁ、もう少し試行錯誤すればいい感じのやり方が見えてくるはず。

***

 とりあえず、方位軸だけ試しにP制御を実装。それなりには動く。が、モータードライバに制御を戻してやると、台形制御でキッチリ制御されるので、キビキビ動く。
 L64x0は追値制御ができないのが面倒。CNCとか3Dプリンタとかジンバルとか、そういう用途だと常に目標が変化するので定値制御専用だとつらい。
 しかし、昔衛星追尾を作ったときは定値制御でもそれなりに動いてたんだよなぁ。たぶんRFだったので制御誤差が見えなかっただけだと思うけど。

 とりあえず、もう少し現実に即した制御をできるようにして、AziEleの向きを受け取って追従できるようになれば、モータードライバの制御周りは終了。
 あとはTLEの計算だったり恒星の計算だったり、そのあたりを実装したり、設置姿勢誤差の補正を組み込んだり。
 まぁ、暖かくなるまでには作れるだろ。どうせ冬の間は寒いから外に出せないし。むしろそれまでに飽きないように(&使い方を忘れないように)するほうが大変か。

 最近小ネタばっかりなのでもうちょっとマシなネタを確保したい。。。

0 件のコメント:

コメントを投稿