TVのリモコンで車ラジコンを操作する

〔マイコンのトップに戻る〕


前回の記事で”赤外線リモコンを送信器にして何か動かす”を書きました、
今回その記事を利用した応用例として、車のラジコンを作りそれをTVのリモコンで操作する記事を書きます。

まずは、回路図などを見て下さい。
(Fritzing用のTA7291P部品ダウンロードはこちらからお願いします。)
 回路図1
回路図2
 この回路のモータ電源は図では3Vですが、実際は6V程必要です。
 (今回は利用したモータの定格電圧が不明ですが9V掛けて見ました)
 また、arduinoの外部電源9Vも必要です、お忘れなく!。
 この回路に赤外線受信用のIRモジュールを取付けます、
 回路は前回の記事を参照下さい。

 それとぉ、モータにはノイズキャンセラーコンデンサ(0.1uF)を
 取付けます、左写真を参考に。
 3個も付いていますが最低端子間の1個でOKと思えます.....


今回はこの回路を、壊れたおもちゃの車が在ったので、
モータ部分のみ取出す為に更に壊しましたぁ o(*^▽^*)oエヘ。
IRモジュールも壊れたおもちゃから取出してぇ、って言うかぁ、はいぶつりよぅお。
これに上記回路を乗せて見ました、
ほんとぉ〜にぃ、ガムテープでぇただ乗せただけのぉ、恥ずかしい車ですぅ、
ちゃんとぉ、基板に半田付してぇ作れば見栄えも立派になるのですがぁ.....実験ですからぁ。
この位言い訳しておけば見せても良いかなぁ、
はい、これ!
完成写真
 きゃ〜ぁ、恥ずかしい **(/▽/)**
 みせちゃったぁ〜

 購入する場合は
 タミヤのツインモーターギヤーボックス
 利用すればOKと思います。
 ただ付属のFA-130モータは定格電圧が
 3Vです、電圧6V位まではOKでしょう、
 但し、寿命が短くなると思いますが。
 今回はPWM制御なのでそこまでは流れないけどね。


リモコン
これが今回利用したSHARP(AQuos)のTVリモコンです。

[▲]ボタン:スピードアップ
[▼]ボタン:スピードダウン
[>]ボタン:右回転(押し続けると回転が速くなります)
[<]ボタン:左回転
[決定]ボタン:ブレーキ
[終了]ボタン:回転終了(左右回転を止めます)
[ツール]ボタン:前進・後進の切替え(停止中で操作可能)

《arduinoのスケッチプログラム》

@上記の回路の様に配線を行います。

Aarduinoボード(Arduino Duemilanove 328)はUSBケーブルで接続して、arduino IDEを起動させます。

BIDEに下記のスケッチプログラムをコピーペーストして貼り付けて下さい。
 このスケッチをダウンロードしたい方はこちら
 ダウンロードスケッチの保存先と開き方はこちらを参照下さい。
---------------------------------------------------------------------
#define IR_PIN          2	// 赤外線受信モジュール接続ピン

#define ML_PWM_PIN      3     // モーター(左)接続ピン
#define ML_IN1_PIN      4
#define ML_IN2_PIN      5
#define MR_PWM_PIN      6     // モーター(右)接続ピン
#define MR_IN1_PIN      8
#define MR_IN2_PIN      7

#define DATA_POINT      5	// 受信したデータから読取る内容のデータ位置
#define SPEED_OFFST     7	// 左右のモータ速度を合わせる為の調整用

int FR_flag ;				// 前進・後進の状態フラグ
int LR_flag ;				// 左右回転の状態フラグ
int Speed_L ;				// モーター(左)の速度値
int Speed_R ;				// モーター(右)の速度値

void setup()
{
     pinMode(IR_PIN,INPUT) ;			// 赤外線受信モジュール接続ピンを入力に設定
     pinMode(ML_IN1_PIN,OUTPUT) ;		// モーター(左)接続ピン1を出力に設定
     pinMode(ML_IN2_PIN,OUTPUT) ;		// モーター(左)接続ピン2を出力に設定
     Speed_L = 0 ;					// モーター(左)の速度を0に初期化
     analogWrite(ML_PWM_PIN,0) ;
     digitalWrite(ML_IN1_PIN, HIGH);	// モーター(左)正転(前進)
     digitalWrite(ML_IN2_PIN, LOW) ;
     pinMode(MR_IN1_PIN,OUTPUT) ;		// モーター(右)接続ピン1を出力に設定 (*1)
     pinMode(MR_IN2_PIN,OUTPUT) ;		// モーター(右)接続ピン2を出力に設定 (*1)
     Speed_R = 0 ;					// モーター(右)の速度を0に初期化
     analogWrite(MR_PWM_PIN,0) ;
     digitalWrite(MR_IN1_PIN, HIGH);	// モーター(右)正転(前進)
     digitalWrite(MR_IN2_PIN, LOW) ;
     FR_flag = 0 ;  				// 前進状態に設定
     LR_flag = 0 ;                      // 回転はしていない状態に設定
}
void loop()
{
     int ans , l , r ;

     ans = IRrecive() ; // 赤外線リモコンのデータを受信する
     if (ans != 0) {    // データを受信したら処理する
          switch(ans) {
           case 0xD8: // [>]ボタン:右回転
                    if (Speed_L == 0) {
                         // 停止中
                         Speed_R++ ;
                         if (Speed_R == 1) Speed_R = 2 ;
                         if (Speed_R >= 9) Speed_R = 9 ;
                         // 右モータを後進させる
                         digitalWrite(MR_IN1_PIN, LOW) ;
                         digitalWrite(MR_IN2_PIN, HIGH) ;
                    } else {
                         LR_flag = 1 ;
                         Speed_R-- ;
                         if (Speed_R <= 1) Speed_R = 0 ;
                    }
                    break ;
           case 0xD7: // [<]ボタン:左回転
                    if (Speed_R == 0) {
                         // 停止中
                         Speed_L++ ;
                         if (Speed_L == 1) Speed_L = 2 ;
                         if (Speed_L >= 9) Speed_L = 9 ;
                         // 左モータを後進させる
                         digitalWrite(ML_IN1_PIN, LOW) ;
                         digitalWrite(ML_IN2_PIN, HIGH) ;
                    } else {
                         LR_flag = 2 ;
                         Speed_L-- ;
                         if (Speed_L <= 1) Speed_L = 0 ;
                    }
                    break ;
           case 0x57: // [▲]ボタン:スピードUP
                    Speed_L++ ;
                    if (Speed_L == 1) Speed_L = 2 ;
                    if (Speed_L >= 9) Speed_L = 9 ;
                    Speed_R++ ;
                    if (Speed_R == 1) Speed_R = 2 ;
                    if (Speed_R >= 9) Speed_R = 9 ;
                    break ;
           case 0x20: // [▼]ボタン:スピードDOWN
                    Speed_L-- ;
                    if (Speed_L <= 1) Speed_L = 0 ;
                    Speed_R-- ;
                    if (Speed_R <= 1) Speed_R = 0 ;
                    break ;
           case 0xF5: // [終了]ボタン:回転終了
                    // 回転を停止させる処理
                    if (LR_flag != 0) {	// 左右に回転中か?
                         if (LR_flag == 1) {
                              // 右回転中
                              Speed_R = Speed_L ;
                         } else {
                              // 左回転中
                              Speed_L = Speed_R ;
                         }
                         LR_flag = 0 ;
                         break ;
                    }
           case 0x52: // [決定]ボタン:ブレーキ
                    // 前進・後進を停止させる処理
                    LR_flag = 0 ;
                    Speed_L = 0 ;
                    Speed_R = 0 ;
                    analogWrite(ML_PWM_PIN,0) ;
                    analogWrite(MR_PWM_PIN,0) ;
                    delayMicroseconds(500) ;
                    digitalWrite(ML_IN1_PIN, HIGH) ;
                    digitalWrite(ML_IN2_PIN, HIGH) ;
                    digitalWrite(MR_IN1_PIN, HIGH) ;
                    digitalWrite(MR_IN2_PIN, HIGH) ;
                    delay(500) ;
                    if (FR_flag != 0) {
                         digitalWrite(ML_IN1_PIN, LOW) ;
                         digitalWrite(ML_IN2_PIN, HIGH) ;
                         digitalWrite(MR_IN1_PIN, LOW) ;
                         digitalWrite(MR_IN2_PIN, HIGH) ;
                    } else {
                         digitalWrite(ML_IN1_PIN, HIGH) ;
                         digitalWrite(ML_IN2_PIN, LOW) ;
                         digitalWrite(MR_IN1_PIN, HIGH) ;
                         digitalWrite(MR_IN2_PIN, LOW) ;
                    }
                    break ;
           case 0xbc: // [ツール]ボタン:前進/後進の切替え
                    if (Speed_L == 0 && Speed_R == 0) { // 停止中で切替えOK
                         if (FR_flag == 0) {
                              // 後進処理
                              FR_flag = 1 ;
                              digitalWrite(ML_IN1_PIN, LOW) ;
                              digitalWrite(ML_IN2_PIN, HIGH) ;
                              digitalWrite(MR_IN1_PIN, LOW) ;
                              digitalWrite(MR_IN2_PIN, HIGH) ;
                         } else {
                              // 前進処理
                              FR_flag = 0 ;
                              digitalWrite(ML_IN1_PIN, HIGH) ;
                              digitalWrite(ML_IN2_PIN, LOW) ;
                              digitalWrite(MR_IN1_PIN, HIGH) ;
                              digitalWrite(MR_IN2_PIN, LOW) ;
                         }
                    }
                    break ;
          }
          // スピードデータをPWM値に変更する
          // 左モータの回転が右より早いのでここでPWM値を少し減らす
          if (Speed_L == 2) l = map(Speed_L,0,9,0,255) - SPEED_OFFST ;
          else l = map(Speed_L,0,9,0,255) - (SPEED_OFFST*Speed_L) ;
//          l = map(Speed_L,0,9,0,255) ;
          r = map(Speed_R,0,9,0,255) ;
          // 実際にモータへPWM出力
          analogWrite(ML_PWM_PIN,l) ; // 0-255(50-255)
          analogWrite(MR_PWM_PIN,r) ; // 0-255(50-255)

          delay(300) ;                // 300msリモコンチャタリング防止
     }
}
/*******************************************************************************
*  IRrecive - 赤外線リモコンの送信データを受信する関数                         *
*             DATA_POINTで指定した位置のデータ(8ビット)を読み取ります。       *
*                                                                              *
*    戻り: 読み取った整数値を返します                                          *
*******************************************************************************/
int IRrecive()
{
     unsigned long t ;
     int i , j ;
     int cnt , ans ;
     char IRbit[64] ;

     ans = 0 ;
     t = 0 ;
     if (digitalRead(IR_PIN) == LOW) {
          // リーダ部のチェックを行う
          t = micros() ;                          // 現在の時刻(us)を得る
          while (digitalRead(IR_PIN) == LOW) ;	// HIGH(ON)になるまで待つ
          t = micros() - t ;					// LOW(OFF)の部分をはかる
     }
     // リーダ部有りなら処理する(3.4ms以上のLOWにて判断する)
     if (t >= 3400) {
          i = 0 ;
          while(digitalRead(IR_PIN) == HIGH) ;	// ここまでがリーダ部(ON部分)読み飛ばす
          // データ部の読み込み
          while (1) {
               while(digitalRead(IR_PIN) == LOW) ;// OFF部分は読み飛ばす
               t = micros() ;
               cnt = 0 ;
               while(digitalRead(IR_PIN) == HIGH) {// LOW(OFF)になるまで待つ
                    delayMicroseconds(10) ;
                    cnt++ ;
                    if (cnt >= 1200) break ;		// 12ms以上HIGHのままなら中断
               }
               t = micros() - t ;
               if (t >= 10000) break ;			// ストップデータ
               if (t >= 1000)  IRbit[i] = (char)0x31 ;	// ON部分が長い
               else            IRbit[i] = (char)0x30 ;	// ON部分が短い
               i++ ;
          }
          // データ有りなら指定位置のデータを取り出す
          if (i != 0) {
               i = (DATA_POINT-1) * 8 ;
               for (j=0 ; j < 8 ; j++) {
                    if (IRbit[i+j] == 0x31) bitSet(ans,j) ;
               }
          }
     }
     return( ans ) ;
}
---------------------------------------------------------------------
CIDEツールバーの赤枠部分「Upload」ボタンをクリックしてコンパイルとarduinoボードに書込みを行います。

upload

Dリモコンを押してみて、動くかなぁ?

左右のモータに同じPWM値を出力しましたが、真直ぐ行かず右に少し曲がりました、
左モータの回転が少し早い用です、右のモータが劣化しているのかも?、
左モータの出力に電流制限抵抗を入れて見ようと思ったのですが、
ソフトで調整してみる事にしました、
それで、PWMの出力の所に
if (Speed_L == 2) l = map(Speed_L,0,9,0,255) - SPEED_OFFST ;
else l = map(Speed_L,0,9,0,255) - (SPEED_OFFST*Speed_L) ;
が入っていますが、真っ直ぐ走るなら、この2行を
l = map(Speed_L,0,9,0,255)
にして下さい。

使用するリモコンによって次の行を変更する必要があります。
#define DATA_POINT      5	// 受信したデータから読取る内容のデータ位置
           case 0xD8: // [>]ボタン:右回転
           case 0xD7: // [<]ボタン:左回転
           case 0x57: // [▲]ボタン:スピードUP
           case 0x20: // [▼]ボタン:スピードDOWN
           case 0xF5: // [終了]ボタン:回転終了
           case 0x52: // [決定]ボタン:ブレーキ
           case 0xbc: // [ツール]ボタン:前進/後進の切替え
変更方法は前回の記事を読みましょう。

《その他》

出力波形  秋月通商のLCDオシロスコープキットでモータの出力を表示させて
 見ました。
 arduinoのPWM出力は約4.2V程で、TA7291PのVref(4番ピン)へ入力
 されます。
 でぇ、TA7291Pのモータ電圧Vs(8番ピン)は測った所8.2Vでした、
 でもモータ出力(OUT1-OUT2)は4.5V程のPWM出力(左図)です。
 だからぁ、TA7291Pの損失電圧1.2V+4.5V=5.7Vなのでぇ
 モータ電圧Vsは6V(今回9V電池接続)からって事でしょうかね。
それにぃ、ロジック側電圧Vccは4.5Vからの様です、arduino電源回路は3.3Vでは無理っぽいですね。

TA7291Pデータシートの応用回路例を見るとVs(8番ピン)とVcc(7番ピン)は電解コンデンサを介してGNDに接続されています、 基板で半田付けして作る場合はコンデンサ入れた方が良いでしょう。

あとぉ、このままの状態回路ではモータから発振音がします。対策必要かな?


追記(*1) 2011/8/28


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2011 Shigehiro Kimura All Rights Reserved.