Bumper car on an Arduino Uno
A 2WD robot car on a DRV8833 with two lever microswitches for bumpers. It drives until a bumper is hit, then backs off and turns away from that side. The whole build, an Arduino Uno and 4 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate About 30 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $41. On Mokxi they're free.
What you'll learn
- Driving a DC motor with an H-bridge driver
- PWM on one input for speed, and sign for direction
- Active-low switches with
INPUT_PULLUP - Simple reactive behavior: sense, then escape
- Difficulty: Intermediate
- Time: About 30 minutes
- Board: Arduino Uno R3
- Parts: 6
How it works
A DRV8833 motor driver runs the two wheel motors. Each motor has two inputs. The sketch holds one low and sends PWM to the other, and the PWM duty sets the speed and direction.
Two lever microswitches act as bumpers on pins 7 and 8. Each one connects its pin to ground when pressed, so a press reads LOW.
The car cruises forward at CRUISE (180 out of 255). If a bumper is pressed, it brakes, backs up for half a second, then turns away from the side that hit.
Parts list
6 parts, plus the jumper wires. They retail for about $41; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Motor driver, DRV8833In Claw Machine Kit, Robot Car Kit.
- 1 × Robot car chassis, 2WDIn Robot Car Kit.
- 2 × Limit switch, lever microswitchIn Claw Machine Kit, Vending Machine Kit.
- 1 × Power, 6 V
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Arduino Uno R3 pin GND | Ground |
| Motor driver, DRV8833 pin BIN2 | Arduino Uno R3 pin 10 |
| Motor driver, DRV8833 pin BIN1 | Arduino Uno R3 pin 9 |
| Limit switch, lever microswitch (2) pin NO | Arduino Uno R3 pin 8 |
| Limit switch, lever microswitch (1) pin NO | Arduino Uno R3 pin 7 |
| Motor driver, DRV8833 pin AIN2 | Arduino Uno R3 pin 6 |
| Motor driver, DRV8833 pin AIN1 | Arduino Uno R3 pin 5 |
| Motor driver, DRV8833 pin VM | 6 V |
| Motor driver, DRV8833 pin GND | Ground |
| Robot car chassis, 2WD pin L+ | Motor driver, DRV8833 pin AOUT1 |
| Robot car chassis, 2WD pin L- | Motor driver, DRV8833 pin AOUT2 |
| Robot car chassis, 2WD pin R+ | Motor driver, DRV8833 pin BOUT1 |
| Robot car chassis, 2WD pin R- | Motor driver, DRV8833 pin BOUT2 |
| Limit switch, lever microswitch (1) pin COM | Ground |
| Limit switch, lever microswitch (2) pin COM | Ground |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Bumper car: a 2WD chassis on a DRV8833, with two lever microswitches
// mounted on the front corners as bumpers.
//
// DRV8833 AIN1 pin 5, AIN2 pin 6 left motor
// BIN1 pin 9, BIN2 pin 10 right motor
// VM from the four-AA pack (6 V), GND to the Uno's GND
// SLP left unwired: the breakout pulls it up, so the chip is awake
// bumpers COM to GND, NO to pin 7 (left) and pin 8 (right), INPUT_PULLUP
//
// The DRV8833 has two inputs per motor and no enable pin. One input held low
// and a PWM on the other is drive and coast in turn, so the duty is the speed.
// Both low coasts; both high brakes.
//
// A bumper reads LOW while it is pressed, because its NO contact joins the pin
// to ground. The car backs off and turns away from whichever side hit. Hold a
// switch with the mouse to bump the car on the canvas.
const int AIN1 = 5;
const int AIN2 = 6;
const int BIN1 = 9;
const int BIN2 = 10;
const int BUMP_LEFT = 7;
const int BUMP_RIGHT = 8;
const int CRUISE = 180;
// One motor as a signed speed, -255 to 255: PWM on one input, the other low.
void motor(int in1, int in2, int speed) {
if (speed >= 0) {
digitalWrite(in2, LOW);
analogWrite(in1, speed > 255 ? 255 : speed);
} else {
digitalWrite(in1, LOW);
analogWrite(in2, -speed > 255 ? 255 : -speed);
}
}
void drive(int left, int right) {
motor(AIN1, AIN2, left);
motor(BIN1, BIN2, right);
}
void brake() {
digitalWrite(AIN1, HIGH);
digitalWrite(AIN2, HIGH);
digitalWrite(BIN1, HIGH);
digitalWrite(BIN2, HIGH);
}
void escape(const char *side, int turnLeft, int turnRight) {
Serial.print("bumped on the ");
Serial.print(side);
Serial.println(": back off and turn away");
brake();
delay(150);
drive(-CRUISE, -CRUISE);
delay(500);
drive(turnLeft, turnRight);
delay(400);
}
void setup() {
pinMode(AIN1, OUTPUT);
pinMode(AIN2, OUTPUT);
pinMode(BIN1, OUTPUT);
pinMode(BIN2, OUTPUT);
pinMode(BUMP_LEFT, INPUT_PULLUP);
pinMode(BUMP_RIGHT, INPUT_PULLUP);
Serial.begin(115200);
Serial.println("bumper car: ready");
}
void loop() {
if (digitalRead(BUMP_LEFT) == LOW) {
escape("left", CRUISE, -CRUISE);
} else if (digitalRead(BUMP_RIGHT) == LOW) {
escape("right", -CRUISE, CRUISE);
} else {
drive(CRUISE, CRUISE);
}
delay(10);
}
Code walkthrough
The key functions of the sketch, and what each one does.
motor sketch.ino
Drives one motor with a signed speed from -255 to 255. A positive speed puts PWM on the first input and holds the second LOW. A negative speed swaps them, so the motor spins the other way.
// One motor as a signed speed, -255 to 255: PWM on one input, the other low.
void motor(int in1, int in2, int speed) {
if (speed >= 0) {
digitalWrite(in2, LOW);
analogWrite(in1, speed > 255 ? 255 : speed);
} else {
digitalWrite(in1, LOW);
analogWrite(in2, -speed > 255 ? 255 : -speed);
}
}drive sketch.ino
Sets both sides at once by calling motor for the left and right motors. Two different speeds make the car turn.
void drive(int left, int right) {
motor(AIN1, AIN2, left);
motor(BIN1, BIN2, right);
}escape sketch.ino
The reaction to a bump. It prints which side was hit, brakes for 150 ms, reverses for 500 ms, then drives the turn it was given for 400 ms. The left bumper turns the car right, and the right bumper turns it left.
void escape(const char *side, int turnLeft, int turnRight) {
Serial.print("bumped on the ");
Serial.print(side);
Serial.println(": back off and turn away");
brake();
delay(150);
drive(-CRUISE, -CRUISE);
delay(500);
drive(turnLeft, turnRight);
delay(400);
}loop sketch.ino
Checks the left bumper first, then the right. If neither is pressed, the car drives straight at CRUISE. A short 10 ms delay keeps the checks steady.
void loop() {
if (digitalRead(BUMP_LEFT) == LOW) {
escape("left", CRUISE, -CRUISE);
} else if (digitalRead(BUMP_RIGHT) == LOW) {
escape("right", -CRUISE, CRUISE);
} else {
drive(CRUISE, CRUISE);
}
delay(10);
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The car turns toward the wall instead of away This project
Check that the left bumper is on pin 7 and the right on pin 8, and that each side's motor wires match the driver outputs. - The bumpers never trigger This project
Wire the switch's COM pin to ground and its NO pin to the Arduino pin. The sketch looks for LOW. - The motors do not move This project
Check that the driver's VM pin has the 6 V supply and that its GND is shared with the Uno's GND. - The motor does not turn or only one direction works. Motor driver
Power VM from 2.7 to 10.8 V and drive both inputs of a channel. One HIGH and one LOW spins it. Swap to reverse. Both LOW coasts, both HIGH brakes. - Speed control is jerky or the driver gets hot. Motor driver
Use PWM on one input and hold the other steady. The chip gives about 1.5 A per bridge, so stay below that, and join grounds. - The car drives in circles or goes backwards. Robot car chassis
Motor polarity decides the direction. Swap the two wires on a motor that spins the wrong way. For a straight run, the motors are never identical, so trim the speed on one side. - The motors do not run, or the board resets when they start. Robot car chassis
Motors draw far more current than a pin can give. Use a motor driver such as an L298N or L293D. Power the motors from a separate battery pack and join its ground with the Arduino ground. - The input reads the wrong level, or floats when released. Limit switch
Use COM and one contact. NC is closed at rest, NO closes when pressed. Add a pull-up or INPUT_PULLUP so the pin never floats.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.