リモコンカーのパーツも揃ったので作成に掛ります、今回のロボカーはモーター2個とボールキャスター1個の仕様で作成します。
ロボカーのシャーシ作成
シャーシーは前回と同様3Dプリンターで作成しますが、今回は初めてPETGフィラメントを使用しました。
ABSより縁のソリは出ませんが糸引きが結構出ます、堅さはABSよりはありますね。
主要パーツ
Arduino NANOに拡張ボードを使用しています、その他モータードライバー、リモコン、ソナー、サーボ、モーターなどです、ボールキャスターはホームセンターにあったものを使用します。
組み立てとスケッチの書き込み
モータードライバーはシャーシーの下に取付けArduino NANOは拡張ボードに差し込み上部に両面テープで固定。
ソナーはサーボホーンと一緒にサーボにネジ止め、赤外線センサーは角度を付けて両面テープでシャーシーに貼り付けました。
モータードライバーへは7.4Vのリポ電池を使用、このモータードライバーは5V出力端子がありますのでここからArduinoに電源供給しています。
スケッチはここを参考にリモコンに合わせて設定しました、リモコンでの操作とソナー使用の自動走行をリモコンで切り替えが出来ます。
スケッチのリンクが切れてますのでスケッチを載せておきます。
//モーター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 への配線は分かります。