ラジコンサーボをパソコンで動かす

一応、SISOさんサーボプログラムは動きましたので、パソコンから動かすを通信でやってみることにまします。
 通信で数値を送りラジコンサーボを動かす場合、通信なら関数で以前やったのでそれとハイパーターミナル使用なら、案外簡単にできます。
通信にハイパーターミナルを使い、簡易的にやってみました。これでもちゃんと出力パルスが制御でき、ラジコンサーボが命令通り動きます。

マイコンとのRS232C通信

方法は元の16軸多軸ラジコンサーボのソフトに パソコンからパルス長に関わる数値を送ってやるだけという案外簡単なものです。肝は送受信方法だけでしょう。

それもハイパーターミナルなら以前やったように簡単にやりとりはできます。

 

受け取ったパルス長数値を配列に入れてやるだけ、という簡単なものです。
一度に1軸だけ動かせる程度のものをつくってみました。でも、続けて入力すると全部の軸を動かせます。実用というよりも確認用に作ってみるといった感じです。

 

実用にするにはやはりPC側でちゃんとソフトを作ることになるでしょう。(もし動かす基本がわからない人がいれば、この簡易的なプログラムを足がかりに)
単なるテスト用ということで、ここでは一度に1軸だけ動かす数値をハイパーターミナルから送ることにします。

 

送信は簡易的にハイパーターミナルから 文字列として送信

  • ラジコンサーボの配列番号  0~15
  • パルス長       25未満

を送り


H8-3664F で文字列受信関数で受け、加工して放り込むだけというものです。


このプログラムは 上記HPのSISOさんが作成されたもので、同様のことを手がけているときに偶然出会い、SISOさんの厚意により当HPで公開許可いただけたものです

内容はよくわからないが実用に改良したい等、一番問い合わせが多いのがここの多軸RCサーボ制御のところですが、これは多軸RCサーボ制御方法の1つとして加えました。sisoさんのソースもきれいに簡潔に書かれていて、下に説明も加えましたので処理内容を理解し発展させる種として活用してください。


回路図

SISOさん作成のものと同様、以下各ポートにパルスが出力されます。

awServoPos[0] P14  awServoPos[1] P15  awServoPos[2] P16  awServoPos[3] P17 
awServoPos[4] P50 awServoPos[5] P51 awServoPos[6] P52 awServoPos[7] P53
awServoPos[8] P80 awServoPos[9] P81 awServoPos[10] P82 awServoPos[11] P83
awServoPos[12]P84 awServoPos[13]P85 awServoPos[14] P86 awServoPos[15] P87

 

プログラム

 

SISO_sarvos10ms_PC


#include <3664.h>

#define TIMERW_10MSEC 45535  // 10msec待つためのタイマW初期値
#define TIMERW_2M5SEC 60535  // 2.5msec待つためのタイマW初期値

_BYTE   bStep;            // サーボ制御ステップ
_WORD   awServoPos[16];   // サーボ制御位置

unsigned char txb[10], rxb[10] ;
char b[20];             //通信用

//
// タイマW割り込みルーチン
//
void int_timerw( void )
{
  _BYTE bSrvA, bSrvB, bSrvC, bSrvD;   // サーボ制御信号ON作業用

  if( TW.TSRW.BIT.OVF == 1 ){   // オーバーフロー発生
    // オーバーフロー発生時の処理
    TW.TSRW.BIT.OVF = 0;    // オーバーフローフラグクリア

    TW.TMRW.BIT.CTS = 0;    // タイマストップ(他のビットはデフォルト)


      TW.TCNT = TIMERW_2M5SEC;    // 2.5msec後にOVFする値設定

      // GRレジスタへの制御信号OFF時間の設定
      TW.GRA = TIMERW_2M5SEC + awServoPos[(bStep-1)+0];
      TW.GRB = TIMERW_2M5SEC + awServoPos[(bStep-1)+4];
      TW.GRC = TIMERW_2M5SEC + awServoPos[(bStep-1)+8];
      TW.GRD = TIMERW_2M5SEC + awServoPos[(bStep-1)+12];

      bSrvA = 1 << (( bStep-1 )+4 );  // 元ネタの計算
      bSrvB = 1 << (( bStep-1 ));     // 元ネタの計算
      bSrvC = 1 << (( bStep-1 ));     // 元ネタの計算
      bSrvD = 1 << (( bStep-1 )+4 );  // 元ネタの計算

      IO.PDR1.BYTE |= bSrvA;          // 信号ON!!
      IO.PDR5.BYTE |= bSrvB;          // 信号ON!!
      IO.PDR8.BYTE |= bSrvC;          // 信号ON!!
      IO.PDR8.BYTE |= bSrvD;          // 信号ON!!
    

    // ステップ情報の操作
    //   1~4:サーボ制御信号出力なので、5になっていたら
    //   数値を0に戻す。
    bStep++;
    if( bStep == 5 ){
      bStep = 1;
    }

    TW.TMRW.BIT.CTS = 1;    // タイマスタート
  }
  
  if(TW.TSRW.BIT.IMFA  == 1){   // GRA コンペアマッチ
    // GRAコンペアマッチ発生時の処理
    IO.PDR1.BYTE &= 0x0F;
    TW.TSRW.BIT.IMFA = 0;       // 割り込みフラグクリア
  }
  if(TW.TSRW.BIT.IMFB  == 1){   // GRB コンペアマッチ
    // GRBコンペアマッチ発生時の処理
    IO.PDR5.BYTE &= 0xF0;
    TW.TSRW.BIT.IMFB = 0;       // 割り込みフラグクリア
  }
  if(TW.TSRW.BIT.IMFC  == 1){   // GRC コンペアマッチ
    // GRCコンペアマッチ発生時の処理
    IO.PDR8.BYTE &= 0xF0;
    TW.TSRW.BIT.IMFC = 0;       // 割り込みフラグクリア
  }
  if(TW.TSRW.BIT.IMFD  == 1){   // GRD コンペアマッチ
    // GRDコンペアマッチ発生時の処理
    IO.PDR8.BYTE &= 0x0F;
    TW.TSRW.BIT.IMFD = 0;       // 割り込みフラグクリア
  }
}

int main()
{
  unsigned char SavNo ,Pls_w;
        
  //
  // 初期化
  //
  //通信用初期化
  SCI3_INIT(br38400, txb, sizeof(txb), rxb, sizeof(rxb));
  
  // タイマモードレジスタ
  TW.TMRW.BIT.CTS = 0;    // タイマストップ(他のビットはデフォルト)

  // タイマコントロールレジスタ
  TW.TCRW.BIT.CKS = 3;    // クロックセレクト
                          //   内部クロックをΦ8でカウントアップ

  // タイマインタラプトイネーブルレジスタ
  TW.TIERW.BIT.OVIE = 1;  // オーバーフロー割り込み有効
  TW.TIERW.BIT.IMIEA = 1; // GRA割り込み有効
  TW.TIERW.BIT.IMIEB = 1; // GRB割り込み有効
  TW.TIERW.BIT.IMIEC = 1; // GRC割り込み有効
  TW.TIERW.BIT.IMIED = 1; // GRD割り込み有効

  IO.PCR1 = 0xF0;         // ポート1のP14-17を出力設定
  IO.PCR5 = 0x0F;         // ポート5のP50-53を出力設定
  IO.PCR8 = 0xFF;         // ポート8は全部出力設定

  bStep = 1;              // ステップを0に初期化

  // データの初期化
  awServoPos[0] = 3000;  // 1.5msec   P14
  awServoPos[1] = 3200;  // 1.6msec   P15
  awServoPos[2] = 3400;  // 1.7msec   P16
  awServoPos[3] = 3600;  // 1.8msec   P17

  awServoPos[4] = 3800;  // 1.9msec   P50
  awServoPos[5] = 4000;  // 2.0msec   P51
  awServoPos[6] = 3000;  // 1.5msec   P52
  awServoPos[7] = 3200;  // 1.6msec   P53

  awServoPos[8] = 3400;  // 1.7msec   P80
  awServoPos[9] = 3600;  // 1.8msec   P81
  awServoPos[10] = 3800;  // 1.9msec   P82
  awServoPos[11] = 4000;  // 2.0msec   P83

  awServoPos[12] = 3000;  // 1.5msec   P84
  awServoPos[13] = 3200;  // 1.6msec   P85
  awServoPos[14] = 3400;  // 1.7msec   P86
  awServoPos[15] = 3600;  // 1.8msec   P87
  

  EI;                     // 割り込み許可

  TW.TCNT = TIMERW_2M5SEC;// タイマカウンタに2.5msec後にOVFする値設定
  TW.TMRW.BIT.CTS = 1;    // タイマスタート

  //文字列送信→PC
  //送信文字は 2桁_2桁
  SCI3_OUT_STRING ("\nサーボNo(2桁)  スペース  パルス長(2桁)入力\n");//文字列送信関数
  
  
  while( 1 ){
    // せっかくなのでパソコンからキーボード入力でサーボを
    // 動かすプログラムを書いてみましょ。
        SCI3_IN_STRING (b, sizeof(b) - 1);  //文字列受信関数
        SCI3_PRINTF("[%s]\n",b);          //オウム返し表示
        
  //受信文字 10進数へ変換
    //サーボ配列No
        SavNo = ( b[0]-'0')*10;
        SavNo += ( b[1]-'0');
        
    //パルス長
        Pls_w = ( b[3]-'0')*10;
        Pls_w += ( b[4]-'0');      

        if(SavNo<16 && Pls_w<25){    //範囲処理
              awServoPos[SavNo] = Pls_w*200;
        }
  }
}

       

 

PCとの通信

通信設定などに関しては

 パソコンと通信してみる を参考にしてください。

 

通信速度は main()最初の初期化で

 SCI3_INIT(br38400, txb, sizeof(txb), rxb, sizeof(rxb));

ボーレート38400に設定してあります。

ハイパーターミナル側も初期設定時には、この部分の数値に合わせてください。

 

パルス長を変えるには

このプログラムではラジコンサーボ用のパルス出力は

  配列  awServoPos[ 0~15 ] = パルス長×2000

の数値をパルス長時間としてタイマW時間にして、割り込みで毎回読み込んでいます。

ここの配列の数値を変更すると、対応する各ポートからパルスが数値に応じて出力されます。

配列に入れる数値は ここの設定ではパルス長の2000倍です。

 

ハイパーターミナルでの入力

簡単にするためにパソコンからハイパーターミナルでの数値の入力のカタチは

2桁 1桁 2桁
ラジコンサーボの配列番号(0~15) スペース パルス長(25未満)

としてあります。

 

  • ラジコンサーボの配列番号2桁   0~15
  • パルス長は 実際の10倍 2桁   0~24

をスペースで区切り、入力して送ることに。


これを守って
ラジコンサーボの配列番号2桁 に続いて
スペース1つ 続いてパルス長(25未満)2桁
をハイパーターミナルに入力

 

例)ポート80 のパルスを2.0ms にするなら

 awServoPos[8] = 4000; // P80
とすべきなので

  08_20 (_はスペースのコト)  
のように ハイパーターミナルに入力して送ります。

 8のように 1桁でも 08と必ず2桁にします。

 

3664Fでの受信と加工

文字列として配列b[] に受け取り、そのデータを数値にします。

 

ハイバーターミナルでの入力のカタチを決めてあるので、データは必ず5桁になるように来ます。(こうすることで受信と加工が簡単になります)

  • 最初の2桁の数値が b[0],b[1]に
  • ・b[3]にはスペース
  • b[4],b[5]にはパルス長の10倍に入力された数値

が1桁(0~9)ずつに分解されて文字列で配列b[]に受け取れます。

 

その文字列を10進数値に変換 変数SavNo 、Pls_w に入れています。

 

文字列→10進数値の変換処理もべた書きでやってます。

//受信文字 10進数へ変換
//サーボ配列No
    SavNo = ( b[0]-'0')*10;
    SavNo += ( b[1]-'0');
//パルス長
    Pls_w = ( b[3]-'0')*10;
    Pls_w += ( b[4]-'0');
    if(SavNo<16 && Pls_w<25){   //範囲処理
        awServoPos[SavNo] = Pls_w*200; //ここで受取り加工した数値を配列に入力!
    }

 

これを 配列 awServoPos[] に放り込んでるだけです。。
awServoPos[SavNo] = Pls_w*200; 
こんな方法で簡易的にできることになります
その代わり送信側での入力のカタチを守らなければ、入力でチェックは範囲以外なにもしません。
(文字列でなく、数値を直接送ればいいのでは、とも思いますが数値そのものは簡単に送れないので)

 

実行

 

ハイパーターミナル

まずはハイパーターミナルを起動します。
そのへんは   パソコンとシリアル通信する を見てください。本元のTekuRobo工作室の説明もみれば、通信の種類など基本的な説明が全部あるのでよくわかると思います。

 

このプログラムではボーレート38400に設定してあります。
ハイパーターミナル側も初期設定時には、この部分の数値に合わせてください。

3664F

続いて 3664Fを起動させると

hyperTerminal画面1

このようにでれば正しく接続されています。

 


ハイパーターミナルに入力

ここで

  • ラジコンサーボの配列番号2桁   0~15
  • パルス長は msの10倍 2桁   0~24

をスペースで区切り、入力


* 配列番号がどのポートなのかは、上の 回路図のところの表を参照

 

 入 力

 

ポートP80 のパルス長を 1.2msにしてみます。
ポートP80 は 配列番号8です。

hyperTerminal画面2

 

上図の行ように、まず

  8 12         と入力しました。
[8 12]  と入力がH8から返され表示されます

 

 

ポートP80パルス長を測定すると
 初期設定のまま 1.7ms
 で変化はありません。

 

 

8 12の
最初の8がいけないのです。
(入力のカタチを守りましょう, 自分でも忘れてました)

 

 

 目標通り 

 1.2msの
パルス長になっています。

 

 

上図の三番目 
  11 15   は 
ポートP83 を1.5msにする入力です。
* 配列番号がどのポートなのかは、上の 回路図のところの表を参照

確認できるポートは測定してみましたが、正しく変更されました。

 

 

 

スポンサーリンク
  • facebook
  • twtter
  • google+
  • hatena