2023年7月29日 星期六

ESP32 with HC-SR04 Ultrasonic Sensor

Purpose: 

The ultrasonic sensor uses sonar to determine the distance to an object. the ESP32 and provide several example sketches to determine the distance to an object using the HC-SR04.

Fundamental:

Introducing the HC-SR04 Ultrasonic Sensor(HC-SR04超音波模組)

The HC-SR04 ultrasonic sensor uses sonar to determine the distance to an object. This sensor reads from 2cm to 400cm (0.8inch to 157inch) with an accuracy of 0.3cm (0.1inches), which is good for most hobbyist projects. In addition, this particular module comes with ultrasonic transmitter and receiver modules.

超音波感測器有兩個大大的「眼睛」,很多機器人或小車結構都會利用這個感測器做避障功能,不過其實與其說是眼睛,不如說是「耳朵」,左下角標示的「T」是TX的意思,代表左邊的孔負責傳送(Transport)超音波,而右下角標示「R」是RX代表右側的耳朵負責接收(Receive)超音波回音,也就是左側是嘴巴負責發出聲音,而右側是耳朵負責聽回音,兩者缺一不可。

下方四個腳位則依序為VCC、Trig、Echo、GND,其中Trig代表嘴巴,決定何時發出聲音,Echo則代表耳朵,用來計算聽到回音的時間,再透過公式就可以計算距離了,而VCC與GND則與以往相同,接在5V及GND腳位,這裡說明一下目前超音波有多個版本,有少數版本僅能使用5V,而大多數是5V、3.3V都可用,因此個人建議接在5V的位置。音速 c = 331.5 + 0.607 * t  (其中 t 為攝氏溫度)。 

例: 攝氏20度時的音速約為: 331.5 +    0.607*20 = 343.64 公尺/秒

音速公尺/秒 換算成 公分/微秒:343.64 * 100 / 1000000 = 0.034364 公分/微秒,亦即

音速每公分需要29.1 微秒:  1 / 0.034364 = 29.1 微秒/公分

超音波發射的距離為來回,因此單程距離 = 時間差 / 2  再除以  29.1 微秒 / 公分,同樣的如果      要換算成英吋,只要將 29.1 再乘以 2.54 即可, 使用pulseIn()讀取脈衝訊號,並計算

Circuit:

要換算成英吋,只要將 29.1 再乘以 2.54 即可, 使用pulseIn()讀取脈衝訊號,並計算

YouTube Demonstration:



Code Introduce:

//--------- Flag structure --------------------------------------
typedef struct _vFlag
{
  uint8_t BTFlag = 0;
  uint8_t DC_Flag = 0;
  uint8_t CANFlag = 0;
  uint8_t I2C_Flag = 0;
  uint8_t BMP180Flag = 0;
  uint8_t HCSR04Flag = 0;
  uint8_t LEDFlag = 1;
  uint8_t initial_Flag = 0;
  uint8_t FunctionFlag = 3;
  uint8_t SendFlag = 0;
  uint8_t BMPCnt = 0;
} vFlag;
vFlag *flag_Ptr;
vFlag flag;
//------LED------------------
#define LED_BUILTIN 2
//-----hcsr04 sensor------------------
#define TRIGPIN_PIN  12//發出聲波腳位(ESP32 GPIO12)
#define ECHO_PIN    14//接收聲波腳位(ESP32 GPIO14)
//int TRIGPIN_PIN17=17;
//int ECHO_PIN16=16;
long duration;
int distance;
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
int interval = 1000;
//----------uart--------------
#define LINE_BUFFER_LENGTH 64
//--------- uart structure --------------------------------------
typedef struct _vUart
{
  char c;
  int lineIndex = 0;
  int line1Index = 0;
  int BTlineIndex = 0;
  bool lineIsComment;
  bool lineSemiColon;
  char line[128];
  char BTline[20];
  String inputString;
  String BTinputString;
  String S1inputString;
  int V[16];
  char ctemp[30];
  char I2C_Data[80];
  int DC_Spped = 50;
  float Voltage[16];
  int Buffer[128];
  int StartCnt = 0;
  int ReadCnt = 0;
  int sensorValue = 0;
} vUart;
vUart *Uart_Ptr;
vUart Uart;

//-------------------------------------------------
void setup()
{
  Serial.begin(9600);
  Serial.println(F("init"));
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(TRIGPIN_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
}
//-----------------------------------------
void loop()
{
  Serial.print(F("Main at core:"));
  Serial.println(xPortGetCoreID());
  while(1)
  {
    if(flag.LEDFlag == 1)
    {
      digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
      vTaskDelay(300);
      digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
      vTaskDelay(300);
    }
    while (Serial.available() > 0)
    {
      Uart.c = Serial.read();

      if ((Uart.c == '\n') || (Uart.c == '\r'))
      { // End of line reached
        if (Uart.lineIndex > 0)
        { // Line is complete. Then execute!
          Uart.line[Uart.lineIndex] = '\0'; // Terminate string
          //Serial.println( F("Debug") );
          //Serial.println( Uart.inputString );
          processCommand(Uart.line); // do something with the command
         
          Uart.lineIndex = 0;
          Uart.inputString = "";
        }
        else
        {
          // Empty or comment line. Skip block.
        }
        Uart.lineIsComment = false;
        Uart.lineSemiColon = false;
        Serial.println(F("ok>"));
      }
      else
      {
        //Serial.println( c );
        if ((Uart.lineIsComment) || (Uart.lineSemiColon))
        {
          if (Uart.c == ')')
            Uart.lineIsComment = false; // End of comment. Resume line.
        }
        else
        {
          if (Uart.c == '/')
          { // Block delete not supported. Ignore character.
          }
          else if (Uart.c == '~')
          { // Enable comments flag and ignore all characters until ')' or EOL.
            Uart.lineIsComment = true;
          }
          else if (Uart.c == ';')
          {
            Uart.lineSemiColon = true;
          }
          else if (Uart.lineIndex >= LINE_BUFFER_LENGTH - 1)
          {
            Serial.println("ERROR - lineBuffer overflow");
            Uart.lineIsComment = false;
            Uart.lineSemiColon = false;
          }
          else if (Uart.c >= 'a' && Uart.c <= 'z')
          { // Upcase lowercase
            Uart.line[Uart.lineIndex] = Uart.c - 'a' + 'A';
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += (char)(Uart.c - 'a' + 'A');
          }
          else
          {
            Uart.line[Uart.lineIndex] = Uart.c;
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += Uart.c;
          }
        }
      }
    } //while (Serial.available() > 0)
    if(flag.HCSR04Flag==1)
    {
      currentMillis = millis();
     
      pinMode(TRIGPIN_PIN, OUTPUT);
      digitalWrite(TRIGPIN_PIN, LOW);  //關閉超音波
      delayMicroseconds(2);  //sustain at least 10us HIGH pulse
      digitalWrite(TRIGPIN_PIN, HIGH); //啟動超音波
      delayMicroseconds(10);  //sustain at least 10us HIGH pulse
      digitalWrite(TRIGPIN_PIN, LOW);  //關閉超音波
      pinMode(ECHO_PIN, INPUT);
      duration= pulseIn(ECHO_PIN, HIGH);
      distance= duration/29/2;
      if (duration==0)
      {
        Serial.println("No pulse is from sensor");
      }
      else {
        Serial.print("Ultrasonic sensor is shown distance:");
        Serial.print(distance);
        Serial.println("cm");
      }
    }
  }
}
//----------------------------------------
void processCommand(char *data)
{
  int len, xlen, ylen, zlen, alen;
  int tempDIO;
  String stemp;

  len = Uart.inputString.length();
  //---------------------------------------
  if (strstr(data, "VER") != NULL)
  {
    Serial.println(F("ESP32_20230710"));
  }
   if (strstr(data, "HCSR04_ON") != NULL)
  {
    flag.HCSR04Flag = 1;
    flag.LEDFlag = 0;
    Serial.println(F("HCSR04_ON"));
  }
  if (strstr(data, "HCSR04_OFF") != NULL)
  {
    flag.HCSR04Flag = 0;
    flag.LEDFlag = 1;
    Serial.println(F("HCSR04_OFF"));
  }  
}
//-----------------------------------------


沒有留言:

張貼留言