This interesting project will cover all things required for the ultimate goal of building a mobile remote surveillance camera.
This interesting but complicated project will cover things from designing building a robot, to advanced configurations in linux (raspberry pi) to building an Android application and controlling the robot.
So this being said itās more ambitious then the average projects, but i think youāll have a lot to learn by examining some ideas here or even replicating the entire project.
First weāll build the robot using plexiglass, plastic sheets, DC motors with gearboxes and various electronic components. The device will be able to move independently the two front wheels and it will be able to use itās headlight. Then weāre going to set up the raspberry pi powering the robot and configure the project and install various dependencies. Then weāre going to build and install an android app and use it to control the robot remotely using the camera and a wifi connection.
The technologies and concepts will be exploring here:
Development platforms: Arduino, Raspberry pi, Android
Electronics: H-bridge, using a transistor to drive a big load, infrared sensors
Linux : using docker, docker compose, configuring services using systemctl, video streaming
Programming: Android applications, python, arduino language, serial communication, MQTT
Step 1: Things Required
Parts:
1. Plexiglass sheet
2. Plastic sheet ( you can also use a plexiglass sheet here )
3. Glue
4. Tyre + DC motor with gearbox + bracket. Small nuts and bolts, hexagonal metal spacers
6. 2 x any directional wheel tyre
7. Small LED flashlight (it will be transformed into a headlight)
8. Arduino pro mini 328p
9. 2 x infrared obstacle sensor
10. PCB
11. NPN tranzistor (to drive the flashlight)
12. L7805CV 5V regulator
13. L298 H-bridge
14. Rezistor 220 Ohms
15. Male usb connector
16. Male micro usb connector
17. Various wires
18. 3 v regulator (for communication between arduino and raspberry pi)
19. Male & female PCB connectors
20. On / off switch
21. XT-60 female LiPo connector
22. 2S 1300 mAh LiPo battery with XT-60 connector
23. 5v battery pack
24. Raspberry Pi 3
25. Raspberry Pi card
26. Raspberry Pi case
27. Raspberry Pi camera
Tools: 1. USB to serial FTDI adapter FT232RL to programm the arduino pro mini
2. Arduino IDE
3. Drill
4. Fine blade saw
5. Screwdrivers
6. Soldering iron
7. Wire cutter
Skills:
1. Soldering, check this tutorial
2. Basic arduino programming, this tutorial might be useful
3. Linux service configuration, package installation
Step 2: Building the Robot Platform
The robot weāre going to build is going to have the following specifications:
ā It will have traction on the front wheels by two separately DC motors
ā the back wheels should be able to move in any direction 360 degrees
ā the direction will be controlled by varying speed on the front wheels so no separately direction mechanism is needed, also the robot will be able to rotate on the spot
ā it will have lights on the top
ā it should have enough room for the electronics, batteries, and a raspberry pi case with a camera
ā a few cm ground clearance is needed to overcome small obstacles
Donāt forget to check the images for important details and building tips.
Weāre going to build the robot from plexiglass or hard plastic, iāve used them both but you can choose whatever you wish.
The base plate will be 18 x 13 cm on the base plate the DC engines will be attached with metal brackets nuts and bolts. The H-bridge will be mounted the middle of the plate facing the floor. The back wheels will be attached using 2 cm hexagonal metal spacers (one side male one side female)
A big hole near the H-bridge is needed to connect the electronics on the top side.
The top part of the robot will consist of two plates in āLā shape one will be 12 x 13 cm and the other 6,5 x 13 cm. The plastic plates will be glued together. These plates will provide cover for the electronics, a place to mount the headlight and a support for the raspberry pi case. The top part will be attached from the bottom part using 6 cm hexagonal metal spacers )
Step 3: Building the Electronics
Pinout (arduino):
Led flashlight: D3
Left motor: PWM (D5), EN1, EN2(A4, A5)
Right motor: PWM (D6), EN1, EN2(A3, A2)
Infrared sensors: Front (A0), Back(A1)
Raspberry pi communication pins: Tx: D11, Rx: D10
Building the PCB, assembly
1. In the last step weāve already accommodated the H-bridge on the floor side of the robot. Weāll also need to install the two infrared sensors one in front and one in the back. Weāre going to mount them on the chassis using a small metal plate. The metal plate will be like an āLā shape, and will have two holes. Using nuts an bolts weāre going to install it on the chassis. The sensors will be on the middle of the chassis one in the front and one in the back.
2. Next the headlight part, iāve used a 5 volts led flashlight for this. Iāve cut the headlight exposing only the āheadā part and soldered two wires to power it. Then iāve glued the headlight on the middle of the robot top part and drilled a hole near the headlight put the cables through the hole and soldered a small female two wire connector to it.
3. Assembling the raspberry pi case. You will need a raspberry pi, a pi camera, memory card at least 4 GB, an pi camera connector. Insert the card with the latest Raspian installed, then take the pi camera connector insert it carefully on the raspberry pi, then insert it in the camera, then close the case.
If you donāt know how to install the Raspian operating system check this link.
For more information on how to install the camera and enable it check this official article.
4. Building the PCB with the main electronic components. Iāve attached the fritzing schematics in fzz format and as a picture. You can use it as a reference oh how to build the electronics.
Soldering steps:
a. Cut the female PCB connectors, there are two 12 pin connectors for the microcontroller and two 5 pin connectors, there are two 3 pin connectors for the IR sensors, a six pin connector for the H-bridge and a pin connector for the raspberry pi communication (ground, TX, RX) b. After all the connectors are cut there must be soldered on the back of the PCB
c. Solder the KF301-2P connector
d. Solder the NPN tranzistor and the corresponding resistor to itās base
e. Solder the L7805CV 5V regulator
f. Solder the 3.3 volts regulator on the arduino to raspeberry pi TX line
g. Solder the male pins to the arduino pro mini
h. Solder all the red(+), black(-), and white(signal) thin wires according to the fritzig schematic
i. Solder a male connector to the breadboard for the flashlight
5. Connectors
a. Build a connector from the 5V USB battery pack to the raspberry pi and arduino, you will need a male USB connector type A, a male micro usb connector black and red wires, heat shrink tubing and a female to female breadboard connector. First cut the female to female connector in two, these parts will go into the arduino negative and positive male pins. The type A USB connector will send power to the arduino and also to the raspberry pi using a micro usb connector. Check the images for soldering usb tips.
b. Build the connector to the LiPo battery to the electronics board, you will need a XT-60 female LiPo connector, red and black wires, heat shrink tubing and a small switch capable of handling 10 A. The black wire will be connected directly from the XT-60 to the electronics board (KF301-2P plug in screw connector), the red wire will be connected through the small switch
c. Connect the two IR sensors of the robot to the corresponding female connectors on the PCB using female ā male breadboard connectors
d. Connect the H-bridge to the 6 pin female connectors to the PCB using male ā female breadboard connectors
e. Connect the motors positive and negative terminals to the H-bridge
f. Connect the H-bridge main power supply to the KF301-2P plug in screw connector on the PCB
6. Before placing the arduino to the PCB double check everything using a magnifying glass and a multimeter
Step 4: Arduino Code
First i need to answer an important question: Why does an intermediary arduino layer has to exist and not directly connect the Pi to the electronics?
1. Itās more modular, you can reuse the arduino robot in another project without the PI
2. For safety, itās cheaper to replace a 3$ arduino pro mini than to replace a Pi (35$)
3. An arduino itās not intrerupted by the operating system like the pi is, so itās more efficient to implement PWM controlls for the mottors, polling the front and back sensors a few times per second
4. If an error might occur in the python script the robot might run forever draining the batteries and probably damaging it or catching fire if not supervised, in an arduino sketch a safeguard itās more reliable because it does not depends on an operating system
5. Itās easier to debug a decoupled system
Ok, so iāve got the Why part covered, iāll explain the arduino sketch a bit. It basically does two things:
1. It receives motor and light commands from the serial line and drive the motors or toggle the light
For example:
* āM:-25:16;ā means (-25 left), and (16 power), it wil translate to left motor 17% and right motor 32%, and direction forward * āM:44:19;ā means (44 to the right) and (19 power) it will translate to: left motor 38%, right motor 5% and direction forward
* āL:1;ā means lights and āL:0ā lights off
2. It polls the infrared sensors from the back and the front of the robot and sends data about distances through the serial line
First youāll need to download and install this library:
The main code is located on github repository here, or from you can copy paste it from below.
Upload the code to the arduino using a FTDI adapter. Now you can give the robot commands to see it work, for this just connect the second serial line and send motor or light through it. One way to do this is using a bluetooth module like HC-05 and connect it to a phone using a bluetooth application. Then give it serial commands like āL:1ā
// source for TextMotorCommandsInterpretter: "https://github.com/danionescu0/arduino/tree/master/libraries/TextMotorCommandsInterpretter"
#include <SoftwareSerial.h>
#include <TextMotorCommandsInterpretter.h>
const char MOTOR_COMMAND = 'M';
const char LIGHT_COMMAND = 'L';
/**
* how long the motor command will take effect in ms
* an incomming motor command will last for maxDurationForMottorCommand
* if it's not going to be resetted by another motor command
*/
const long maxDurationForMottorCommand = 300;
// adjust this value to limit robot speed
const byte maxPwmValue = 230;
// How long between successive distance transmissions in ms
const long transmitingInterval = 500;
const int maxObstacleDetection = 1000; // analog read max detection value
const int minObstacleDetection = 500; // analog read min detection value
const byte FLASH_PIN = 3;
const byte RIGHT_MOTOR_PWM_PIN = 5;
const byte RIGHT_MOTOR_EN1_PIN = A4;
const byte RIGHT_MOTOR_EN2_PIN = A5;
const byte LEFT_MOTOR_PWM_PIN = 6;
const byte LEFT_MOTOR_EN1_PIN = A3;
const byte LEFT_MOTOR_EN2_PIN = A2;
const byte FRONT_DISTANCE_SENSOR = A0;
const byte BACK_DISTANCE_SENSOR = A1;
SoftwareSerial masterComm(11, 10); // RX, TX
TextMotorCommandsInterpretter motorCommandsInterpretter(-50, 50, -50, 50);
String currentCommand;
long lastCheckedTime;
long lastTransmitTime;
boolean inMotion = false;
void setup()
{
Serial.begin(9600);
masterComm.begin(9600);
masterComm.setTimeout(10);
pinMode(FLASH_PIN, OUTPUT);
pinMode(LEFT_MOTOR_PWM_PIN, OUTPUT);
pinMode(LEFT_MOTOR_EN1_PIN, OUTPUT);
pinMode(LEFT_MOTOR_EN2_PIN, OUTPUT);
pinMode(RIGHT_MOTOR_PWM_PIN, OUTPUT);
pinMode(RIGHT_MOTOR_EN1_PIN, OUTPUT);
pinMode(RIGHT_MOTOR_EN2_PIN, OUTPUT);
lastCheckedTime = millis();
lastTransmitTime = millis();
}
void loop()
{
if (masterComm.available() > 0) {
currentCommand = masterComm.readString();
processCommand();
}
if (inMotion && millis() - lastCheckedTime > maxDurationForMottorCommand) {
stopMotors();
}
if (millis() - lastTransmitTime > transmitingInterval) {
lastTransmitTime = millis();
masterComm.print(getObstacleData());
Serial.print(analogRead(BACK_DISTANCE_SENSOR));Serial.print("---");
Serial.println(getObstacleData());
}
/* FOR DEBUG
motorCommandsInterpretter.analizeText("M:-14:40;");
Serial.write("Left==");Serial.println(motorCommandsInterpretter.getPercentLeft());
Serial.write("Right==");Serial.println(motorCommandsInterpretter.getPercentRight());
delay(10000);*/
}
String getObstacleData()
{
int frontDistance = analogRead(FRONT_DISTANCE_SENSOR);
int backDistace = analogRead(BACK_DISTANCE_SENSOR);
frontDistance = map(frontDistance, maxObstacleDetection, minObstacleDetection, 0, 10);
backDistace = map(backDistace, maxObstacleDetection, minObstacleDetection, 0, 10);
return String("F=" + String(frontDistance) + ":B=" + String(backDistace) + ";");
}
void processCommand()
{
switch (currentCommand.charAt(0)) {
case (MOTOR_COMMAND):
steerCar();
break;
case (LIGHT_COMMAND):
toggleLight(currentCommand.charAt(2));
break;
}
}
void steerCar()
{
motorCommandsInterpretter.analizeText(currentCommand);
float percentLeftMotor = motorCommandsInterpretter.getPercentLeft();
float percentRightMotor = motorCommandsInterpretter.getPercentRight();
Serial.write("Left=");Serial.println(percentLeftMotor);
Serial.write("Right=");Serial.println(percentRightMotor);
setMotorsDirection(motorCommandsInterpretter.getDirection());
analogWrite(LEFT_MOTOR_PWM_PIN, percentLeftMotor * maxPwmValue);
analogWrite(RIGHT_MOTOR_PWM_PIN, percentRightMotor * maxPwmValue);
inMotion = true;
lastCheckedTime = millis();
}
void setMotorsDirection(boolean forward)
{
if (forward) {
digitalWrite(LEFT_MOTOR_EN1_PIN, HIGH);
digitalWrite(LEFT_MOTOR_EN2_PIN, LOW);
digitalWrite(RIGHT_MOTOR_EN1_PIN, HIGH);
digitalWrite(RIGHT_MOTOR_EN2_PIN, LOW);
} else {
digitalWrite(LEFT_MOTOR_EN1_PIN, LOW);
digitalWrite(LEFT_MOTOR_EN2_PIN, HIGH);
digitalWrite(RIGHT_MOTOR_EN1_PIN, LOW);
digitalWrite(RIGHT_MOTOR_EN2_PIN, HIGH);
}
}
void stopMotors()
{
Serial.println("Stopping motors");
analogWrite(LEFT_MOTOR_PWM_PIN, 0);
analogWrite(RIGHT_MOTOR_PWM_PIN, 0);
inMotion = false;
}
void toggleLight(char command)
{
Serial.println("Toggle light");
if (command == '1') {
digitalWrite(FLASH_PIN, HIGH);
} else {
digitalWrite(FLASH_PIN, LOW);
}
}
Step 5: Installing and Configuring the Raspberry Pi Project and Dependencies
How does it work:
You will see a diagram of what iāll try to explain above in the attached images.
a. The android app shows the uv4l streaming inside a webview. The uv4l process runs on the raspberry pi, captures video input from the camera and streams it. Itās an awesome tool with many features
b. Using controls inside the android app lights and engines commands are issued to the MQTT server
c. The python server inside the docker container on the raspberry pi listens to MQTT commands and passes them using serial interface to the arduino. The arduino board controls the motors and the lights.
d. The arduino senses distances in front and back of the robot and sends the data through the serial interface to the python server, the python forwards them to the MQTT and they get picked up by the android interface and shown to the user
First thing youāll need a fully installed and configured Raspbian on the raspberry pi, and the camera needs to be psychically connected and configured. Also all the configuration will be done using ssh, so itās a good thing to get it configured.
We canāt cover all the basic things here, but do try these links if necessary:
If you donāt know how to install the Raspbian operating system check this link. For more information on how to install the camera and enable it check thisofficial article.
For how to configure ssh on Raspbian, check this.
If you wish to control your robot using the android app from outside the wifi, you should consider port forwarding on your wifi router, otherwise youāll be restricted to use your local ip addresses inside your wifi.
To find out your local ip address on the raspberry pi use āifconfigā:
ifconfig
.........
eth0
Link encap:Ethernet HWaddr b8:27:eb:16:e7:ff
inet6 addr: fe80::ff00:f22f:9258:b92b/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
........
wlan0 Link encap:Ethernet HWaddr 00:c1:41:00:10:f6
inet addr:192.168.0.102 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::e1f4:5112:9cb2:3839/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1678396 errors:0 dropped:0 overruns:0 frame:0
TX packets:381859 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:259428527 (247.4 MiB) TX bytes:187573084 (178.8 MiB)
.....
Weāre interested on the wlan0 inet addr, in our case ā192.168.0.102ā
The ports to be forwarded (defaults) are: 9090 for uv4l and 1883 for mosquitto. You can forward this ports to the same output ports if they areān banned from the internet provider firewall or some other ports.
Port forwarding is something isās done differently on every router, here are some tutorials: this, and you can also try to search on google āport forwarding your_router_modelā to see more relevant results.
Prerequisites:
a. install git using command line
b. clone the github project in the home folder:
The folder location itās important because in docker-compose.yml the location is hard coded as: /home/pi/robot-camera-platform:/root/debug If you need to change the location, please change the value in docker-compose too
git clone https://github.com/danionescu0/robot-camera-platform.git
c. disable the piās serial console, if you donāt know how to do that, check this link
Install Uv4l streamming:
chmod +x uv4l/install.sh
chmod +x uv4l/start.sh
sh ./uv4l/install.sh
If this fails or you need to find out more details about uv4l, check this tutorial.
Configuration:
a. by editing uv4l/start.sh you can configure the following aspects of the video streaming: password, port, frame rate, with, height, rotation and some other minor aspects
b. edit config.py and replace password with your own password that youāve set on the mosquitto server
c. edit docker-container/mosquitto/Dockerfile and replace this line
RUN mosquitto_passwd -b /etc/mosquitto/pwfile user your_password
with your own user and password for mosquitto
d. edit config.py and replace serial port and baud rate with your own, i recommend youāll keep the baud rate though. If you want to change it donāt forget to edit that on the arduino-sketch too
Test uv4l installationa. Start it:
sh ./uv4l/start.sh
b. Test it in the browser at the address: http://your_ip:9090/stream
c. Stop it
sudo pkill uv4l
Install docker and docker-compose
About docker installation: https://www.raspberrypi.org/blog/docker-comes-to-ā¦
About docker-compose installation: https://www.raspberrypi.org/blog/docker-comes-to-ā¦
Auto starting services on reboot/startup
By making the services auto start youāll eliminate the need of manually login through ssh and then activate all the services by hand, weāre going to do this usingĀ systemctl.