2024年1月1日月曜日

障害物回避ロボットカー ESP32

 
2018年に製作した障害物回避ロボットカーについて記事にしました。サーボモーター SG90を180度回転しながら超音波距離センサー HC-SR04で障害物を発見すると回避走行します。
走行方向をOLED・音声合成LSIで通知、圧電スピーカによる効果音に「スター・ウォーズ」R2-D2を使いました。

●同ブログ関連記事:【障害物回避ロボットカー ESP32 RemoteXY操作






動画


回路図



構成部品
上面
●ESP32NodeMCU開発ボード
●ATP3012R5-PU(小型ロボットの音声)
●サーボモーター SG90
●超音波距離センサー HC-SR04(障害物検知)


側面
●モバイルバッテリー 5000mAh(ESP32開発ボード電源)









内部
●デュアルモータードライバDRV8835
●TA7368使用小型アンプキット
●スピーカー(音声)
●圧電スピーカ(効果音)
●リチウムポリマー電池 3.7V(モーター電源)
●SSD1306 OLED




底面
●タミヤ ダブルギヤボックス(70168)
●タミヤ ボールキャスター(70144)
●タミヤ ユニバーサルプレート
●マイクロスイッチ(障害物検知)










モータ
●ノイズ対策
モータ電源端子⊕⊝間 セミコン104
モータ電源端子⊕-モータ金属ケース セミコン104
モータ電源端子⊝-モータ金属ケース セミコン104







Arduino IDE











プログラム
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <ESP_Adafruit_SSD1306.h>
#include <AquesTalk.h> 

#define OLED_RESET 4      //  21Pin SDA , 22PIN SCL
#define ServoPin  15      // Servo モータ    
#define LEDPin    16
#define SpeakPin  17      //スピーカ
#define LM1Pin    33      // AIN1 左モーター DRV8835
#define LM2Pin    32      // AIN2 左モーター
#define RM1Pin    26      // BIN1 右モーター
#define RM2Pin    25      // BIN2 右モーター
#define echoPin 27 // Echo Pin
#define trigPin 14 // Trigger Pin 
#define swPin 23   // Sw Pin 

Adafruit_SSD1306 display(OLED_RESET);
AquesTalk atp;  //インスタンス定義 変数名は任意

int PWM=150;                              //モーター回転数制御
int Distance = 0, rightDistance = 0, leftDistance = 0, middleDistance = 0;
int sw ;     

void Go(){
  ledcWrite(0, PWM);      
  ledcWrite(1, 0);           
  ledcWrite(2, PWM);          
  ledcWrite(3, 0); 
  display.clearDisplay(); // Clear the buffer.
  display.setTextColor(WHITE); 
  display.setTextSize(6);
  display.setCursor(30,10);
  display.println( "GO" );
  display.display();
  delay(10); 
}

void Left(){
  ledcWrite(0, 0);      
  ledcWrite(1, PWM);           
  ledcWrite(2, PWM);          
  ledcWrite(3, 0);  
  display.clearDisplay(); // Clear the buffer.
  display.setTextColor(WHITE); 
  display.setTextSize(4);
  display.setCursor(15,20);
  display.println( "LEFT" );
  display.display(); 
  delay(10);
}

void Stop(){
  ledcWrite(0, 0);      
  ledcWrite(1, 0);           
  ledcWrite(2, 0);          
  ledcWrite(3, 0);   
  display.clearDisplay(); // Clear the buffer.
  display.setTextColor(WHITE);
  display.setTextSize(4);
  display.setCursor(15,20);
  display.println( "STOP" );
  display.display(); 
  delay(10); 
}

void Right(){
  ledcWrite(0, PWM);      
  ledcWrite(1, 0);           
  ledcWrite(2, 0);          
  ledcWrite(3, PWM); 
  display.clearDisplay(); // Clear the buffer.
  display.setTextColor(WHITE);
  display.setTextSize(4);
  display.setCursor(0,20);
  display.println( "RIGHT" );
  display.display();
  delay(10);
  }

void Back(){
  ledcWrite(0, 0);      
  ledcWrite(1, PWM);           
  ledcWrite(2, 0);          
  ledcWrite(3, PWM); 
  display.clearDisplay(); // Clear the buffer.
  display.setTextColor(WHITE);
  display.setTextSize(4);
  display.setCursor(10,20);
  display.println( "BACK" );
  display.display(); 
  delay(10);
}

void L(){
  Left();
  atp.Synthe("hidari");  
  delay(750); 
  Stop();   
 
}
void GO(){
  Go();   
  atp.Synthe("zensin");    
}

void R(){
  Right(); 
  atp.Synthe("migi"); 
  delay(750); 
  Stop();   
}

 void LEFT(){
  Left();  
  atp.Synthe("sasetu");   
}

void STOP(){ 
  Stop();   
  atp.Synthe("sutoppu");  
}

void RIGHT(){
  Right();  
  atp.Synthe("usetu");  
}

void BACK(){
  Back();   
  atp.Synthe("bakku");    
}


void Auto() {      
      swon();      
      ledcWrite(6, 57);   //(-45)                     
      delay(350);
      rightDistance = Distance_test(); 
      if( rightDistance <= 30) { 
      Left();
      Tone(); 
      atp.Synthe("hidari");
      delay(200);
      swon(); 
      Go(); 
      }      
      swon();
      ledcWrite(6, 42);   //(-90)                          
      delay(350);
      rightDistance = Distance_test(); 
      if( rightDistance <= 20) {    
      Left();
      Tone(); 
      atp.Synthe("hidari");
      delay(100);
      swon();
      Go();           
      } 
      swon(); 
      ledcWrite(6, 73);   // ( 0 )     
      delay(700);      
      Distance = Distance_test();
      if( Distance <= 30) {  
      Search();     
      } 
      swon();
      ledcWrite(6, 88);  // (+45)      
      delay(350);                                   
      leftDistance = Distance_test(); 
      if(leftDistance <= 30) {   
      Right();
      Tone(); 
      atp.Synthe("migi");
      delay(200);
      Go();            
      } 
      swon();
      ledcWrite(6, 106);  // (+90)      
      delay(350);                                   
      leftDistance = Distance_test(); 
      if(leftDistance <= 20) {       
      Right();
      Tone();
      atp.Synthe("migi");
      delay(100);
      swon();
      Go();           
      }  
      swon();
      ledcWrite(6, 73);   //( 0 )                             
      delay(700);      
      Distance = Distance_test();
      if( Distance <= 30) {
      Search();       
      }
      swon(); 
      Go();  
   }

void   Search() {
  Stop();
  digitalWrite(LEDPin,HIGH);
  R2d2_tone();
  atp.Synthe("kakunin");  
  if(rightDistance > leftDistance) {  
  Back();
  delay(1000);
  digitalWrite(LEDPin,LOW);
  atp.Synthe("usetu");
  Right();    
  delay(1000);
  Go();
  }
  else if(rightDistance < leftDistance) {     
  Back();
  delay(1000);
  digitalWrite(LEDPin,LOW); 
  atp.Synthe("sasetu");        
  Left();   
  delay(1000);
  Go();
  }
  else if((rightDistance <= 30) || (leftDistance <= 30)) {  
  Back(); 
  atp.Synthe("sagari masu");  
  delay(2000);
  Right();    
  delay(750);
  }
  else {
  swon();
  Go();    //GO      
      }
    }  

void  swon() {
      sw = digitalRead(swPin ) ; //スイッチの状態を読む 
      if(sw== LOW){
      Back(); 
      atp.Synthe("kiken sagarimasu");  
      delay(3000);
      Right();    
      delay(750);
      }  
}

 // HC-SR04    
  int Distance_test() {
  digitalWrite(trigPin, LOW);   
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);  
  delayMicroseconds(20);
  digitalWrite(trigPin, LOW);   
  float Fdistance = pulseIn(echoPin, HIGH);  
  Fdistance= Fdistance / 58;       
  return (int)Fdistance;  
}

void R2d2_tone(){
    
  const int NOTE_NONE = NOTE_MAX;

  int melody[] = {
  NOTE_A, NOTE_G, NOTE_E, NOTE_C, NOTE_D, NOTE_B, NOTE_F, NOTE_C,
  NOTE_A, NOTE_G, NOTE_E, NOTE_C, NOTE_D, NOTE_B, NOTE_F, NOTE_C
  };

  int noteOctaves[] = {
  7, 7, 7, 7, 7, 7, 7, 8,
  7, 7, 7, 7, 7, 7, 7, 8
  };

  int noteDurations[] = {
  1, 1, 1, 1, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1
  };
  for (int thisNote = 0; thisNote < 16; thisNote++) {
    ledcWriteNote(4, (note_t)melody[thisNote], noteOctaves[thisNote]);
    int pauseBetweenNotes = 1000 / noteDurations[thisNote] * 0.1 ;
    delay(pauseBetweenNotes);
    ledcWriteTone(4, 0); // stop the tone playing:
  }  
}

void Tone() {
  digitalWrite(LEDPin,HIGH);
  ledcWriteTone(4, 800);
  delay(100);
  digitalWrite(LEDPin,LOW);
  ledcWriteTone(4, 0);   
}

void setup() {   
  pinMode(LM1Pin, OUTPUT); // AIN1
  pinMode(LM2Pin, OUTPUT); // AIN2
  pinMode(RM1Pin, OUTPUT); // BIN1
  pinMode(RM2Pin, OUTPUT); // BIN2
  pinMode(SpeakPin, OUTPUT); // スピーカ
  pinMode(ServoPin, OUTPUT); // Servo
  pinMode( echoPin, INPUT );
  pinMode( trigPin, OUTPUT );
  pinMode( swPin, INPUT );
    
  ledcSetup(0,490,8);     // モータ 0CH 490Hz 8bit=0-255(PWM)
  ledcSetup(1,490,8);     
  ledcSetup(2,490,8);     
  ledcSetup(3,490,8);
  ledcSetup(4,5000,13);   //スピーカ 4CH 5000Hz 13biT=0-8192(PWM)
  ledcSetup(6, 50, 10);  // 5ch 50 Hz 10bit=0-1023(PWM)
  
  ledcAttachPin(LM1Pin, 0); // モータ 0CH
  ledcAttachPin(LM2Pin, 1);
  ledcAttachPin(RM1Pin, 2); 
  ledcAttachPin(RM2Pin, 3);
  ledcAttachPin(SpeakPin, 4); //スピーカ 4CH 
  ledcAttachPin(ServoPin, 6); //サーボ  5ch 
   
  Wire.begin(21,22);  // (SDA,SCL)
  display.begin(SSD1306_SWITCHCAPVCC, 0x78>>1); // OLED ADDRESS

  Serial.begin(9600);  
  pinMode( LEDPin, OUTPUT);
  delay(500); 
  Go();
}

void loop() {  
  Auto();
}
  

0 件のコメント:

コメントを投稿

Raspberry Pi Donkey Car スマートカー

  2020年に製作したDonkey Car スマートカー について記事にしました。 Donkey CarはRaspberry Pi のカメラからコースを ディープラーニングさせ自動走行を行います。(動画は白線上を自動走行)   動画