リモコンカーのパーツも揃ったので作成に掛ります、今回のロボカーはモーター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; // 信号ピンを12へ IRrecv 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 への配線は分かります。