Community project
Obstacle-Avoiding Rover

This obstacle-avoiding rover uses a Raspberry Pi Pico to autonomously navigate around obstacles using an HC-SR04 ultrasonic sensor. The rover drives forward at a set speed, continuously scanning for obstacles ahead, and when something gets too close, it stops, backs up, turns, and resumes its journey.
The guide provides a complete wiring diagram, parts list, and ready-to-upload firmware. Assembly covers mounting the motors and L298N motor driver to the chassis, wiring the dual DC motors for independent left and right control, setting up the 2S LiPo battery with regulated 5V power for the Pico and sensor, protecting the HC-SR04 signal lines with a level shifter, and performing a safe first power-on test.
Wiring diagram
Interactive · read-only
Pan and zoom to explore the wiring. Remix the project to edit it in your own workspace.
Parts list
Bill of materials| Component | Qty | Notes |
|---|---|---|
| DFRobot MDV 2x2A DC Motor Controller (L298N)L298N module | 1 | L298N dual H-bridge motor driver carrier. 2A continuous per channel, 5-46V motor supply, ~1.8V dropout (BJT-based, hot at high currents). Drives 2 brushed DC motors or 1 bipolar stepper. Pair with PWM on EN pins for speed control. |
| HC-SR04HC-SR04 | 1 | Ultrasonic distance measurement sensor |
| MP1584 Buck ConverterSet to 5.0 V | 1 | Adjustable buck (step-down) DC-DC converter, 4.5-28 V in -> 0.8-20 V out, ~3 A. Configured to 5 V to step a 9 V / 12 V supply or battery pack down to the board's 5 V rail. |
| DC Motor6 V DC gearmotor | 1 | DC motor (requires motor driver like L298N) |
| DC Motor6 V DC gearmotor | 1 | DC motor (requires motor driver like L298N) |
| 2S LiPo battery pack7.4 V nominal, 1000 mAh | 1 | 7.4 V nominal (8.4 V fully charged), 1000 mAh two-cell LiPo battery pack for the rover. Use its discharge connector only for the load and use a dedicated 2S balance charger for charging. |
| 2S rover power distribution block7.4 V, 5 A minimum | 1 | Insulated high-current distribution block that splits the 2S battery discharge supply into a motor branch and a buck-converter branch, with a common ground return. |
| HC-SR04 3.3 V / 5 V signal level shifter3.3 V ↔ 5 V, 2 channels | 1 | Two-channel level translator: translates Pico trigger to 5 V and HC-SR04 echo down to 3.3 V. |
Assembly
6 stepsPrepare the chassis and motor driver
Mount the Pico, L298N module, battery holder, and the two motors securely. Keep the motor wires away from the ultrasonic sensor face. Remove the ENA and ENB jumpers from the L298N so the Pico can control motor speed with PWM.
- Tip: Fit a caster wheel at the front or rear of the two-wheel chassis.
- Tip: Do not power the circuit while making or changing connections.
- ⚠ The L298N gets warm during use; leave airflow around its heatsink.
- ⚠ Confirm each motor's stall current is within the L298N module's real thermal capability.
Wire both motors to the L298N
Connect the left motor's two leads to OUT1 and OUT2. Connect the right motor's two leads to OUT3 and OUT4. If a motor runs opposite to the intended direction during testing, swap only that motor's two output leads.
- Tip: Use short, secure motor wires to reduce electrical noise.
- ⚠ Never connect a motor directly to a Pico GPIO pin.
Make the battery and regulated 5 V power wiring
Connect battery BAT+ to the L298N VS motor-supply input and to buck VIN. Connect battery BAT− to L298N GND and buck GND. Before connecting loads, adjust and measure the buck VOUT as exactly 5.0 V. Then connect buck VOUT to Pico VSYS and HC-SR04 VCC; connect their grounds to the same common ground.
- Tip: Add an inline power switch or unplug the battery when the rover is not in use.
- Tip: The Pico is fed at VSYS with regulated 5 V, not through a GPIO pin.
- ⚠ Verify the buck output with a multimeter before connecting the Pico or sensor: more than 5.5 V can damage them.
- ⚠ All grounds—battery, buck, L298N, Pico, and HC-SR04—must be connected together.
- ⚠ Use a proper 2S LiPo charger/balancer appropriate for your battery; do not charge it through this circuit.
Wire Pico control signals to the L298N
Connect Pico GP2 to IN1, GP3 to IN2, GP4 to ENA, GP6 to IN3, GP7 to IN4, and GP8 to ENB on the L298N. Keep ENA and ENB jumpers removed.
- Tip: Use the Pico's labeled GP pin numbers, not physical header-pin positions.
- Tip: The L298N inputs accept the Pico's 3.3 V logic levels.
- ⚠ Do not connect the L298N 5 V pin to a Pico GPIO.
Wire and protect the HC-SR04 signal
Connect HC-SR04 TRIG to Pico GP10, VCC to regulated 5 V, and GND to common ground. Create a voltage divider for ECHO: HC-SR04 ECHO → 10 kΩ resistor → junction → Pico GP11; from that same junction connect a 20 kΩ resistor to common ground. This reduces the 5 V ECHO signal to about 3.3 V.
- Tip: Mount the two ultrasonic transducers facing straight forward and clear of the chassis.
- Tip: Keep the divider junction insulated so it cannot short to adjacent wiring.
- ⚠ Never connect a standard 5 V HC-SR04 ECHO pin directly to Pico GP11; Pico GPIO pins are 3.3 V-only.
Perform a safe first power-on
Lift the drive wheels off the ground, connect the battery, and use Schematik's Deploy button to flash the rover firmware. The rover drives forward when it sees clear space. At 25 cm or closer it stops, reverses briefly, then pivots right before continuing.
- Tip: If the rover drives backward instead of forward, swap both leads of both motors or reverse the relevant direction logic.
- Tip: If it pivots the wrong way, swap one motor's leads or change the turn direction in firmware.
- ⚠ Keep hands, hair, and loose wires away from the wheels during powered testing.
- ⚠ Disconnect battery power before altering any wiring.
Pin assignments
Board wiring reference| Pin | Connection | Type |
|---|---|---|
| GND | buck GND | ground |
| 5V | buck VOUT | power |
| GND | driver GND | ground |
| 5V | driver 5V | power |
| GPIO 2 | driver IN1 | digital |
| GPIO 3 | driver IN2 | digital |
| GPIO 4 | driver ENA | pwm |
| GPIO 6 | driver IN3 | digital |
| GPIO 7 | driver IN4 | digital |
| GPIO 8 | driver ENB | pwm |
| EXT | driver OUT1 → DC Motor VCC | output |
| EXT | driver OUT2 → DC Motor GND | output |
| EXT | driver OUT3 → DC Motor VCC | output |
| EXT | driver OUT4 → DC Motor GND | output |
| EXT | left_motor IN1 → DFRobot MDV 2x2A DC Motor Controller (L298N) OUT1 | digital |
| EXT | left_motor IN2 → DFRobot MDV 2x2A DC Motor Controller (L298N) OUT2 | digital |
| EXT | right_motor IN1 → DFRobot MDV 2x2A DC Motor Controller (L298N) OUT3 | digital |
| EXT | right_motor IN2 → DFRobot MDV 2x2A DC Motor Controller (L298N) OUT4 | digital |
| 5V | ultrasonic VCC | power |
| GND | ultrasonic GND | ground |
| GND | battery BAT- | ground |
| EXT | battery BAT+ → 2S rover power distribution block BAT_IN | power |
| EXT | power_distribution MOTOR_OUT → DFRobot MDV 2x2A DC Motor Controller (L298N) VS | power |
| EXT | power_distribution BUCK_OUT → MP1584 Buck Converter VIN | power |
| GND | power_distribution GND | ground |
| 3V3 | level_shifter LV | power |
| 5V | level_shifter HV | power |
| GND | level_shifter GND | ground |
| GPIO 10 | level_shifter TRIG_LV | digital |
| EXT | level_shifter TRIG_HV → HC-SR04 TRIG | digital |
| EXT | ultrasonic ECHO → HC-SR04 3.3 V / 5 V signal level shifter ECHO_HV | digital |
| GPIO 11 | level_shifter ECHO_LV | digital |
Firmware
Raspberry Pi Pico#include <Arduino.h>
// HC-SR04 signal paths pass through a 3.3V/5V level shifter.
// Forward declarations
void motor(int a, int b, int en, int value);
void drive(int left, int right);
unsigned int distanceCm();
const int LEFT_IN1 = 2, LEFT_IN2 = 3, LEFT_EN = 4;
const int RIGHT_IN1 = 6, RIGHT_IN2 = 7, RIGHT_EN = 8;
const int TRIG_PIN = 10, ECHO_PIN = 11;
const int CRUISE_SPEED = 190, TURN_SPEED = 175;
const unsigned int OBSTACLE_CM = 25;
void motor(int a, int b, int en, int value) {
value = constrain(value, -255, 255);
digitalWrite(a, value > 0 ? HIGH : LOW);
digitalWrite(b, value < 0 ? HIGH : LOW);
analogWrite(en, abs(value));
}
void drive(int left, int right) { motor(LEFT_IN1, LEFT_IN2, LEFT_EN, left); motor(RIGHT_IN1, RIGHT_IN2, RIGHT_EN, right); }
unsigned int distanceCm() {
digitalWrite(TRIG_PIN, LOW); delayMicroseconds(3);
digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10); digitalWrite(TRIG_PIN, LOW);
unsigned long us = pulseIn(ECHO_PIN, HIGH, 30000UL);
return us ? us / 58UL : 0;
}
void setup() {
pinMode(LEFT_IN1, OUTPUT); pinMode(LEFT_IN2, OUTPUT); pinMode(LEFT_EN, OUTPUT);
pinMode(RIGHT_IN1, OUTPUT); pinMode(RIGHT_IN2, OUTPUT); pinMode(RIGHT_EN, OUTPUT);
pinMode(TRIG_PIN, OUTPUT); pinMode(ECHO_PIN, INPUT);
drive(0, 0);
}
void loop() {
unsigned int cm = distanceCm();
if (cm && cm <= OBSTACLE_CM) {
drive(0, 0); delay(120); drive(-CRUISE_SPEED, -CRUISE_SPEED); delay(300);
drive(TURN_SPEED, -TURN_SPEED); delay(480); drive(0, 0); delay(80);
} else drive(CRUISE_SPEED, CRUISE_SPEED);
delay(90);
}“Deploy to device” opens this project in Schematik, where you can flash it to your board over USB.
Remix this project
Make it yours in one click
Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.