A compact embedded sensing system that transforms ultrasonic echoes into a live radar view.
This project implements a simplified ultrasonic radar using an STM32L475VG, an HC-SR04 ultrasonic sensor, a servo motor, an I2C LCD and a Python visualization application.
The STM32 controls the measurement cycle, estimates the obstacle distance, displays a local status on the LCD and transmits angle-distance pairs to a PC over UART. Python receives the stream and renders it as a polar radar view.
The project was developed as an academic embedded-systems project and demonstrates the complete path from sensor acquisition to data visualization.
HC-SR04
TRIG / ECHO
│
▼
┌──────────────────────┐ UART ┌─────────────────────┐
│ STM32L475VG │ ────────────────> │ Python application │
│ │ │ │
│ TIM2: echo timing │ │ PySerial │
│ TIM3: servo PWM │ │ NumPy │
│ I2C1: LCD │ │ Matplotlib │
│ GPIO: trigger/echo │ │ Polar radar plot │
└──────────┬───────────┘ └─────────────────────┘
│
▼
Servo + LCD
The repository includes a recorded demonstration in media/radar_ultrason_python.mp4.
| Hardware setup | LCD and measurement | Python radar output |
|---|---|---|
![]() |
![]() |
![]() |
- STM32L475VG development board.
- HC-SR04 ultrasonic sensor.
- Servo motor for angular scanning.
- 16×2 LCD with PCF8574 I2C backpack.
- USB/UART connection to the computer.
- Voltage divider for the HC-SR04 ECHO signal when required.
The HC-SR04 ECHO output can be higher than the STM32 GPIO voltage domain. The signal must be adapted to a safe level before connecting it to the microcontroller. The project documentation uses a resistor divider concept for this interface.
The firmware is located in firmware/STM32CubeIDE/Core/Src/main.c. It is organized around a repeatable measurement loop:
- Move the servo to the current angle.
- Generate a short TRIG pulse.
- Measure the HIGH duration of ECHO.
- Convert the time of flight into distance.
- Display the result on the LCD.
- Transmit the angle and distance over UART.
- Continue the scan from 0° to 180°.
| Peripheral | Role |
|---|---|
| TIM2 | Microsecond timing and ECHO pulse measurement. |
| TIM3 | PWM generation for the servo motor. |
| I2C1 | Communication with the LCD backpack. |
| USART1 | Transmission of measurements to the PC. |
| GPIO + EXTI | TRIG control and ECHO edge detection. |
The distance is estimated from the duration of the ultrasonic round trip:
distance = echo_time × speed_of_sound / 2
In the firmware, the speed of sound is approximated by 0.0343 cm/µs. The division by two accounts for the outgoing and returning paths of the acoustic wave.
The LCD provides local feedback during the experiment, including the measured distance and qualitative ranges such as short, medium or long distance.
The STM32 sends one measurement per scan position using a text frame similar to:
A:90, D:35.42 cm
Where:
Ais the servo angle in degrees.Dis the measured distance in centimetres.
The Python script reads the serial stream, extracts the two fields and converts the angle to radians for the polar plot. The current script is available at python/scripts/script.py.
The PC application uses:
pyserialfor UART acquisition.numpyfor angle conversion.matplotlibfor the polar visualization.
Install the dependencies:
pip install pyserial numpy matplotlibSet the serial port in python/scripts/script.py according to your computer:
ser = serial.Serial('COM6', 115200, timeout=1)Then launch the application from the repository root:
python python/scripts/script.pyThe STM32 must be powered and transmitting before starting the script.
.
├── docs/
│ └── images/ # Technical screenshots and project photos
├── firmware/
│ ├── librairies/ # Optional embedded libraries
│ └── STM32CubeIDE/
│ └── Core/Src/main.c # STM32 application source
├── media/
│ └── radar_ultrason_python.mp4
├── python/
│ └── scripts/script.py # Real-time radar visualization
├── .gitignore
└── README.md
The project follows a clear embedded acquisition chain:
- Time-domain measurement: the ECHO pulse width is measured instead of sampling an analogue signal.
- Hardware timer usage: TIM2 provides a deterministic time base for distance estimation.
- Event-driven capture: GPIO edge interrupts identify the beginning and end of the ECHO pulse.
- Actuator synchronization: the servo position defines the angular coordinate associated with each distance.
- Local and remote feedback: the LCD gives immediate feedback while UART enables richer PC visualization.
- Separation of concerns: the STM32 handles real-time acquisition; Python handles presentation and visualization.
This architecture keeps the real-time constraints on the microcontroller while using the PC for a more flexible user interface.
The current prototype is intentionally simple and can be improved in future revisions:
- Add a dedicated STM32CubeIDE project file and complete generated configuration files.
- Add the LCD driver source and header files to the repository if they are external to the current source tree.
- Replace blocking delays with a non-blocking state machine.
- Improve servo calibration and use floating-point-safe PWM mapping.
- Remove debug
printfcalls from interrupt routines. - Add UART frame validation and error handling.
- Filter unstable distance measurements.
- Add a configurable detection range and obstacle threshold.
- Store measurements in CSV for later analysis.
Embedded C · STM32 · STM32CubeIDE · GPIO/EXTI · Timers · PWM · I2C · UART · Ultrasonic sensing · Sensor interfacing · Python · PySerial · NumPy · Matplotlib · Real-time visualization
Joseph Mbode
GitHub: @Josephulrich
If you find this project useful, feel free to explore the source code and the technical documentation included in docs/images/.








