これまでのプログラムは1個のタイマーを使いタイマー割り込みハンドラ内で割り込み周期を段階的に変えることでモーターの駆動パルスを作っていたので制御が粗くなってしまっていた。
そこで今回はやり方を変えて、タイマー割り込みの周期は一定とし代わりにモーター制御用のパルス生成器を作ることにした。
パルス生成器の構造はシンプルにアキュムレータ方式とした。アキュムレータを acc とすると、accは毎クロック acc = acc + αで更新される。また、acc が閾値 N を超える場合は0に戻す。この時パルスが1つ出力される。下図はaccのαが1, 2, 3の場合のaccの軌跡を表している。現在回路は100MHzで動かしているのでNは100_000_000に設定する。すると、αが1の場合1秒に1回パルスが発生し、αが2の場合1秒に2回、αが3の場合は1秒に3回発生する。つまり、αはパルスの周波数を設定することになる。今回のモーターの場合パルス12発で1回転するので、モーターの回転数を RPS (Rotate Per Second)で表すとするとαは 12×RPS になるがこの変換はIP内で行うことにした。つまり、ソフトウェアは秒当たりの回転数を何らかの方法で算出して設定すれば良い。
次に回転数の生成だが、前回採取した波形から起動時の立ち上がりの部分(左下の緑色の曲線)を式化してそれを使って回転数を決定してみることにした。
色々試してみた結果、y = ax^4、a = 1.97499e-11 を使うことにした。 多項式にすると計算に時間が掛かるのでなるべく単純な式にした。タイマーの割り込み周期は1msecにして、割り込みハンドラで y = ax^4 でモーターの回転数 RPS を計算してIPに設定する。 aの値が1.97499e-11とかなり小さいので固定小数演算にすると32bitを超えてしまう。そこで計算はfloatで行うことにした。zumi32-gccはfloatも使えるのでfloat演算自体は問題ないが、zumi32の演算用リソースとしてはバレルシフタのみなのでコンパイル後のマシン語のステップ数と演算に要する時間が気になるところだ。
そこで、コンパイルしたマシン語列をシミュレーションで流してみたところ、割り込み処理時間は約28usecであることが判った。タイマー割り込み周期は1msecにするのでまったく問題ない。(シミュレーションではタイマの割り込み周期は50usにしている。)
で、これを実機で動かしてみたのだが結果はNGだった。起動直後に脱調してしまう。aの値を小さくしたりx^4をx^2にしたりして立ち上がりを遅くすると動くのだが最大回転数は50 [rps](3000 [rpm])が上限だった。そこで、モーターのdrv_A, drv_B, drv_Cの駆動パターンを変えてみることにした。具体的には従前は 011、110、101のパターンを繰り返しており常に2つのコイルを励磁するようにしていたのだが、これを001、011、010、110、100、101と1コイルのみが励磁されるパターンを入れることにした。 これにより今までは12パルス@1回転だったのが24パルス@1回転になるので、IPの設定値を12倍している部分は24倍に変更した。 この他にaの値を色々調整したりした結果 120[rps](7200 [rpm])まで動くようになった。 ヤッタ!!
以下はロジアナで採った波形だ。
Sensorの周期が120Hzなので7200[rpm]で回転していることが判る。
ということで、zumi32でモーターを制御して7200 [rpm]で回転させることが出来た。また、zumi32のプログラムでもfloat演算を問題なく使えることを確認することが出来た。\(^_^)/