brickOSは、疑似PWM(Pulse Width Modulation)制御で、モーターの出力を調整しているらしい、ということは分かっていたのですが、具体的な制御方法や制御の遅れ時間が不明であったため、自分で調査した結果を下記にまとめました。
以下にRCXの出力ポートの波形を示します。
ちなみに出力ポートの電圧は600Ωの抵抗で終端して測定しています。
SPEED = 64 |
---|
SPEED = 128 |
---|
SPEED = 192 |
---|
波形からスピードに比例してモータを駆動する(=電圧をHIGHにする)時間が長くなっていることが見て取れます。
ちなみに実際のモーター駆動では 1ミリ秒単位の短い周期で電圧が急上昇と急下降を繰り返しているわけではありません。
その説明のために、次にOUTポートの出力をオープンで測定した波形を示します。
SPEED = 32 |
---|
SPEED = 64 |
---|
これは出力ポート内部のキャパシター(コンデンサー)の効果で、出力電圧が平滑化されたことによるものです。
実際にモーターを接続したときも、このキャパシターとモーターの内部インダクタンスの効果で、モーターにかかる電圧は(ミリ秒単位の測定時間から見れば)滑らかに変化します。
しかしながら一般的なPWM制御ではON-OFF(HIGH-LOW)の周期を一定に保ちながら、ONとOFFの時間の比(デューティー比)を変化させる方法が一般的ですが、brickOSの(疑似)PWM制御ではON-OFFの周期が定まっていません。
そこでソースコード (kernel/dmotor.c) を調べたところ誤差拡散法を応用して、疑似PWMの波形を作り出しているらしいということが分かりました。(ソースコードに delta という変数名が出てくることから開発者も誤差拡散法を知っていて意識したものと思います。)
誤差拡散法は「福引の補助券」の例え話で説明することができます。
ある商店街で1000円の買い物をすると1回抽選機を回せる福引があったとします。もし福引の補助券がなければ、1100円の買い物を10回しても端数の100円は毎回切り捨てられて10回しか抽選機を回せません。しかし100円の補助券があれば、11回抽選機を回すことができます。 ちなみに「1000円未満の端数」のことを情報工学の用語では「量子化誤差」と呼ぶことができます。そして、この量子化誤差をキャリーオーバーさせて拡散させるというのが「誤差拡散法」の原理です。
brickOSの疑似PWMも同じ原理です。具体的には1ミリ秒毎の割込み処理でspeed(delta)の値をsumに加算します。sumの値が255を超える(オーバーフローする)毎に出力ポートを1回(1ミリ秒間)、HIGHに制御しています。
したがって、speed(delta)が 1 のときは 256ミリ秒に1回、speedが 2 のときは2回、・・・、1ミリ秒のHIGHのパルスが出力されます。
ちなみに、speedが 255 (MAX_SPEED) のときは、常にHIGHが出力されるようにソースコードで細工されています。
と、ここまで説明して良いことずくめに思える誤差拡散法による疑似PWMですが、一つ問題があります。制御に対して出力が遅れることです。量子化誤差が積み重なって初めて出力が得られるため仕方がないと言えば仕方がないのですが、出力の遅れ時間が不定で読めない、というのは困った特性になります。
ということでどう工夫すれば良いか分からないのですが、とりあえず制御の変化の開始位置では、sum に 255 を放り込んで、すぐに最初のパルスが得られるように修正すれば制御の遅れ時間の問題は改善するのかな?と考えています。
2008.06.09 追記
ある方から、brickOSのモーター制御方法は『ΔΣ(デルタシグマ)変調』ではないかというご指摘を受けました。
調べてみたところ確かに指摘の通りなので補足します。が、量子化誤差・・・の説明は当たらずと言えど、遠からずだと本人としては悦に入っていますので、前の文章はそのまま残しておきます。^_^;