Knowledge
   

プロポをマイコンで制御


2004/10/31

プロポをマイコンで制御・その1

プロポをマイコンで制御
20041031P00.JPG - 23,400BYTESさて、次回ROBO-ONE用に、SISO LABにて検討中アイテムの1つに、「オリジナルコントローラによる操作」というのがあります。スイッチボードを自作、もしくはゲームコントローラを改造してマイコンを接続し、プロポに入力して電波を飛ばそうという試みです。

いや、KONDOの無線コントロールユニットとかにすれば、こんな苦労は要らないのですが、あの受信機、かなり小さいけど、今のG-Tuneにはまだ大きい…。あれ?今、ロボット王国のホームページチェックしてたら、「フリクションスペーサ」がある〜。いつの間に…。

さってと、話、戻りましてと。フタバプロポに限らず、プロポには「トレーナー機能」というものがついています。これは、以前のTOPICでも紹介しましたが、生徒さんとトレーナさんの2台のプロポをケーブルで接続し、トレーナのプロポで生徒さんの操作を行うものです。このSKYSPORT4、良く見ると正面左上に、小さなボタンがついていますが、これを押している間、ケーブルを経由して別のプロポから操作をすることができます。

また、このトレーナ機能、SKYSPORT4(どのプロポもそうみたいですが)では、生徒さん側もトレーナ側もできるようです。つまり、このSKYPORT4からも信号が出力されているはずなので、Trainer端子を適当にあたって、まずは信号解析してみました。ネットでちょっと「トレーナケーブル」なるものを探してみたのですが、うぅ、トレーナケーブル、意外に高価だったので購入をあきらめました(笑)。というわけで、ピンを直接あたることにしました。

トレーナ信号とは???
20041031P01.JPG - 23,483BYTESというわけで、裏蓋開けてにらめっこし…あきらめました。グランドぐらいはわかるのですが…。というわけで、「Google」で「プロポ トレーナ 端子」ぐらいで検索をへろへろっと。おお、ありました。まず端子ですが、左の写真のようになっています。

実は、さっきのGoogle検索で、すでにトレーナ信号を解説されているホームページを発見してしまいました。どうも、ラジコンフライトシミュレータソフトのコントローラとして、プロポをそのまま使用するようです。なるほど。それならラジコンと同じ操作感が得られます。

そんなわけで、きっと、このページを見たみなさんも、既に発見されていると思いますので、信号は、試しに見てみる程度にしたいと思います。というわけで、まずはオシロ(のおもちゃ?)をつないで波形を見てみます。この秋月のペン型オシロ、ちゃちだし少々怪しげですが、結構、役に立ちます(でも、もっといいのがやっぱり欲しい〜)。

20041031P02.JPG - 8,311BYTES20041031P03.JPG - 7,691BYTES

左が「1マス5msec」です。これを見ると、18msecで信号が繰り返されているのがわかります。で、この部分を拡大したのが右側です。「1マス1msec」です。じゃ、試しにスティックを動かしてみます。左スティックを上下してみました。

20041031P04.JPG - 7,823BYTES20041031P05.JPG - 7,663BYTES

上にすると、2番目の山が小さくなり、下にすると、2番目の山が大きくなるのがわかります。他も微妙に動いているような気がしますが、実際のところどうなんでしょう…。電圧(HIGH)ですが、上の絵ですと、「1マス2.5V」ですので、4Vをちょっと切るぐらいですが、もう1つ前の写真を見ると、5Vちょっと切るぐらいです。これは、「グランド」を適当につなげたか、しっかりつなげたかで変化が出てまして、「プロポ操作つき」のデータ収集の場合、どうも端子へのあたりがいいかげんになってしまいまして、こういう結果になってしまいました。

ネットで見つけた情報によると、「LOWになっている部分は0.4msec、山はスティック位置が真中で1.1msecあたりで0.6〜1.6msec程度、操作によって変化、最後に、もう1つ0.5〜0.6msec程度の山があって、全体は常に18msec」とありますが、これで確認はできました。また、それぞれのスティックの信号が短い場合、それ以降の信号は前詰になりますが、全体は18msecのままであるということもわかります。

同じプロポ同士でトレーナ機能が使えるならば、これと同じ信号を、トレーナの入力端子に入れれば動作できるはずです。

どれがどれ?
先ほどの調子で、スティックを1つずつ動かして波形を調べてみたら、次のような結果になりました。

  • 1つめの信号 右スティックの横方向
  • 2つめの信号 左スティックの縦方向
  • 3つめの信号 右スティックの縦方向
  • 4つめの信号 左スティックの横方向

というわけで、明日はテストプログラムの解説をしたいと思います。

ところで、ONOさ〜ん、また電脳壁新聞、見当たらないんですが…うちだけでしょうか?

追記)うふっ。見つけました。ONOの電脳壁新聞!

 

2004/11/04

プロポをマイコンで制御・その2

というわけで…
20041104P01.JPGつなげてみました。ベースボードとの結線が、以前壊したS03Tのケーブルを使ってたりと、微妙にせこかったりしますが、評価には充分です。接続は、P82(たまたまテストボードにサーボ出力用にピンが立ててあったから)からトレーナ端子の一番上(入力)に接続しています。コードを修正していただければ、どの出力ピンでもOKです。おっと、P56とP57だけはやめておいてください。あのピンだけは出力レベルtが値がいますから。

さて、気になるプログラムですが、今回は、TimerWを使用しました。18msecの基本周期が必要になりますので、TimerWのコンペアマッチクリア機能を使用して作ります。コンペアマッチクリアというのは、あらかじめジェネラルレジスタに値を設定しておき、カウンタがその値になると、自動的にクリアされる仕掛けです。ジェネラルレジスタA(GRA)のみ、この機能を使用することができます。

そして、GRBによってコンペアマッチ割り込みを適宜発生させるようにします。H8/3664のCPUクロックは16MHzですので、1/8周期でカウントアップした場合、2000カウントで1msecになります。下の図で説明しますと、GRAによって、36000カウントでタイマがクリアされるようにしておいて(黄色い線)、GRBによってそれぞれのタイミング(緑色の線)で割り込みをかけます。そして、制御信号(青色の線)が出力されます。

20041101P00.JPG - 14,435BYTES

GRBによる割り込み処理内容
GRBの割り込み処理の内容は次のようになります。表中に「+800」という表現がありますが、カウンタは先の説明の通り、0〜36000(18ms)で変化するように設定して使用していますので、比較する方のGRBも、随時、値を足し込んでいくという意味で、こういう表記にしています。

0. 0 CLK 信号をLOWレベルにしてGRBに+800(0.4ms)を設定。
1. +800 CLK 信号をHIGHレベルにし、GRBにCH0のスティック位置に応じた時間(+CLKCH0)を設定。
2. +CLKCH0 CLK 信号をLOWレベルにしてGRBに+800(0.4ms)を設定。
3. +800 CLK 信号をHIGHレベルにし、GRBにCH1のスティック位置に応じた時間(+CLKCH1)を設定。
4. +CLKCH1 CLK 信号をLOWレベルにしてGRBに+800(0.4ms)を設定。
5. +800 CLK 信号をHIGHレベルにし、GRBにCH1のスティック位置に応じた時間(+CLKCH2)を設定。
6. +CLKCH2 CLK 信号をLOWレベルにしてGRBに+800(0.4ms)を設定。
7. +800 CLK 信号をHIGHレベルにし、GRBにCH1のスティック位置に応じた時間(+CLKCH3)を設定。
8. +CLKCH3 CLK 信号をLOWレベルにしてGRBに+800(0.4ms)を設定。
9. +800 CLK 信号をHIGHレベルにし、GRBに+1200(0.6ms)を設定。
10. +1200 CLK 信号をLOWレベルにし、GRBに+800(0.6ms)を設定。
11. +800 CLK 信号をHIGHレベルにし、GRBに0を設定。

長くなったしまったので、ここらで一旦切りまして、明日はいよいよプログラムの解説をします。

ところで、OLMECAの部屋のイカガワさん、Hashioさん、元気〜?今は大学祭とかかなぁ。トレーナ機能はこれであってる???

 

2004/11/05

プロポをマイコンで制御・その3

さて、プログラム解説
というわけで、気になるプログラムですが、サンプルで、「キーボードをプロポスティックに見立てて操作するプログラム」を作ってみました。操作イメージは次のような感じです。キーボードのぽっちがついているキーを中心に、上下左右という感じで振ってみました。例えば、「R」を押すと、左スティックが上、「F」を押すと中央に戻ります。例によって、GDLを使わさせて頂いています。

左スティック

○ 

右スティック
E R T Y U I
D F G H J K
C V B N M ,

TimerWの初期化
TimerWを18msecで折り返すということで、今回は、GRAによるカウンタのクリア機能を使用します。TimerWは、16bitなので、黙って走らせておくと、「0〜65535」までのカウントアップしてまた「0」に戻るという動作をするのですが、この機能を使用すると、「GRAに設定した値になると0に戻る」という動作をしてくれます。今回、カウンタは、φ/8でカウントアップされますので、「1/16MHz*8」が1カウントに必要な時間になります。18msカウントするためには、36000までカウントすれば良いことになります。

また、GRBのコンペアマッチによって割り込みをかけます。よって、初期化プログラムは以下のようになります。

    TW.TMRW.BYTE = 0x48;                            //  タイマストップ、モード普通
    TW.TCRW.BIT.CCLR = 1;                           //  GRAコンペアクリアあり
    TW.TCRW.BIT.CKS = 3;                            //  φ/8

    TW.TIERW.BIT.IMIEB = 1;                         //  Bコンペアマッチ割り込み有効

数値をDEFINEで定義
これは、見易さとか、趣味の問題なのですが、プログラム中で使う数値を"#define"等で宣言します。例えば、いきなりプログラム中に「36000」と書いてあるより、「DDFT_TCNT00180S」と書いてあった方が、「ああ、0.018secか〜」ってわかりやすい気がするので、こうしています。こんな風に定義しました。

#define     DDFT_TCNT00180S     36000               //  16MHzで1/8の18msカウントアップ初期値
#define     DDFT_TCNT00004S     800                 //  信号と信号の間のLOW時間
#define     DDFT_TCNT00006S     1200                //  スティックLow Low(600us)
#define     DDFT_TCNT00011S     2100                //  スティックCenter(1100us)
#define     DDFT_TCNT00016S     3200                //  スティックHigh High(1600)

#define     DDFT_SIGNALOUT      IO.PDR8.BIT.B2      //  トレーナ信号出力端子

#define     DDFT_SPOS_HGH       0x01        //  スティック位置定義
#define     DDFT_SPOS_CNT       0x02        //  スティック位置定義
#define     DDFT_SPOS_LOW       0x03        //  スティック位置定義
      

グローバルデータ
このプログラムで使用する、グローバルデータは次の2つです。

_BYTE   GVDbSignalStep;         //  信号処理ステップ(0:最初の0.4ms,1:CH0,2:0.4ms,3:CH1...)
_BYTE   GVDabStickPos[4];       //  プロポスティック位置
      

「GVDbSignalStep」は、TimerW割り込み処理のところで詳しく説明しますが、全体の処理のステップ(最初に0.4msのLOWを出して、つぎにCH0の信号を出して…みたいな処理)を覚えておくための変数です。「GVDabStickPos[4]」の方は、プロポスティック位置相当のデータをキーボードからの入力によって覚えておくためのデータです。

TimerW割り込み処理
さて、一番複雑な部分のTImerW処理です。逐次動作を変えないといけません。前回の説明を見ていただくとわかりますが、まず最初に「0.4msのLOW」、そして次に「CH0にあわせた時間のHIGH」、そして…という感じで、動作を変えていく必要があります。そういうわけで、グローバルデータを1つ用意し、これを動作ごとに1つずつインクリメントし、それで動作を切り替えることにします。

void    int_timerw( void )
{
    //  GRB コンペアマッチ  信号作成用カウントアップ
    if( TW.TSRW.BIT.IMFB == 1 ){
        TW.TSRW.BIT.IMFB = 0;                       //  割り込みフラグクリア
        switch( GVDbSignalStep ){
        case 0:                                     //  初期化(0でコンペア)
            DDFT_SIGNALOUT = 0;                     //  LOWにする。
            TW.GRB = DDFT_TCNT00004S;               //  最初の0.4msを設定する。
            break;
        case 9:                                     //  最後信号の0.6ms ON。
            DDFT_SIGNALOUT = 1;
            TW.GRB += DDFT_TCNT00006S;
            break;
        case 11:                                    //  最後
            DDFT_SIGNALOUT = 1;                     //  HIGHにする。
            GVDbSignalStep = 0xFF;                  //  初期値(インクリメントして0になる)
            TW.GRB = 0;                             //  初期化する。
            break;
        default:
            if(( GVDbSignalStep & 0x01 ) != 0 ){    //  奇数ならば信号出力
                DDFT_SIGNALOUT = 1;
                switch( GVDabStickPos[(GVDbSignalStep/2)] ){
                case DDFT_SPOS_HGH:     TW.GRB += DDFT_TCNT00006S;  break;
                case DDFT_SPOS_CNT:     TW.GRB += DDFT_TCNT00011S;  break;
                case DDFT_SPOS_LOW:     TW.GRB += DDFT_TCNT00016S;  break;
                default:                TW.GRB += DDFT_TCNT00011S;  break;
                }
            }
            else{
                DDFT_SIGNALOUT = 0;
                TW.GRB += DDFT_TCNT00004S;
            }
            break;
        }
        GVDbSignalStep++;
    }
}
   

いきなりちょっと長いですが、「GVDbSignalStep」というグローバル変数を使用して、これを、0〜11に変化させることでCASE文の中を飛ばしています。昨日の処理の表と見比べてみてください。この「GVDbSignalStep」とう変数の数値と、昨日の表の項目番号は一致しています。

昨日の表をよく見るとわかるのですが、「9」と「11」を除いた奇数の時には「スティックに応じた位置の出力」、偶数の時は「0.4ms」の出力の処理になります。おっと、よくみると「case 0:」は不要な感じですね〜。すいません、余分なものをいれてしまいました。

後は、これにキー入力処理をいれたら出来上がりです。ご参考、実験用ということで、完成プログラムはここです。

さて、これを使えば…オリジナルで作ったコントローラパッドからの入力をマイコンで受け、それをプロポのスティック位置として出力することができそうです。おっと、最後になりましたが、実験される時は、「プロポ左上のボタンを押す」ことをお忘れなく。

 


SISO-LAB Knowledge