FreeBSD上でSH2の開発環境構築とSH2を使ったDCサーボモータの制御のページ
その3

SH2の開発環境とDCサーボモータを制御する方 法を紹介してきます。


2006年
5月6日
外部のスイッチ(シフトパドル)から外部割込みを行な い、モータを動作させるようテストプログラムを修正しました。動作はN−>3−>4−>3−>4−>3−>Nで す。画像をクリックすると動画を再生します。

・SH2のToppersで外部割込みを有効にするために修正した部分です。

 ・割 り込みベクタテーブの 修正
  config/sh2/vector_table.c
  にIRQ0-IRQ7を追加設定します。以下、ソースコードの抜粋です。

        no_reg_exception,       /* 62           */
        no_reg_exception,       /* 63           */
        irq0_handler,           /* 64 IRQ0      */
        irq1_handler,           /* 65 IRQ1 Shift Up   */
        irq2_handler,           /* 66 IRQ2 Shift Down */
        irq3_handler,           /* 67 IRQ3      */
        irq4_handler,           /* 68 IRQ4      */
        irq5_handler,           /* 69 IRQ5      */
        irq6_handler,           /* 70 IRQ6      */
        irq7_handler,           /* 71 IRQ7      */
        no_reg_exception,       /* 72           */
        no_reg_exception,       /* 73           */



   ・割り込み番号の追加
 
config/sh2/apsh2f6a/apsh2f6a.h
   に外 部割込みの番号を定義します。

            #define EXT_IRQ0              64              /* IRQ0 */
            #define EXT_IRQ1              65              /* IRQ1 */
            #define EXT_IRQ2              66              /* IRQ2 */
            #define EXT_IRQ3              67              /* IRQ3 */
            #define EXT_IRQ4              68              /* IRQ4 */
            #define EXT_IRQ5              69              /* IRQ5 */
            #define EXT_IRQ6              70              /* IRQ6 */
            #define EXT_IRQ7              71              /* IRQ7 */


 ・ アプリケーションの コンフィグレーション

   XXX.cfg(XXXはアプリケーション名)内 に静的APIを使って割込みのハンドラを追加します。IRQ1IRQ2の割込みハンドラです。

            DEF_INH(EXT_IRQ1, { TA_HLNG, irq1_handler});
            DEF_INH(EXT_IRQ2, { TA_HLNG, irq2_handler});


 ・ アプリケーションプログラム内 に割込みのハンドラ本体を追加します。

       /*
        * Shift Up
        */
        void irq1_handler(void)
        {
            Y_state++;

            if (Y_state >= 2)
                Y_state = 2;

            syslog(LOG_NOTICE, ">irq1_handler %d\n", M_y);
            sil_wrh_mem(ISR, (sil_reh_mem(ISR) & ~0x0040)); /* clear intr */

        }

       /*
        * Shift Down
        */
        void irq2_handler(void)
        {
            Y_state--;

            if (Y_state <= 0)
                Y_state = 0;

            syslog(LOG_NOTICE, "irq2_handler %d\n", M_y);
            sil_wrh_mem(ISR, (sil_reh_mem(ISR) & ~0x0020)); /* clear intr */

        }


 ・ アプリケーションプログラム内に外部割込が動作するように各レジスタに 設定を行ないます。PBCR2(ポート2制御レジスタ、ICR(割込みコントロールレジスタ)、IPRA(割込みプライオリティレジスタA)ピンファンクションコントローラで割込み端子に設定します。IRQ1,2を立下りエッジ割込みに設定します。IRQ1,2の優先順位を10に設定します。以下、メインタスクの抜粋です。

        void main_task(VP_INT exinf)
        {

        /************************************/
        /* IRQ1,2の設定                     */
        /************************************/

        sil_wrh_mem (PBCR2, 0xa145); /* IRQ1,2=10 */
        sil_wrh_mem (ICR, 0x0060);   /* IRQ1,2=fall edge */
        sil_wrh_mem (IPRA, 0x0aa0);  /* IRQ1,2=10 */

5月7日
ボードに接続された8x8LEDシフトポジションに合わせて文字を表示するプログラムを追加しました。
サーボの誤差が大きいうちは緑で表示し、誤差が収束した時に赤で表示します。現状は3−4速に固定しているので、実際のシフトポジションはN、3、4速です。画像をクリックすると動画を再生します。
 


7月9日
回転前後方向、2つのモータを使ったテストプログラムを作成しました。ケントに付 いている5速のミッションは下のようなシフトパターンです。シフトするには回転方向の 位 置決めをした後、前後方向を移動すれば良いことがわかります。テストなのでモータはミッションには取り付けません。新しいプログラムは大抵ちゃんと動かないですから(笑)。


回転方向が修了した後に前後方向を制御すればいいので初め下の左側のフ ローでプログラムを作成しました。しかしハンチングが起こり上手く行きませんでし た。原因は回転方向ループと前後方向のループが別になっているため回転前後方向が交互に最終位置決めのハンチングが起すためです。そこでのフローのように1つのループの中に入れるように変更したところ上 手く行きました。この手の途中で止められないプ ログラムをgdbを使ってデバックするのは難しいです。P制御の係数とモータのドライブ電圧(PWM値)を低くしてモータ全体の動きをゆっくりにしてはじめて不具合が判りました。



7月16日
ベースプレートに前後方向のスライド、回転方向のギアなど を取り付けて先週作ったプログラムで2個のモータで駆動し、部品の干渉などが無いか確認します。画像をクリックすると 動画を再生します。約5Mバイトあります。N−>1−>2 −>3 −>4ー>5とゆっくり変速して、その後、 早く逆に戻 します。一番最後がバック(R)です。来週には回転方向の移動量を調べてミッションに接続してテストを行なう予定です。動作が間違ってました。


9月2日
久しぶりにセミ・オートマの作業しました。上記のモータの動作ですが、モータをミッションに付けて気が付きました。ちょっと間違ってました。

プログラムを修正してミッションに取りつけて動作させました。やっとHパターンで動きまし た。5速が入りにくいときがあります。また、R(リバース)は動作していません。クリックすると動画を再生します。約4.5MBあります。


9月10日
リバースの動作を追加しました。リバースのみ他の動作と 異なるため後回しになっていました。また、比例係数を実 数にして細かい調整ができるように変更しました。おまけとして5速に入って一定時間たつと表示部に文字をスクロールさるようにしました。5速に入ったままということはたぶん高速道路巡行して いると判断して文字をスクロールさせます(笑)。
クリックすると動画を再生します。スクロール文字は動画には映っていません。約12MBあります。


9月15日
動作の説明です。下図は2速から3速への移動ですが、初めに前後方向を ニュートラル位置まで移動し、その後回転方向を3速まで移動します。最後に前後方向を3速まで移動して 完了します。このパターンは3−>2、4−>5、5−>4の移動でも同様です。制御プログラムでは下図の前後方向+回転方向前後方向に分けて制御します。リバースはちょっと動作が違います。


以下、永久ループ内の3速へシフトするプログラムとマク ロ部の抜粋 です。大文字はマクロです。シフトパッドの割り込みでシフトポジション
(Shift_p)が3にな り、割り込みフラグ(Intr_flag)がセットさ れます。3速 に来る前のシフトポジション(Last_shift)が2であれば2速ー>3速への移動なので、初めの1回だけSERVO_YX()マクロを実行し その後はシフトポジションが変更されるまでSERVO_Y()が 実行されます。4速ー>3速の場合には回転方 向を移動する必要がないので初めからSERVO_Y()のみ実行されます。

課題はタ イムアウトが発生した時です。一定時間内にシフトが完了しなかったということは引っかかったり、何らかの不具合が発生しています。


   //
   // R 1 3 5
   // | | | |
   // N-n-N-N
   //   | |
   //   2 4
   //
   // N:前後方向のみニュートラル
   // n:ニュートラル
   //
   // X:回転方向
   // Y:前後方向
   //
   // SERVO_Y():前後方向移動
   // SERVO_YX():前後方向移動後、回転方向を移動
   //

    while(1) {

            ///
            /// その他の処理
            ///

            else if (Shift_p == 3) {
                /////////////////
                // 3
                /////////////////
                //
                // 移動パターン

                // 4->3
                //
                //    (3)
                //     |
                //     N
                //     |
                //     4

                // 2->3 (N/3に移動してから)
                //
                //    (3)
                //     |
                //   --N
                //   |
                //   2

                // 緑にしてLEDバッファに3をいれる
                SET_CHAR_LED('3');

                // 2から3へシフトアップ2段階移動の初期動作
                if (Intr_flag) {
                    if (Last_shift == 2) {
                        // 2->N/3へ

                        // 移動は一定時間内に終了したか?
                        // 一定時間を過ぎて移動が完了しないと周期関数で
                        // Time_outがセットされる
                        m_y = Y_0_VAL;
                        m_x = X_3_VAL;
                        SERVO_YX();

                        // 移動は一定時間内に終了したか?
                        if (Time_out)
                            break;
                    }

                }

                // 移動、一定の範囲に入るとLEDが赤になって戻る
                // 一定時間を過ぎて移動が完了しないと周期関数で
                // Time_outがセットされる
                m_y = Y_3_VAL;
                m_x = X_3_VAL;
                SERVO_Y();

                // 移動は一定時間内に終了したか?
                if (Time_out)
                    break;

            }
                  ///
                  /// その他の処理
                  ///
         }

         ///
         /// タイムアウトの処理
         ///



///////////////////////////////////////////////
//
// 前後制御サーボマクロ
//
// Y軸(前後)にみ移動、X軸(回転)は保持
//
///////////////////////////////////////////////
//
#define SERVO_Y() \
    To_count = TIME_OUT_VAL; \
    Time_out = 0; \
    while (TRUE) { \
        Count1 = (short)*TCNT1; \
        pd = m_x - Count1; \
        err_x = (short)(pd * kpx); \
        if (err_x >= COUNTER_X_MAX) { \
            err_x = COUNTER_X_MAX; \
        } \
        else if (err_x <= COUNTER_X_MIN) { \
            err_x = COUNTER_X_MIN; \
        } \
        if (err_x < 0) { \
           sil_wrh_mem (PEDR, sil_reh_mem (PEDR) & ~MOTOR_XDIR); \
           sil_wrh_mem (TGR3B, err_x * -1); \
        } \
        else { \
           sil_wrh_mem (PEDR, sil_reh_mem (PEDR) | MOTOR_XDIR); \
           sil_wrh_mem (TGR3B, err_x); \
        } \
        Count2 = (short)*TCNT2; \
        pd = m_y - Count2; \

        err_y = (short)(pd * kpy); \
        if (err_y >= COUNTER_Y_MAX) { \
            err_y = COUNTER_Y_MAX; \
        } \
        else if (err_y <= COUNTER_Y_MIN) { \
            err_y = COUNTER_Y_MIN; \
        } \
        if (err_y < 0) { \
           sil_wrh_mem (PEDR, sil_reh_mem (PEDR) & ~MOTOR_YDIR); \
           sil_wrh_mem (TGR4B, err_y * -1); \
        } \
        else { \
           sil_wrh_mem (PEDR, sil_reh_mem (PEDR) | MOTOR_YDIR); \
           sil_wrh_mem (TGR4B, err_y); \
        } \
        if (err_y < Y_ERR_MINUS || err_y > Y_ERR_PLUS) \
            Font_color = LED_COL_RED; \
        if (lasterr_y == err_y) { \
            if (err_y >= Y_ERR_MINUS && err_y <= Y_ERR_PLUS) { \
                To_count = TIME_OUT_VAL; \
                break; \
            } \
        } \
        if (!(Loop % 10000)) { \
            syslog(LOG_INFO, "Y C1=%d E1=%d M1=%d", Count1, err_x, m_x); \
            syslog(LOG_INFO, "Y C2=%d E2=%d M2=%d\n", Count2, err_y, m_y); \
        } \
        Loop++; \

        lasterr_y = err_y; \
    } \


//////////////////////////////////////////////////////////////////
//
// 前後回転制御サーボマクロ
//
// 初めにY軸(前後)を移動、その後X軸(回転)方向を移動
//
//////////////////////////////////////////////////////////////////
//
#define SERVO_YX() \
    y_done = 0; \
    To_count = TIME_OUT_VAL; \
    Time_out = 0; \
    while (TRUE) { \
        Count2 = (short)*TCNT2; \
        pd = m_y - Count2; \
        err_y = (short)(pd * kpy); \
        if (err_y >= COUNTER_Y_MAX) { \
            err_y = COUNTER_Y_MAX; \
        } \
        else if (err_y <= COUNTER_Y_MIN) { \
            err_y = COUNTER_Y_MIN; \
        } \
        if (err_y < 0) { \
           sil_wrh_mem (PEDR, sil_reh_mem (PEDR) & ~MOTOR_YDIR); \
           sil_wrh_mem (TGR4B, err_y * -1); \
        } \
        else { \
           sil_wrh_mem (PEDR, sil_reh_mem (PEDR) | MOTOR_YDIR); \
           sil_wrh_mem (TGR4B, err_y); \
        } \
        if (lasterr_y == err_y) { \
            if (err_y >= Y_ERR_MINUS && err_y <= Y_ERR_PLUS) \
                 y_done = 1; \
        } \
        lasterr_y = err_y; \
        if (y_done) { \
            Count1 = (short)*TCNT1; \
            pd = m_x - Count1; \
            err_x = (short)(pd * kpx); \
            if (err_x >= COUNTER_X_MAX) { \
                err_x = COUNTER_X_MAX; \
            } \
            else if (err_x <= COUNTER_X_MIN) { \
                err_x = COUNTER_X_MIN; \
            } \
            if (err_x < 0) { \
               sil_wrh_mem (PEDR, sil_reh_mem (PEDR) & ~MOTOR_XDIR); \
               sil_wrh_mem (TGR3B, err_x * -1); \
            } \            else { \
               sil_wrh_mem (PEDR, sil_reh_mem (PEDR) | MOTOR_XDIR); \
               sil_wrh_mem (TGR3B, err_x); \
            } \
        } \
        if (lasterr_x == err_x) { \
            if (err_x >= X_ERR_MINUS && err_x <= X_ERR_PLUS) { \
                 if (y_done) { \
                     Intr_flag = 0; \
                     To_count = TIME_OUT_VAL; \
                     break; \
                 } \
            } \
        } \
        if (!(Loop % 10000)) { \
            syslog(LOG_INFO, "XY C1=%d E1=%d M1=%d", Count1, err_x, m_x); \
            syslog(LOG_INFO, "XY C2=%d E2=%d M2=%d\n", Count2, err_y, m_y); \
        } \
        Loop++; \
        lasterr_x = err_x; \
    } \



10月1日
5速に入って一定時間たつと表示される(高速道路では5のままで退屈なので)スクロールの動画を撮ってみました(笑)。現在は直ぐにスクロールが始まりますが、実際には5分くらいに設定します。表示されるのは歌詞ですが、乱数で複数のから選択し ても良いかもしれません。