ブログだいちゃん

ブログだいちゃん

趣味のブログ

ブログだいちゃん

赤外線リモコンでロボカーを動かす 完結編

リモコンカーのパーツも揃ったので作成に掛ります、今回のロボカーはモーター2個とボールキャスター1個の仕様で作成します。

ロボカーのシャーシ作成

シャーシーは前回と同様3Dプリンターで作成しますが、今回は初めてPETGフィラメントを使用しました。

ABSより縁のソリは出ませんが糸引きが結構出ます、堅さはABSよりはありますね。

主要パーツ

Arduino NANO拡張ボードを使用しています、その他モータードライバーリモコンソナーサーボモーターなどです、ボールキャスターはホームセンターにあったものを使用します。

組み立てとスケッチの書き込み

モータードライバーはシャーシーの下に取付けArduino NANOは拡張ボードに差し込み上部に両面テープで固定。

ソナーはサーボホーンと一緒にサーボにネジ止め、赤外線センサーは角度を付けて両面テープでシャーシーに貼り付けました。

モータードライバーへは7.4Vのリポ電池を使用、このモータードライバーは5V出力端子がありますのでここからArduinoに電源供給しています。

スケッチはここを参考にリモコンに合わせて設定しました、リモコンでの操作とソナー使用の自動走行をリモコンで切り替えが出来ます。

スケッチのリンクが切れてますのでスケッチを載せておきます。

#include <IRremote.h>  //赤外線リモコンライブラリー
#include <Servo.h>    //サーボライブラリー

//モーターAの設定
const int enA = 5;     //モーターA速度設定ピン
const int MotorA1 = 4; //固定変数設定(const)
const int MotorA2 = 7; 

//モーターBの設定 
const int enB = 6;     //モーターB速度設定ピン
const int MotorB1 = 8;
const int MotorB2 = 9;

//ソナーピン設定
const int trigger=10;
const int echo=11;

int leftscanval, centerscanval, rightscanval, ldiagonalscanval, rdiagonalscanval; //int(整数型)
char choice; //キャラクター(char)
  
//赤外線コントロール設定
int receiver = 12;         // 信号ピンを12IRrecv irrecv(receiver);  
decode_results results; 
char contcommand;
int modecontrol=0;
int power=0;

const int distancelimit = 27;     //前方障害物の距離制限 27cm          
const int sidedistancelimit = 12; //両側の障害物までの最小距離(12cm)
int distance;                     //距離は整数
int numcycles = 0;
char turndirection;               //どの方向が障害物フリーであるかに応じて 'l''r'または 'f'を取得します。
const int turntime = 600;         //ロボットが回転している時間(ミリ秒)実際に動かし設定する
int thereis;
Servo head;

void setup(){
  head.attach(3);           //サーボは3ピン
  head.write(80);           //サーボ角度80度
  irrecv.enableIRIn();      // 赤外線受信開始
  pinMode(enA, OUTPUT);     //モーターアウトプット設定
  pinMode(MotorA1, OUTPUT);
  pinMode(MotorA2, OUTPUT); 
  pinMode(enB, OUTPUT);
  pinMode(MotorB1, OUTPUT); 
  pinMode(MotorB2, OUTPUT);
  pinMode(trigger,OUTPUT);  //超音波設定
  pinMode(echo,INPUT);

  //変数の初期化(モーターストップ)
  digitalWrite(MotorA1,LOW);
  digitalWrite(MotorA2,LOW);
  digitalWrite(MotorB1,LOW);
  digitalWrite(MotorB2,LOW);
  analogWrite(enA, 0);
  analogWrite(enB, 0); 
  digitalWrite(trigger,LOW);
}
 //前進
void go(){ 
   analogWrite(enA, 102);
   analogWrite(enB, 100); 
   digitalWrite (MotorA1, HIGH);                              
   digitalWrite (MotorA2, LOW); 
   digitalWrite (MotorB1, HIGH); 
   digitalWrite (MotorB2, LOW);
}
 //バック
void backwards(){
   analogWrite(enA, 100);
   analogWrite(enB, 100);  
   digitalWrite (MotorA1, LOW);                              
   digitalWrite (MotorA2, HIGH); 
   digitalWrite (MotorB1, LOW); 
   digitalWrite (MotorB2, HIGH);
}
//sonarで距離測定
int watch(){  
  long howfar;
  digitalWrite(trigger,LOW);
  delayMicroseconds(5);                                                                              
  digitalWrite(trigger,HIGH);
  delayMicroseconds(15);
  digitalWrite(trigger,LOW);
  howfar=pulseIn(echo,HIGH);
  howfar=howfar*0.01657; //障害物がどれくらい離れているかcm
  return round(howfar);
}
//左折
void turnleft(int t){  
   analogWrite(enA, 100);
   analogWrite(enB, 100); 
  digitalWrite (MotorA1, LOW);                              
  digitalWrite (MotorA2, HIGH); 
  digitalWrite (MotorB1, HIGH); 
  digitalWrite (MotorB2, LOW);
  delay(t);
}
//右折
void turnright(int t){  
   analogWrite(enA, 100);
   analogWrite(enB, 100); 
  digitalWrite (MotorA1, HIGH);                              
  digitalWrite (MotorA2, LOW); 
  digitalWrite (MotorB1, LOW); 
  digitalWrite (MotorB2, HIGH);
  delay(t);
}  
 //ストップ
void stopmove(){ 
  digitalWrite (MotorA1 ,LOW);                              
  digitalWrite (MotorA2, LOW); 
  digitalWrite (MotorB1, LOW); 
  digitalWrite (MotorB2, LOW);
}  

void watchsurrounding(){ //左右、右対角、左対角線の距離を測り、それらをcm単位で変数rightscanval、
                         //leftscanval、centerscanval、ldiagonalscanvalとrdiagonalscanvalに代入する
  centerscanval = watch();
  if(centerscanval<distancelimit){stopmove();}
  head.write(120);
  delay(100);
  ldiagonalscanval = watch();
  if(ldiagonalscanval<distancelimit){stopmove();}
  head.write(160); //サーボの可動範囲(角度)を設定する
  delay(300);
  leftscanval = watch();
  if(leftscanval<sidedistancelimit){stopmove();}
  head.write(120);
  delay(100);
  ldiagonalscanval = watch();
  if(ldiagonalscanval<distancelimit){stopmove();}
  head.write(80); //160度スパンの中心角(サーボを180度動かすと90度を使用します)
  delay(100);
  centerscanval = watch();
  if(centerscanval<distancelimit){stopmove();}
  head.write(40);
  delay(100);
  rdiagonalscanval = watch();
  if(rdiagonalscanval<distancelimit){stopmove();}
  head.write(0);
  delay(100);
  rightscanval = watch();
  if(rightscanval<sidedistancelimit){stopmove();}

  head.write(80); //前方を向いて終了
  delay(300);
}

char decide(){   //距離がある方向のキャラクターを設定(l,r,f)
  watchsurrounding();
  if (leftscanval>rightscanval && leftscanval>centerscanval){
    choice = 'l';
  }
  else if (rightscanval>leftscanval && rightscanval>centerscanval){
    choice = 'r';
  }
  else{
    choice = 'f';
  }
  return choice;
}

void translateIR() {      //リモコンキーによる動作
  switch(results.value)
  {
  case 0xFF18E7:          //前進(↑)
    go();
    break;
  case 0xFF10EF:          //左折(←)
    turnleft(turntime); 
    stopmove();  
    break;
  case 0xFF38C7:            //ストップ(OK)
    stopmove();   
    break;
  case 0xFF5AA5:          //右折(→)
    turnright(turntime);
    stopmove(); 
    break;
  case 0xFF4AB5:          //バック(↓)
    backwards();
    break;
  case 0xFF6897:          //自動走行(*)
    modecontrol=0; stopmove(); // 「*」が受信された場合、自動ロボット動作モードに切り替える
    break;
  default: 
    ;
  }// 終了
  delay(500);             // .5秒待機
} 

  //======メインルーチン======
void loop(){ 
  if (irrecv.decode(&results)){    //リモコンが信号を送信しているかどうかを確認する
    if(results.value==0xFFB04F){   //#」が受信された場合は、ロボットをオンにします
      power=1; }
    if(results.value==0xFF9867){   //0」が受信された場合、ロボットをオフにする
      stopmove(); 
      power=0; }
    if(results.value==0xFF6897){   //(*)を受信した場合は、自動ロボット<==>遠隔操作の切替
      modecontrol=1;               //  リモコン操作モードを有効にする
      stopmove();                  //ロボットは停止し、ユーザーの指示に応答します
    }
    irrecv.resume();               // 赤外線を受信する
  }
  
  while(modecontrol==1){  //modecontrol = 0 (*)になるまで、システムはリモート制御モード中にこのループに入ります
    if (irrecv.decode(&results)){   //何かが受信されている場合
      translateIR();                //受信した信号に応じた動作をする
      irrecv.resume();              // 赤外線を受信する
     }
  }
  if(power==1){
  go();                             // 何もなければ前進
  ++numcycles;
  if(numcycles>130){                //前進中に130度以内の障害物を探す 
    watchsurrounding();
    if(leftscanval<sidedistancelimit || ldiagonalscanval<distancelimit){
      turnright(turntime);
    }
    if(rightscanval<sidedistancelimit || rdiagonalscanval<distancelimit){
      turnleft(turntime);
    }
    numcycles=0;                //サイクル数を0にする
  }
  distance = watch();           // watch()関数を使用して前方確認
  if (distance<distancelimit){  // 前方に障害物があれば停止する、超音波センサーの誤動作を無視するため(25回試す)
      ++thereis;}
  if (distance>distancelimit){
      thereis=0;}               //カウント再開
  if (thereis > 25){
    stopmove();                 // 前方に何かあればストップ
    turndirection = decide();   //曲がる方向を決める
    switch (turndirection){
      case 'l':
        turnleft(turntime);
        break;
      case 'r':
        turnright(turntime);
        break;
      case 'f':
        ;                       //前方に何もなければ前進
        break;
    }
    thereis=0;
  }
 }
}

 

配線図はありませんが、スケッチの内容を見ればArduino への配線は分かります。