2016-05-20 18:10 | カテゴリ:PIC応用回路
RCサーボの制御が出来るようになりました!


PWMでRCサーボの制御が出来ないかとの御質問を頂きました。
しかし、このPIC回路では、PWMの処理速度が速すぎて、RCサーボの制御には向いていないことがわかりました。
でも、せっかくなのでこれを生かしてRCサーボも制御したい、と言うわけで、ソフトを検討してみました。

RCサーボの制御は、繰り返しパルス信号を与えます。その信号のONの時間を1500マイクロ秒(usec)を中心として、プラスマイナス500usecの範囲で、変化させるとそれに応じてサーボが動作する仕組みです。
このONとなっている時間は結構シビアに与えないと、サーボが微振動したり、誤動作したりします。
このパルス信号を繰り返して与えるのですが、その繰り返しの周期の精度は、それほど高く求められません。
せいぜい、10-20msecの繰り返しでよいでしょう。

先日から製作しているソフトは、LEDの点滅と言う、人間の目で見て、かなり自由度の高い、処理をしていますので、プログラム自体の動作時間(分岐や、処理の長短)は、ほとんど無視できるくらいのものです。
しかし、サーボの制御は、数usec位の分解能で制御されますので、プログラムの動作時間で影響される事が十分考えられます。

したがって、RCサーボの制御をこのソフトに組み入れるには、タイマー割り込みで、かなり正確なON時間を出力し制御する必要があると考えました。

検討した方法は以下の通りです。
LEDのカウント処理と同様に、定期的にONの時間を読み出し。それをタイマー割り込みにセットして、RCサーボ用のポートをONにします。
タイマー割り込みが発生したら、ポートをOFFにします。
タイマー割り込みは、かなり精度良く設定できますから、サーボをうまく制御できると思います。

このプロセスのポイントは、タイマーをセットして、割り込みの発生を待っている間は、処理を中断(ループで処理を待っている)して、割り込みが発生したら、ポートをOFFにして、次の処理に移るという事です。
通常、タイマー割り込みは、割り込みが発生するまでは、別の処理を行って、割り込みが発生すると、その処理をするという考え方ですが、今回、割り込み発生を待たずに先に処理を進めてしまうと、次のタイマー処理に進んでしまうと、タイマー0が一つしかありませんので、不都合が生じます。
幸い、サーボの制御で待たなければならない時間は2-3msecですので、この間は処理を進めないで、タイマー割り込みを待って、一つのサーボ処理を完了させてから、次に移るとしても問題ないと判断しました。

この方法ですと、LEDと同様に、RCサーボを複数制御できると思います。

と言うわけで、先日のプログラムをいじって、当初のアイデアを盛り込みました。
ところが、上手くありません。

問題点は

PICが動作すると、サーボが動いて、振り切ってしまいます。パラメータを変えても同じです。

色々なパラメータを与えてもサーボが動作しますが、何故か一方へ振り切ってしまいます。
恐らく、パルスのH時間が長すぎると思いますが、TMR0に直接数値を書き込んでいますので、パルス幅が長くなるわけは有りません。
散々悩んだ末、原因が分かりました。
LEDのON/OFFのルーチンを使用していましたが、これは「負論理」です。ONで、LにOFFでHになります。
うっかりしていました。
ここは、ONとOFFを入れ替えて、サーボは振り切らないで、動作範囲の途中でちゃんと停止するようになりました。
やれやれです。

次に、中立となるはずのパラメータを与えてみました。
しかし、中央ではなく、かなり端にずれています。
値を返ると、それなりに動作するのですが、一方では振り切れます。
どうやら、信号の中央の位置がずれています。計算では中央は、ほぼ1500usecにセットしてあります。
そこで、オシロで実際の出力波形を調べてみました。
なんと、2500usecほどあります。
そんなバカな!
で、プログラムリストを見てみると、原因がありました。
LEDのON/OFFルーチンに、1msecのDelayが入っています。

Prog001.jpg

自分では、何気なしに、入れてしまった意味の無いDelayです。
このために、ちょうど1msecの余分な時間が入ってしまったのでした。

というわけで、これらを修正し、ちゃんとRCサーボが動作するようになりました。

下記のHパルスを得る為のTMR0に指定するパラメータは、実測で

2000マイクロ秒 = 100
1500      = 139
1000      = 178

となりました。



実際のプログラムがこれです。
この部分で、サーボ設定値を読み出して、タイマー割り込みをセットし、ポートをONに。

そして、tmr0_int()で割り込みが発生したところで、ポートをOFFにします。

Prog002.jpg

また、タイマー割り込みを使用するための設定もここで行います。
プリスケーラは1/64にセットしました。
TMR0の詳しい使い方は下記をご覧ください。

Prog003.jpg

サーボのパラメータを切り換えるSW0の読み込み部分はこれです。
SWではなくて、内部のプログラムで動作させる際は、ここに0-100の数値を入れてください。

Prog004.jpg


また、このRCサーボの設定を読み込んで判断するメインルーチンは、この様に追加しました。

Prog005.jpg

と言うわけで、完成です。
今回は、PIC16F876を使用しましたので、ポートは、A(6),B(8),C(8)あわせて、22+1(PWM)個ありますので、本プログラムを拡張すれば、最大で23個のLEDとRCサーボを制御できることになります。
現在のプログラムのままでは、A(5)+B(8)+PWMですが。(デモビデオでは、PortBには全てLEDを接続してありません)

最終のプログラムは、こちらです。
個人的に趣味でご利用される場合は、ご自由にお使いください。
(著作権は一応私に帰属します)
一部、コメントが不適切だったので修正しました

LED_mgr_final2.txt



XC8のメインプログラムとして、コピペすれば動作します。


動作のビデオを撮影しました。




(TMR0の計時の計算方法)

例えば、20MHzの内部クロックをカウンターの入力とした場合、カウンターに入力される周波数は1/4の5MHzが入力されます。
このクロックパルスの周期は200nsです。ですから、TMR0がオーバーフローする時間は0.2μsec x 256 = 51.2μsecになります。
タイマーの使い方にもよりますが、これでは短い場合もあります。そのような場合、プリスケーラを使用します。
プリスケーラのカウント値は2、4、8、16、32、64、128、256の8段階に設定できます。
例えば2と設定した場合、プリスケーラに2パルス入力された時に1パルス出力します。
256の場合には入力に256パルス入ったときに出力から1パルス出ることになります。
ですから、プリスケーラの設定値倍TMR0のオーバーフロー時間を長くすることができます。
先ほどの例の場合、プリスケーラを256設定にすると 51.2μsec x 256 = 13,107.2μsecになり、約13ミリ秒でオーバーフローすることになります。



【ジャンル】:趣味・実用 【テーマ】:模型・プラモデル
コメント(18)

管理者のみに表示する