Robocop detects intruders and shoots them with a Lego missile launcher and can even talk now! I built this lego robot with some help from my sons, who decided on the Police theme. We wanted to build a robot that could "see" a target, aim and fire. It's build out of Lego and controlled by a Raspberry Pi, using two servos and a range sensor. I'll explain how it all works below.
Robocop uses a ultrasonic range sensor to "see" an intruder. The range sensor is an HC-SR04. You can buy a pack of 5 of these for less than £10. This sensor works by sending out pulses of ultrasonic sound, receiving the echo of the sound and measuring the time it takes to work out the distance. Kind of like a bat! They are useful in robots to detect obstacles, and they can "see" things several metres away, but they only detect things in a narrow field and only work well with solid objects. The head part of the robot holds the sensor and the other parts are just to make it look more robot like. The build of the head and non-firing arm is shown in the pictures below.
The sensor has 4 connector pins on it. On my one they are labelled: Vcc, Trig, Echo and Gnd. The Vcc and Gnd pins connect to the 5V out and Ground pins on the Raspberry Pi to power the sensor. The Trig and Echo pins connect to any two GPIO pins. These are used to "trigger" the sensor and receive the "echo" of the sound. In some of the pictures, I've connected up the sensor using a connector board I built, but all but the echo output can be connected directly to the pins on the Pi. I'll explain how to make this work in the programming section. For an explanation of the Raspberry Pi GPIO pins have a look at my robot arm project.
⇧The robot uses a servo in the base to rotate from side to side looking for a target. This is the same base section I use for my Robot Arm project. A part like this is useful for any kind of robot where you want to turn something from side to side horizontally. The plastic arm that comes with the servo is cut down and wired to a lego wheel, so it can be turned by the servo. This turns the round pieces above it, which the head section attaches to. The smooth pieces around it allow the head to turn freely. The construction of the base section is shown in the pictures below.
The servo is a 9g micro servo like used in my other projects. Like the range sensors, you can buy a pack of several of these cheaply. Another of the same type of servo is used in the arm to fire the missile. The servo has three wires. The red wire connects to the 5V pin on the Pi, the brown wire to the Ground pin and the yellow wire to a GPIO pin for the control output. I explain how to connect up a servo and get it working with a simple program in the Robot Arm project.
⇧Another servo is used to trigger the Lego missile launcher to fire. The missile launcher pieces are found in many of the Lego Star Wars and Ninjago, space ship and vehicle sets. It is a brick with a hole through the middle and a spring loaded firing mechanism. The red missile piece fits in to the launcher piece and fires when it is pushed down. To fire, the servo arm moves down, pushing down the rotating piece (with the Police sticker) that pushes down the red missile, causing it to launch. The servo then moves back to it's original position to allow the missile to be reloaded. I worked out the servo positions to get this to work by trial and error. I will explain the control code for firing in the programming section. See my Robot Arm project for how to setup a single servo and get it moving with a simple program. The construction of the arm is shown in the pictures below. More detail of the servo mount construction (which I use in several projects) is shown here.
The robot talks using a small amplifier and speaker connected to the Raspberry Pi via a circuit on the connector board I built. I set it up like this so I could have a small speaker built into my models and find out how sound output works on the Pi Zero, which doesn't have a normal audio output built into it. You can set it up like I did with an external amplifier connected to a GPIO pin, but it took a bit of messing around to get it working. As a simpler alternative you can connect a Bluetooth speaker and use that for sound output. Or if you have a monitor with speakers connected via HDMI to the Pi, you can use that for sound.
To do the robot speech I used espeak, which is an open source speech synthesizer that generates a robot sounding voice from text you provide.
You can install it with sudo apt-get install espeak
and then run it from the command line to generate speech, see their website for details of how to use it.
To check you have your sound working and espeak setup, you can run espeak from the terminal, try espeak "hello"
. Or run speaker-test
to test your sound ouput.
The robot is controlled by a program running on the Raspberry Pi.
You can download a zip file containing the code here.
The program requires the following libraries/packages to be installed for it to work: pigpio (for GPIO), ncurses (for terminal I/O) and espeak (for speech).
See the example in my Robot Arm project for instructions on setting this up.
The espeak package can be installed in the same way by entering at the terminal: sudo apt-get install espeak
.
Unzip the code zip file into a folder on your Raspberry Pi.
From the terminal go into the folder and type sh build.sh
to compile the program, then sudo ./robocop
to run it.
If you have any problems, try getting the simple example from the Robot Arm project working first, to move a single servo.
The main.cpp file contains the main program that tells the robot what to do. The rest of the files contain classes I made to wrap up all the other code that is necessary to make things work.
Below is the main program code from the "main.cpp" file, followed by a description of what it is doing:
#include <iostream>
#include "screen.h"
#include "range-sensor.h"
#include "output.h"
#include "servo.h"
#include "speech.h"
// Possible states for the program
enum States {
look = 1,
stop = 2
};
// Main program
int main() {
// Catch any errors while the program is running
try {
// Setup screen for I/O
Screen io = Screen();
// Setup the turn servo on GPIO pin 22
Servo turnServo = Servo(22, 500, 2000, 1250, 50);
// Setup the fire servo on GPIO pin 27
Servo fireServo = Servo(27, 1000, 1500, 1500, 500);
// Setup the LED for output on pin 25
Output led = Output(25);
// Setup the range sensor on GPIO pins 24 (trigger) and 23 (echo)
RangeSensor sensor = RangeSensor(24, 23);
// Keep track of current state
States state = States::look;
// Start talking
Speech speech = Speech(120, 100);
speech.say("stay back");
// Check for keys pressed until ESC key
int key = 0;
while (key != KEY_ESC) {
// Get keyboard input
key = getch();
if (state == States::look) {
// Looking
io.printLine("range: %d", sensor.range);
// Check range
if (sensor.range <= 30 && sensor.range > 0) {
// Found something, stop turning and fire
state = States::stop;
led.on();
speech.say("fire!");
fireServo.moveDown();
}
else {
// Turn the head
if (turnServo.pos == turnServo.max || turnServo.pos == turnServo.min) {
// Change direction when it gets to the minimum or maximum position
turnServo.step = -turnServo.step;
}
turnServo.moveBy(turnServo.step);
}
}
else if (state == States::stop) {
// Stopped
if (fireServo.pos < fireServo.max) {
// Once fired, wait a second, then reset and ask to reload
io.sleep(1);
fireServo.moveUp();
speech.say("reload");
}
}
// Check keys
if (key == 'R' || key == 'r') {
// Reset, start looking again
speech.say("stay back");
led.off();
state = States::look;
}
// Sleep for a short time before the next update
io.sleep(0.05);
}
}
catch (const exception& e) {
// Error or program aborted
cerr << "Error: " << e.what() << "\n";
}
return 0;
}
This is what the program is doing: