PageTopへ戻る

12.スピードのフィードバック制御

●ADCで取得したモーターの発電電圧の値を利用して、列車の速度が一定になるように フィードバック制御します。

・前回まではリモコンのTrackBarの値をそのままスピードパルス幅にしていましたが、模型列車の種類によっては 同じだけTrackBarを上げても同じ速度で走らず、電気機関車などは だいぶ上げないと動き出しません。また、レイアウトに勾配があると上っている時に止まってしまったりします。
 そこで実際の速度と、設定速度を比較しフィードバックして一定速度になるように制御します。

【dsPICのコード】(2015/3/21変更)

※テキスト部分を右クリック、すべて選択してまた右クリックし、コピーします。

前回からの変更点

●フィードバック制御したスピード値を計算する関数speed_contの追加
void speed_cont(unsigned char n)
●スピードパルスONの部分でスピードパルス幅用メモリspeed_pwにリモコンのスピード値をそのまま代入していたところを、 フィードバック制御した上記関数で計算した値を代入する。

前回 speed_pw[sou] = train[n].speed;
今回 speed_pw[sou] = train[n].speed_cont;

【関数speed_contの説明】
この関数はint_counterが0x1F7のときA相の制御、0xF7のときB相の制御で呼び出されます。
リモコンからのスピード値とADCで取得した実際のスピード値を比較し、その差の大きさに応じてスピードパルス幅を逆向きに増減します。 このときの増減の感度をk1としています。
また、エラーの値を一周期前のエラー値と比較し、エラーが増加しているときは感度k1にエラー増加分を加え補正を大きくします。 逆にエラーが小さくなっていたらエラー増加分を引いて補正を小さくします。こうすることにより、ハンチングを起き難くします。 ハンチングが起こると列車が早くなったり遅くなったりを繰り返します。

【※2013/3変更】
制御したことによるスピードの変化に時間かかかるので、制御間隔を大きくしました。
・変数cont_countを追加し、speed_contを呼び出す間隔を5周期に一回に減らしています。
・スピード検出の部分では、実際にはスピード変化はなめらかであるので、ノイズの影響を受けにくいように徐々に変化するように変更しています。

【PC側のソフト】

●定速度で運転出来るようになり、信号停止(赤信号)の前段階の減速運転(黄信号)が可能になったので、 次位置の次の区間である次々位置を導入し、安全確認で次々位置に他の列車があるときは減速運転することにします。

・前回11.からForm1およびContPanelのデザインの変更はないので、前回と同様にコードを下記と入れ替えてください。

【Form1用コード】

※テキスト部分を右クリック、すべて選択してまた右クリックし、コピーします。

【ユーザーコントロールContPanel用コード】



【ユーザーコントロールContPanel用コード】VB2013用





13.ユニバーサル基板で製作

●次はユニバーサル基板で作ってみます。


・使用したのはサンハヤトの端子付きユニバーサル基板CPU-107Fです。
・基板用コネクタは KEL1150N-044-009 カードエッジコネクです。若松通商で売っています。
・電源用パターンは裏側のみ使用しています。電源電圧を分けるため、カッターでパターンを切断する部分があります。



    <裏 面>



    <接続図>



・このボードは親ボードで2.5V作成回路とRS232C送信用回路を実装しています。
・2つ目以降の子ボードは2.5V作成回路とRS232C送信用回路がない構成になります。
・外部通信用のINT_CLOCK、DATAの2つの端子を他の子ボード、ポイントボード、 シグナルボードなどと共通で接続し、通信をします。

14.複数ボードの制御

●ここからはループを増やすために子ボードを追加します。



・接続は図のように電源は共通とし、RS232Cの受信(PC側のRS232C-TX)は子ボードも共通で受信します。
・RS232Cの送信(PC側のRS232C-RX)は親ボードのみが行い、子ボードの情報は各ボード間で通信をして親ボードが送信します。
・通信はINT_CLOCKとDATAの2本でシリアル同期通信をします。
・各ボードのループはポイントでつながることになりますが、ループ間を跨ぐ時に、パルスの位相が合っている必要があり、 また、同期通信のためにも各ボードは完全に同期させます。

●同期の方法
・親ボードはタイマーインタラプトにより約20μsごとに割り込みを発生させていますが、この割り込み処理の頭の部分で RD9ポートを使用して、子ボードに外部割込みを発生させます。
・これで割り込みのタイミングは一致しますが、インタラプトカウンタを同期するために、カウンタが0の時のみ、インタラプトパルスの 幅を大きくして、子ボードはこの幅が大きい時インタラプトカウンタを0にリセットすることによりカウンタを同期します。

●子ボードの製作例



【dsPICのコード】

●親ボードはROSEN_NUMを0にしてコンパイルし、子ボードは1からの番号に変更してコンパイルします。
    #define ROSEN_NUM 0 //親ボード
    #define ROSEN_NUM 1 //子ボード1
    #define ROSEN_NUM 2 //子ボード2
    ・・・・・

・コンパイラ擬似命令の#ifによりROSEN_NUMが0の時と、0以外の場合でコードを入れ替えます。
たとえばインタラプトルーチンの部分で

#if ROSEN_NUM == 0
    //親ボードはタイマーインタラプトルーチン
    void __attribute__((__interrupt__, __shadow__, no_auto_psv)) _T1Interrupt(void)
#else
    //子ボードは外部端子割り込み
    void __attribute__((__interrupt__, __shadow__, no_auto_psv)) _INT2Interrupt(void)
#endif

のように使用します。MPLAB_Xの場合、条件に合わない部分がグレーになりわかりやすいです。

●コンパイルした後のデータ転送は、転送するボードのdsPIC基板のLR切替SWをLoad側にしReset後にdsPIC基板PushSWを押して dspicguyで転送します。他のボードをはずす必要はないのでやり易いです。

※テキスト部分を右クリック、すべて選択してまた右クリックし、コピーします。※2015_3_24:変更あり


●ボード間の通信

・ボード間の通信は、親ボードからの割込信号INT-CLOCKとDATAの2本の信号線で行います。
・I2Cというマイコン間通信の方法もありますが、完全同期していて手順も簡易なのでこの方法で行います。
・INT-CLOCKを各ボードにてcomm_counterで、0〜0x7ff(2023)を1周期としてカウントします。
・図のようにcomm_counterが偶数のとき送信ボードがbitデータをセットし、次のインタラプトの時、受信ボードが読み込みます。
・8bit単位で通信用メモリエリアのcomm_data[128]をやり取りします。
・下表のようにそれぞれ各ボードのメモリ位置が決まっていて、担当位置のデータの時、送信します。 それ以外のボードは、そのデータを受信し、自分のメモリの当該位置に書き込みます。 これで各ボードのデータをすべてのボードが共有することが出来ます。
・この通信の処理は board_comm() で行っています。
・また、送信する通信データの設定を comm_data_set_tx() で 受信した通信データの設定を comm_data_set_rx() で行っています。


・親ボードのみがPCへデータを送信できるので、子ボードからは読み取りスピードと区間変化情報を送る必要があります。
・また、後でポイントボードを追加しますが、ループを跨ぐ際に制御スピードを同じにしておく必要があり、 制御スピードも共有する必要があります。

【PC側のソフト】

●子ボードを1つ追加したとして、4台運転のPC側ソフトです。

・12.からForm1およびContPanelのデザインの変更はないので、Form1のみコードを下記と入れ替えてください。



【Form1用コード】



・Sub form1_Load()内で列車の初期位置を設定しています。
・路線0の区間1と4,路線1の区間1と4が初期位置です。
・使用しない(4)〜(7)の列車にはNew Train()の引数なしでDummyの路線7を登録しています。

    '列車情報設定
    列車(0) = New train(New 位置情報(1, 0, 0, 0))
    列車(1) = New train(New 位置情報(4, 0, 0, 1))
    列車(2) = New train(New 位置情報(1, 1, 0, 0))
    列車(3) = New train(New 位置情報(4, 1, 0, 1))

    'Dummy Data
    列車(4) = New train()
    列車(5) = New train()
    列車(6) = New train()
    列車(7) = New train()
次へ

PageTopへ戻る