Interfacing HC-SR04 Ultrasonic Sensor with ESP32 Using MicroPython
Tags: micropython, arduino, esp32, iot
Published: 2024-06-20 08:11:05


![Interfacing HC-SR04 Ultrasonic Sensor with ESP32 Using MicroPython](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nminlucxrpc9ifbgexwd.png)

#### Introduction

In this tutorial, we will learn how to interface the HC-SR04 ultrasonic sensor with an ESP32 microcontroller using MicroPython. The HC-SR04 sensor is used to measure distances accurately by sending out ultrasonic pulses and measuring the time it takes for the echo to return.

#### Prerequisites

Before we dive into the code, ensure you have the following:
- ESP32 microcontroller
- HC-SR04 ultrasonic sensor
- Breadboard and jumper wires
- MicroPython installed on the ESP32
- Thonny IDE or any other suitable IDE for writing and uploading MicroPython code

#### Code Explanation

We will use two scripts: `hcsr04.py` (a module for the HC-SR04 sensor) and `main.py` (the main script to read and display distance measurements).

### hcsr04.py Module Code

This module handles the low-level operations of the HC-SR04 sensor. It initializes the trigger and echo pins, sends out ultrasonic pulses, and measures the time it takes for the echo to return. This time is then converted to distance.

```python
import machine, time
from machine import Pin

__version__ = '0.2.0'
__author__ = 'Roberto Sánchez'
__license__ = "Apache License 2.0. https://www.apache.org/licenses/LICENSE-2.0"

class HCSR04:
    """
    Driver to use the untrasonic sensor HC-SR04.
    The sensor range is between 2cm and 4m.
    The timeouts received listening to echo pin are converted to OSError('Out of range')
    """
    # echo_timeout_us is based in chip range limit (400cm)
    def __init__(self, trigger_pin, echo_pin, echo_timeout_us=500*2*30):
        """
        trigger_pin: Output pin to send pulses
        echo_pin: Readonly pin to measure the distance. The pin should be protected with 1k resistor
        echo_timeout_us: Timeout in microseconds to listen to echo pin. 
        By default is based in sensor limit range (4m)
        """
        self.echo_timeout_us = echo_timeout_us
        # Init trigger pin (out)
        self.trigger = Pin(trigger_pin, mode=Pin.OUT, pull=None)
        self.trigger.value(0)

        # Init echo pin (in)
        self.echo = Pin(echo_pin, mode=Pin.IN, pull=None)

    def _send_pulse_and_wait(self):
        """
        Send the pulse to trigger and listen on echo pin.
        We use the method `machine.time_pulse_us()` to get the microseconds until the echo is received.
        """
        self.trigger.value(0) # Stabilize the sensor
        time.sleep_us(5)
        self.trigger.value(1)
        # Send a 10us pulse.
        time.sleep_us(10)
        self.trigger.value(0)
        try:
            pulse_time = machine.time_pulse_us(self.echo, 1, self.echo_timeout_us)
            return pulse_time
        except OSError as ex:
            if ex.args[0] == 110: # 110 = ETIMEDOUT
                raise OSError('Out of range')
            raise ex

    def distance_mm(self):
        """
        Get the distance in milimeters without floating point operations.
        """
        pulse_time = self._send_pulse_and_wait()

        # To calculate the distance we get the pulse_time and divide it by 2 
        # (the pulse walk the distance twice) and by 29.1 becasue
        # the sound speed on air (343.2 m/s), that It's equivalent to
        # 0.34320 mm/us that is 1mm each 2.91us
        # pulse_time // 2 // 2.91 -> pulse_time // 5.82 -> pulse_time * 100 // 582 
        mm = pulse_time * 100 // 582
        return mm

    def distance_cm(self):
        """
        Get the distance in centimeters with floating point operations.
        It returns a float
        """
        pulse_time = self._send_pulse_and_wait()

        # To calculate the distance we get the pulse_time and divide it by 2 
        # (the pulse walk the distance twice) and by 29.1 becasue
        # the sound speed on air (343.2 m/s), that It's equivalent to
        # 0.034320 cm/us that is 1cm each 29.1us
        cms = (pulse_time / 2) / 29.1
        return cms
```

### main.py Code

The main script imports the `HCSR04` class from the `hcsr04.py` module and uses it to continuously read and display distance measurements.

```python
# code written by Shemanto Sharkar (let's connect on LinkedIn: https://www.linkedin.com/in/shemanto/)
# step-1: importing necessary modules
from hcsr04 import HCSR04
from time import sleep

# step-2: telling ESP32 where our sensor's pins are connected
sensor = HCSR04(trigger_pin=5, echo_pin=18, echo_timeout_us=10000)

# step-3: reading data continuously inside loop
while True:
  try:
    distance = sensor.distance_cm()
    print('Distance:', distance, 'cm')
    sleep(1)

  except OSError as e: # Error Handling  
    print("Error Data")
```

### Detailed Code Breakdown

1. **Importing Necessary Modules:**
   ```python
   from hcsr04 import HCSR04
   from time import sleep
   ```
   - `from hcsr04 import HCSR04`: Imports the `HCSR04` class from the `hcsr04` module.
   - `from time import sleep`: Imports the `sleep` function from the `time` module for introducing delays.

2. **Setting Up the Sensor:**
   ```python
   sensor = HCSR04(trigger_pin=5, echo_pin=18, echo_timeout_us=10000)
   ```
   - `sensor = HCSR04(trigger_pin=5, echo_pin=18, echo_timeout_us=10000)`: Initializes the HC-SR04 sensor with the trigger pin connected to GPIO 5 and the echo pin connected to GPIO 18. The `echo_timeout_us` parameter sets the timeout for listening to the echo signal.

3. **Reading Data Continuously:**
   ```python
   while True:
     try:
       distance = sensor.distance_cm()
       print('Distance:', distance, 'cm')
       sleep(1)
    
     except OSError as e:
       print("Error Data")
   ```
   - `while True`: Starts an infinite loop to continuously read data from the sensor.
   - `distance = sensor.distance_cm()`: Reads the distance measurement from the sensor in centimeters.
   - `print('Distance:', distance, 'cm')`: Prints the distance measurement to the console.
   - `sleep(1)`: Introduces a delay of 1 second before the next reading.
   - `except OSError as e`: Catches any errors that occur during the reading process and prints an error message.

### Diagram

Here’s a diagram illustrating the connections:

```
ESP32 Microcontroller:
----------------------
        ___________
       |           |
       |           |
       |           |
       |    5      |--------> HC-SR04 (Trigger Pin)
       |           |
       |    18     |--------> HC-SR04 (Echo Pin)
       |___________|
         |
         |
       GND
       VCC (5V)
```

**Connections:**
- Connect the VCC pin of the HC-SR04 to the 5V pin of the ESP32.
- Connect the GND pin of the HC-SR04 to the GND pin of the ESP32.
- Connect the Trigger pin of the HC-SR04 to GPIO pin 5 of the ESP32.
- Connect the Echo pin of the HC-SR04 to GPIO pin 18 of the ESP32.

### Conclusion

By following this tutorial, you will be able to measure distances using an HC-SR04 ultrasonic sensor with an ESP32 microcontroller running MicroPython. This basic setup can be extended for various applications like obstacle detection, distance measurement, and more. Happy coding!

If you have any questions or need further assistance, feel free to reach out on LinkedIn: [Shemanto Sharkar](https://www.linkedin.com/in/shemanto/).