ultrasonic module

This commit is contained in:
ImplFerris 2024-12-28 19:08:28 +05:30
parent 7c9590ef07
commit 347fea4b8f
16 changed files with 506 additions and 15 deletions

View File

@ -16,3 +16,7 @@
- [Fading LED](./led/index.md)
- [Code](./led/code.md)
- [External LED](./led/external-led.md)
- [Ultrasonic](./ultrasonic/index.md)
- [How it works?](./ultrasonic/how-it-works.md)
- [Circuit](./ultrasonic/circuit.md)
- [Code](./ultrasonic/code.md)

View File

@ -50,4 +50,4 @@ Voltage dividers are used in applications like potentiometers, where the resista
## Simulator
I used the website [https://www.falstad.com/circuit/e-voltdivide.html](https://www.falstad.com/circuit/e-voltdivide.html) to create this diagram. It's a great tool for drawing circuits. You can download the file I created, [`voltage-divider.circuitjs.txt`](./voltage-divider.circuitjs.txt), and import it to experiment with the circuit.
I used the website [https://www.falstad.com/circuit/](https://www.falstad.com/circuit/) to create this diagram. It's a great tool for drawing circuits. You can download the file I created, [`voltage-divider.circuitjs.txt`](./voltage-divider.circuitjs.txt), and import it to experiment with the circuit.

View File

@ -1,4 +1,4 @@
## Code
## Writing Rust Code to Create an LED Fading Effect on ESP32
Now comes the fun part; let's dive into the coding!

View File

@ -10,7 +10,7 @@ We will gradually increment the PWM's duty cycle to increase the brightness, the
"
Come in close... Closer...
Because the more you think you see... The easier itll be to fool you...
Because the more you think you see... The easier it'll be to fool you...
Because, what is seeing?.... You're looking but what you're really doing is filtering, interpreting, searching for meaning...
"

131
src/ultrasonic/circuit.md Normal file
View File

@ -0,0 +1,131 @@
## Connecting HC-SR04 ultrasonic sensor with ESP32
### Why We Need a Voltage Divider?
You can skip this, if you have HC-SR04+ which accepts 3.3V power supply also.
Before diving into the connection, You should familiarize yourself with the concept of a voltage divider; You can refer to [this chapter](../core-concepts/voltage-divider.md). As we mentioned earlier, we need to power the module using a 5V power supply, which can be supplied through the Vin pin of the ESP32. The module sends back the signal through the Echo pin. However, the ESP32 is only around 3.6V tolerant on its GPIO pins, so we need to reduce the voltage using a voltage divider between the Echo pin and the ESP32's GPIO pin.
To make this work, you'll need two resistors with different values, ensuring the output voltage is approximately 3.3V. For example, you can use a 1kΩ resistor as R1 and a 2kΩ resistor as R2, which will bring the voltage down to around 3.3V.
<img style="display: block; margin: auto;" alt="ultrasonic" src="./images/voltage-divider-hc-sr04-3_3_v.png"/>
If you want to experiment with different resistor values, you can use the [Falstd website](https://www.falstad.com/circuit/) with this [voltage-divider circuit text file](./voltage-divider-hc-sr04.txt). It allows you to modify the values of R1 and R2 to see what voltage each combination will output. This way, you can create the voltage divider with the resistors you have on hand.
## Circuit for HC-SR04
<table>
<thead>
<tr>
<th>ESP32 Pin</th>
<th style="height: 4px; width: 250px; margin: 0 auto;">Wire</th>
<th>HC-SR04 Pin</th>
</tr>
</thead>
<tbody>
<tr>
<td>5V</td>
<td style="text-align: center; vertical-align: middle; padding: 0;">
<div class="wire red" style="height: 4px; width: 200px; margin: 0 auto;">
<div class="male-left"></div>
<div class="male-right"></div>
</div>
</td>
<td>VCC</td>
</tr>
<tr>
<td>GPIO 5</td>
<td style="text-align: center; vertical-align: middle; padding: 0;">
<div class="wire green" style="height: 4px; width: 200px; margin: 0 auto;">
<div class="male-left"></div>
<div class="male-right"></div>
</div>
</td>
<td>Trig</td>
</tr>
<tr>
<td>GPIO 18</td>
<td style="text-align: center; vertical-align: middle; padding: 0;">
<div class="wire yellow" style="height: 4px; width: 200px; margin: 0 auto;">
<div class="male-left"></div>
<div class="male-right"></div>
</div>
</td>
<td>Echo (via voltage divider)</td>
</tr>
<tr>
<td>GND</td>
<td style="text-align: center; vertical-align: middle; padding: 0;">
<div class="wire black" style="height: 4px; width: 200px; margin: 0 auto;">
<div class="male-left"></div>
<div class="male-right"></div>
</div>
</td>
<td>GND</td>
</tr>
</tbody>
</table>
- **VCC**: Connect the VCC pin on the HC-SR04 to the Vin pin on the ESP32. If you are using HC-SR04+, use 3.3V pin on the ESP32.
- **Trig**: Connect to GPIO 5 on the ESP32.
- **Echo**: Connect the Echo pin on the HC-SR04 to GPIO 18 through a voltage divider (1kΩ resistor between Echo and GPIO 18, and 2kΩ resistor between GPIO 18 and GND; means the GPIO 18 basically goes in the middle). I believe this will be easier to understand with the circuit diagram.
- **GND**: Connect the GND pin on the HC-SR04 to the GND pin on the ESP32.
## Circuit for LED
You have to connect the anode (long leg) of the LED to GPIO 33, as in the [External LED setup](../led/external-led.md); through the resistor (eg: 330 Ohm resistor) to avoid damaging the LED. And the cathode of the LED(short leg) to Ground.
<table>
<thead>
<tr>
<th>ESP32 Pin</th>
<th style="width: 250px; margin: 0 auto;">Wire</th>
<th>Component</th>
</tr>
</thead>
<tbody>
<tr>
<td>GPIO 33</td>
<td style="text-align: center; vertical-align: middle; padding: 0;">
<div class="wire orange" style="width: 200px; margin: 0 auto;">
<div class="female-left"></div>
<div class="female-right"></div>
</div>
</td>
<td>Resistor</td>
</tr>
<tr>
<td>Resistor</td>
<td style="text-align: center; vertical-align: middle; padding: 0;">
<div class="wire orange" style="width: 200px; margin: 0 auto;">
<div class="female-left"></div>
<div class="female-right"></div>
</div>
</td>
<td>Anode (long leg) of LED</td>
</tr>
<tr>
<td>GND</td>
<td style="text-align: center; vertical-align: middle; padding: 0;">
<div class="wire black" style="width: 200px; margin: 0 auto;">
<div class="female-left"></div>
<div class="female-right"></div>
</div>
</td>
<td>Cathode (short leg) of LED</td>
</tr>
</tbody>
</table>
## Circuit Diagram
I have provided circuit diagrams both with and without a breadboard. To be honest, the breadboard version was a bit confusing when I drew it. If you still find it unclear, please create an issue in the GitHub repository and describe the confusing parts. I'll do my best to improve it.
**Diagram without breadboard**:
<img style="display: block; margin: auto;" alt="connecting ESP32 with HC-SR04 Ultrasonic Sensor circuit" src="./images/ESP32-HC-SR04-circuit-without-breadboard.png"/>
**Diagram with breadboard**:
<img style="display: block; margin: auto;" alt="connecting ESP32 with HC-SR04 Ultrasonic Sensor circuit" src="./images/ESP32-HC-SR04-circuit.png"/>

225
src/ultrasonic/code.md Normal file
View File

@ -0,0 +1,225 @@
## Writing Rust Code Use HC-SR04 Ultrasonic Sensor with ESP32
We'll start by generating the project using the template, then modify the code to fit the current project's requirements.
### Generate project using esp-generate
You have done this step already in the quick start section.
To create the project, use the `esp-generate` command. Run the following:
```sh
esp-generate --chip esp32 ultrasonic
```
This will open a screen asking you to select options. For now, we dont need to select any options. Just save it by pressing "s" in the keyboard.
## Setup the LED Pin and configure PWM
You should understand this code by now. If not, please complete the Fading [LED section](../led/index.md) first.
Quick recap: Here, we're configuring the PWM for the LED, which allows us to control the brightness by adjusting the duty cycle.
```rust
let led = peripherals.GPIO33;
let ledc = Ledc::new(peripherals.LEDC);
let mut hstimer0 = ledc.timer::<HighSpeed>(timer::Number::Timer0);
hstimer0
.configure(timer::config::Config {
duty: timer::config::Duty::Duty5Bit,
clock_source: timer::HSClockSource::APBClk,
frequency: 24.kHz(),
})
.unwrap();
let mut channel0 = ledc.channel(channel::Number::Channel0, led);
channel0
.configure(channel::config::Config {
timer: &hstimer0,
duty_pct: 10,
pin_config: channel::config::PinConfig::PushPull,
})
.unwrap();
```
## Setup the Trigger Pin
We will configure GPIO 5 as an output pin with its initial state set to LOW. If you're wondering why it's an output, it's because we are sending a signal from the ESP32 to the ultrasonic module. This pin is connected to the Trig pin of the ultrasonic module.
```rust
let mut trig = Output::new(peripherals.GPIO5, Level::Low);
```
## Setup the Echo Pin
We will configure GPIO 18 as an input pin since the ultrasonic module sends the signal back to the ESP32. The initial state of this pin will be set to Pull Down to ensure it starts in the low state.
```rust
let echo = Input::new(peripherals.GPIO18, Pull::Down);
```
## 🦇 Light it Up
### Step 1: Send the Trigger Pulse
We will set the trig pin to LOW so that we start fresh. We will set the trig pin to HIGH for 10 microseconds, then turn it back to LOW. This will trigger the module to send ultrasonic waves.
```rust
// Ensure the Trigger pin is low before starting
trig.set_low();
delay.delay_micros(2);
// Send a 10-microseconds high pulse
trig.set_high();
delay.delay_micros(10);
trig.set_low();
```
### Step 2: Measure the pulse width
Next, we will use two loops. The first loop will run as long as the echo pin state is LOW. Once it goes HIGH, we will record the current time in a variable. Then, we start the second loop, which will continue as long as the echo pin remains HIGH. When it returns to LOW, we will record the current time in another variable. The difference between these two times gives us the pulse width.
```rust
// Measure the duration the signal remains high
while echo.is_low() {}
let time1 = rtc.current_time();
while echo.is_high() {}
let time2 = rtc.current_time();
let pulse_width = match (time2 - time1).num_microseconds() {
Some(pw) => pw as f64,
None => continue,
};
```
### Step 3: Calculate the Distance
To calculate the distance, we need to use the pulse width. The pulse width tells us how long it took for the ultrasonic waves to travel to an obstacle and return. Since the pulse represents the round-trip time, we divide it by 2 to account for the journey to the obstacle and back.
The speed of sound in air is approximately 0.0343 cm per microsecond. By multiplying the time (in microseconds) by this value and dividing by 2, we obtain the distance to the obstacle in centimeters.
```rust
let distance = (pulse_width * 0.0343) / 2.0;
```
### Step 4: PWM Duty cycle for LED
Finally, we adjust the LED brightness based on the measured distance.
The duty cycle percentage is calculated using our own logic, you can modify it to suit your needs. When the object is closer than 30 cm, the LED brightness will increase. The closer the object is to the ultrasonic module, the higher the calculated ratio will be, which in turn adjusts the duty cycle. This results in the LED brightness gradually increasing as the object approaches the sensor.
```rust
let duty_pct: u8 = if distance < 30.0 {
let ratio = (30.0 - distance) / 30.0;
let p = (ratio * 100.0) as u8;
p.min(100)
} else {
0
};
if let Err(e) = channel0.set_duty(duty_pct) {
esp_println::println!("Failed to set duty cycle: {:?}", e);
}
```
### Full code
```rust
#![no_std]
#![no_main]
use esp_backtrace as _;
use esp_hal::{
delay::Delay,
gpio::{Input, Level, Output, Pull},
ledc::{
channel::{self, ChannelIFace},
timer::{self, TimerIFace},
HighSpeed, Ledc,
},
prelude::*,
rtc_cntl::Rtc,
};
#[entry]
fn main() -> ! {
let peripherals = esp_hal::init({
let mut config = esp_hal::Config::default();
config.cpu_clock = CpuClock::max();
config
});
// let led = peripherals.GPIO2; // uses onboard LED
let led = peripherals.GPIO33;
let ledc = Ledc::new(peripherals.LEDC);
let mut hstimer0 = ledc.timer::<HighSpeed>(timer::Number::Timer0);
hstimer0
.configure(timer::config::Config {
duty: timer::config::Duty::Duty5Bit,
clock_source: timer::HSClockSource::APBClk,
frequency: 24.kHz(),
})
.unwrap();
let mut channel0 = ledc.channel(channel::Number::Channel0, led);
channel0
.configure(channel::config::Config {
timer: &hstimer0,
duty_pct: 10,
pin_config: channel::config::PinConfig::PushPull,
})
.unwrap();
// For HC-SR04 Ultrasonic
let mut trig = Output::new(peripherals.GPIO5, Level::Low);
let echo = Input::new(peripherals.GPIO18, Pull::Down);
let delay = Delay::new();
let rtc = Rtc::new(peripherals.LPWR);
loop {
delay.delay_millis(5);
// Trigger ultrasonic waves
trig.set_low();
delay.delay_micros(2);
trig.set_high();
delay.delay_micros(10);
trig.set_low();
// Measure the duration the signal remains high
while echo.is_low() {}
let time1 = rtc.current_time();
while echo.is_high() {}
let time2 = rtc.current_time();
let pulse_width = match (time2 - time1).num_microseconds() {
Some(pw) => pw as f64,
None => continue,
};
// Derive distance from the pulse width
let distance = (pulse_width * 0.0343) / 2.0;
// esp_println::println!("Pulse Width: {}", pulse_width);
// esp_println::println!("Distance: {}", distance);
// Our own logic to calculate duty cycle percentage for the distance
let duty_pct: u8 = if distance < 30.0 {
let ratio = (30.0 - distance) / 30.0;
let p = (ratio * 100.0) as u8;
p.min(100)
} else {
0
};
if let Err(e) = channel0.set_duty(duty_pct) {
esp_println::println!("Failed to set duty cycle: {:?}", e);
}
delay.delay_millis(60);
}
}
```
## Clone the existing project
You can clone (or refer) project I created and navigate to the `ultrasonic` folder.
```sh
git clone https://github.com/ImplFerris/esp32-projects/ultrasonic
cd esp32-projects/ultrasonic
```

View File

@ -0,0 +1,80 @@
# How Does an Ultrasonic Sensor Work?
Ultrasonic sensors work by emitting sound waves at a frequency too high(40kHz) for humans to hear. These sound waves travel through the air and bounce back when they hit an object. The sensor calculates the distance by measuring how long it takes for the sound waves to return.
<img style="display: block; margin: auto;width:500px" alt="ultrasonic" src="./images/ultrasonic.jpg"/>
- **Transmitter:** Sends out ultrasonic sound waves.
- **Receiver:** Detects the sound waves that bounce back from an object.
**Formula to calculate distance**:
```
Distance = (Time x Speed of Sound) / 2
```
The speed of sound is approximately 0.0343 cm/µs (or 343 m/s) at normal air pressure and a temperature of 20°C.
## Example Calculation:
Let's say the ultrasonic sensor detects that the sound wave took 2000 µs to return after hitting an object.
Step 1: Calculate the total distance traveled by the sound wave:
```
Total distance = Time x Speed of Sound
Total distance = 2000 µs x 0343 cm/µs = 68.6 cm
```
Step 2: Since the sound wave traveled to the object and back, the distance to the object is half of the total distance:
```
Distance to object = 68.6 cm / 2 = 34.3 cm
```
Thus, the object is 34.3 cm away from the sensor.
## HC-SR04 Pinout
The module has four pins: VCC, Trig, Echo, and GND.
<table style="width:300px;height:200px;">
<tr>
<th>Pin</th>
<th>Function</th>
</tr>
<tr>
<td style="vertical-align: middle;text-align: center;" class="slanted-text st-red">VCC</td>
<td>Power Supply</td>
</tr>
<tr>
<td style="vertical-align: middle;text-align: center;" class="slanted-text st-yellow">Trig</td>
<td>Trigger Signal</td>
</tr>
<tr>
<td style="vertical-align: middle;text-align: center;" class="slanted-text st-teal">Echo</td>
<td>Echo Signal</td>
</tr>
<tr>
<td style="vertical-align: middle;text-align: center;" class="slanted-text st-blue">GND</td>
<td>Ground</td>
</tr>
</table>
## Measuring Distance with the HC-SR04 module
The HC-SR04 module has a transmitter and receiver, responsible for sending ultrasonic waves and detecting the reflected waves. We will use the Trig pin to send sound waves. And read from the Echo pin to measure the distance.
<img style="display: block; margin: auto;" alt="ultrasonic" src="./images/ultrasonic-trigger-echo-wave.png"/>
As you can see in the diagram, we connect the Trig and Echo pins to the GPIO pins of the microcontroller (we also connect VCC and GND but left them out to keep the illustration simple). We send ultrasonic waves by setting the Trig pin HIGH for 10 microseconds and then setting it back to LOW. This triggers the module to send 8 consecutive ultrasonic waves at a frequency of 40 kHz. It is recommended to have a minimum gap of 50ms between each trigger.
When the sensor's waves hit an object, they bounce back to the module. As you can see in the diagram, the Echo pin changes the input sent to the microcontroller, with the length of time the signal stays HIGH (pulse width) corresponding to the distance. In the microcontroller, we measure how long the Echo pin stays HIGH; Then, we can use this time duration to calculate the distance to the object.
**Pulse width and the distance:**
The pulse width (amount of time it stays high) produced by the Echo pin will range from about 150µs to 25,000µs(25ms); this is only if it hits an object. If there is no object, it will produce a pulse width of around 38ms.

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

39
src/ultrasonic/index.md Normal file
View File

@ -0,0 +1,39 @@
# HC-SR04 Ultrasonic Sensor
In this guide, we'll learn how to use the HC-SR04 ultrasonic sensor with the ESP32. Ultrasonic sensors measure distances by emitting ultrasonic sound waves and calculating the time taken for them to return after bouncing off an object.
These kind of sensors you can normally find in the car parking assistance; When you reverse the car for parking, the sensor measures the distance between objects and alert you as you get close to it.
We will build a simple project that gradually increases the LED brightness using PWM, when the ultrasonic sensor detects an object distance of less than 30 cm - You can adjust this value as per your needs.
<img style="display: block; margin: auto;width:500px" alt="ultrasonic" src="./images/hc-sr04-ultrasonic.jpg"/>
## Prerequisites
Before starting, get familiar with yourself on these topics
- [PWM](../core-concepts/pwm/index.md)
## 🛠 Hardware Requirements
To complete this project, you will need:
- HC-SR04 Ultrasonic Sensor (or HC-SR04+)
- Breadboard
- Jumper wires
- External LED (You can also use the onboard LED, just use the GPIO 2 instead)
## HC-SR04 Specs.
The HC-SR04 ultrasonic sensor can measure distances from 2 cm to 400 cm, with an accuracy of up to 3 mm. It needs a 5V power supply to operate.
- [Datasheet](https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf)
## ESP32 Tolerance
In the next chapter, we'll dive into the details of how the sensor works, but the basic idea is pretty simple: it sends out a signal and waits to receive it back. When powered with 5V, the sensor's Echo pin outputs a 5V signal back to the connected device. But there is a problem, ESP32 GPIOs can only handle up to 3.6V. Anything higher risks damaging the microcontroller.
**How do we solve it?**
Here are a few options:
- The simplest option is to get the HC-SR04+, an upgraded version that works with both 3.3V and 5V. Then use 3.3V to power up the module.
- Another option is to use a voltage divider (just a couple of resistors) between the Echo pin and the ESP32 to drop the voltage to 3.3V.
- The last option is to power the HC-SR04 with 3.3V. It might work, but may not be reliable. Avoid this option unless it's absolutely your last resort and you're fine with any potential side effects.

View File

@ -0,0 +1,12 @@
$ 1 0.000005 10.20027730826997 63 10 62 5e-11
v 240 400 240 80 0 0 40 5 0 0 0.5
w 240 80 368 80 0
r 368 80 368 240 0 1000
w 240 400 368 400 0
O 368 240 432 240 1 0
x 378 144 393 147 4 12 R1
x 377 305 392 308 4 12 R2
r 368 400 368 240 0 2000
x 199 219 216 222 4 14 5V
x 209 201 223 204 4 10 Vin
x 424 227 444 230 4 10 Vout

View File

@ -462,65 +462,65 @@ border: 2px solid #CCC;
}
/* Individual color themes */
.slanted-text.red {
.slanted-text.st-red {
/* background: linear-gradient(135deg, #e74c3c, #c0392b); */
background: #e74c3c;
color: black;
}
.slanted-text.yellow {
.slanted-text.st-yellow {
/* background: linear-gradient(135deg, #f39c12, #e67e22); */
background: #efe012;
color: white;
color: black;
}
.slanted-text.teal {
.slanted-text.st-teal {
/* background: linear-gradient(135deg, #1abc9c, #16a085); */
background: #1abc9c;
color: black;
}
.slanted-text.blue {
.slanted-text.st-blue {
/* background: linear-gradient(135deg, #00bcd4, #008c8c); */
background: #3457D5;
color: black;
}
.slanted-text.pink {
.slanted-text.st-pink {
/* background: linear-gradient(135deg, #e91e63, #c2185b); */
background: #e91e63;
color: black;
}
.slanted-text.purple {
.slanted-text.st-purple {
/* background: linear-gradient(135deg, #8e44ad, #6f4f37); */
background: #8e44ad;
color: black;
}
.slanted-text.brown {
.slanted-text.st-brown {
/* background: linear-gradient(135deg, #6f4f37, #a0522d); */
background: #a0522d;
color: black;
}
.slanted-text.green {
.slanted-text.st-green {
/* background: linear-gradient(135deg, #2ecc71, #27ae60); */
background: #00A550;
color: black;
}
.slanted-text.gray {
.slanted-text.st-gray {
background: linear-gradient(135deg, #bdc3c7, #95a5a6);
color: black;
}
.slanted-text.indigo {
.slanted-text.st-indigo {
background: linear-gradient(135deg, #3f51b5, #303f9f);
color: black;
}
.slanted-text.black {
.slanted-text.st-black {
background: #333333;
color: #999;
}