We're creating an internet-controlled robot used to carry grocery, essential goods, medicines to whom are affected by COVID-19. We live in Italy and it's very problematic to deliver such commodities to people who are quarantined: volunteers have to carry them in places which are contaminated, risking health in first person everyday. An instrument like this one could save lives and also help the cases curve to flatten. By also creating an intuitive guide, everyone could create his robot and share it with his community.
We wanted to create a project which would be more ready-to-make as we could. We know that there's a lot of people playing with electronic stuff who would be very pleased to help in such a difficult situation but they can’t because they are not familiar with controllers, web frameworks etc. With our guide enthusiasts could make robots which would carry goods to people. DIYers wouldn’t spend lots of money as they could use recycled stuff, dissembled from old wheelbarrows, tractors etc.
We needed a robot capable of transporting package without exiting our home. To manage this we used long range control, heavy capability and a camera to see the surroundings. We opted for a 4 wheel and 2 motors rover drivable through internet with a Raspberry pi4. We want to clarify that the robot can be made in every dimension and configuration as the software parts are independent from the mechanical parts. You just need to choose the right motor driver and adapt it to the code.
P3psiHere are some photos about our creation, P3psi, a name which came from its colors, blue and red.
This is our P3psi at work, carrying goods to an old lady during quarantine:
Step 1: Building the Rover- Step 1.1: Building the frame and mounting the motors
Our motors are recycled from an old electric wheelchair. They work on 24 volt DC current and have a worm gear reducer which unleash 78 rpm output.
The frame is made with 30x30 mm steel tubes which provide great resistance and lift capabilities. We tested the rover and managed to carry 100kg. Dimensions, 600x800 mm, are a good compromise between liter capability and portability.
We opted for an external frame that guarantees a protection for wheels, chain and transmission. It also cover people surrounding itself.
First thing we did was measuring and cutting 4 tubes, two of them 600 mm long and two 400 mm long. Cuts were made with an horizontal metal cutting band saw at a 45° degree angle for a better contact which guarantees a better weld result.
Now the tubes are fixed in the right position with clamps and welded together with a TIG welder.
Motors are mounted with nuts and bolts through aluminum plates in two other 30x30 tubes, not welded to the frame but fixed through other bolts with the possibility of disassemble to permit to work on the wheels.
We also took care of mounting the motors in a way that ensure a good weight balance.
We used 4 M20x100 bolts as wheel axes, compatible with the inner diameter of the choosen wheels. The process of welding these bolts on the frame is crucial. Axes must be right placed and perpendicular to the frame to ensure a good and straight motion.
Lately a battery support was made and mounted in the midle of the robot, between the two electric motors. This support consists of two 30x30 steel angle bar bolted into the internal support frame, two o-rings TIG welded onto them to fix vent pipes from two 12V 14A/h scooter batteries and an elastic ring to keep the battery down.
Electronics are placed inside an ABS electrical box, bolted into the frame in the front side of the rover.
It is important to contain the heights of the robot, so it's easier to make space for the package rack, mounted on top of the power unit and the brain of the rover.
Four 180mm long, 30x30 mm square Inox steel tubes are welded into the corners of the external frame in an upright position. In two of these hinges are welded and the other two ar drilled
The rack is made with a 40x40 mm steel bar angle in the same way of the frame and with the same dimensions ( 600x800mm ). Inside this rectangular frame an alluminium plate is riveted. First make a hole through both alluminium and steel support, than rivet the piece with a rivet gun.
This support is welded by one side into the two hinges and by the other side to two little steel bar angle with two holes that coincide with the two already made in the square steel tubes. Inside these holes a bolt is inserted and forms a secure system for the "tipper body".
Lately a 3/4" steel tube is fixed with two pipe holder in the back left side of the rover. This will be the support for the camera bracket. We choose to paint it with a cool Pepsi red.
- Step 1.2: Building the transmission
This is the hardest part of the building process.
As transmission system we used two recicled old bicycle chains and six 22T chainwheels, creating a four wheel traction with a 1 to 1 reduction ratio. We also tried a 1 to 1, 455 ratio using bigger chainwheels (32T) to the motors, but that setup increased the speed of the robot, compromising wheels power output.
We also used two litle gear as a chain tensioner obtained form a gear shifter.
Two chainwheels were welded as pinion in the original electric motors pulleys, requiring little work.
Now the wheels are modified to fit the chainwheels. We made sure to buy wheels with a steel interior and luckily we found a set with rim drilled to fit 4 M8 bolts. We replaced the original ones and mounted 4 longer bolts, with a spacer made from a 10mm steel tube cutted at 30mm lenght.
After mounting wheels, motors and chains we realized the necessity of adding a chain tensioner to our system. We made a 6mm wide cut on the high face of the internal frame in the side we had more room, to fit a litle sliding support.
The support is made from 30mm steel bar, it's purpose is to slide left and right a little chainwheel, recovered form a gear shifter, that push the chain.
- Step 1.3: Boards connections and cable management
The easiest and most efficient way to control a DC motor is through a motor driver.
We tested different types of motor drivers, starting with low quality and cheap ones, to more expensive and solid ones. We burned a driver and just after some tries we managed to solve the problem by investing in a good one. We suggest to you to buy a high quality component to get things done at the first attempt.
A motor driver take the tension input and change the output parameters to the motor according to signal from that receive from a microcontroller.
On input it need a signal for the direction (5V = forward, 0V = backward) and a PWM signal for the speed for both of the 2 channel. It also needs a 5V and a ground logic power from the same microcontroller.
All of those signals came from a Raspberry where our program is running.
To power our driver we used 2 motorcycle 12V batteries connected in parallel, for a total of 24V.
We also modify our driver adding two big sinks that help cool down the transistor and prevent a puch through.
The voltage from the battery doesn't go directly to the driver but before it passes through a connector that help to work on the electronics and also through a key switch. In addition, we added a led with a 1, 5k Ohm resistor in series to indicate when the tension is on.
To power our Raspberry we used a car USB charger that can take 24v input from batteries and power a normal USB device. Than we used a classic USB type C cable.
Attached to the USB charger we also connected the power supply for the camera bracket servos to the PWM extender board.
The board is connected to the Raspberry through a serial connection. The wire needed are: VCC (3, 3V logic power supply), GND, SDA, SCL. In addition the board need the supply current for the servos, the 5 Volts wire is connected in the V+ pin and the ground is connected to an output servo pin to connect the servo GND to the Raspberry GND.
From the board 4 wires are attached, V+ and ground to the bracket servo and a PWM signal to each of the 2 servo.
We added a Led with a 100 Ohm resistor in series connected to the Raspberry, to indicate when the program in running.
We also connected the Raspberry Pi4 camera flat cable which carries data to the RPI Camera.
This flat cable and the cable with the 4 wire for the bracket pass through a cable conduit and than through the PVC pipe holding the bracket.
At the beginning we putted the camera in the back and the cable conduit passed in the middle of the rover. We realized the camera cable was inside big electromagnetic fields produced by the motors and as soon as one starts spinning the Raspberry loses the camera signal. We tried to manage the problem by screening the cable conduit with aluminum foils connected to the battery ground, but it didn’t work for us, so we moved the camera to the front.
We also started with a 3/4” steel tube as bracket holder, but in this way the tube created an antenna effect corrupting the signal from the camera, so we switched to a PVC pipe.
At the bottom of the page you can find our Fritzing schematic file.
- Step 1.4: Designing and 3D printing thePan and Tilt camera bracket
We tried to push ourself out our boundaries and we decided to 3D print the camera bracket. This was our first time using a 3D printer, but we are pretty happy with the result.
We wanted to use 2 servo motor, one for the Y axis and one for the X axis. They are easy to program, precise and reliable. Luckily we found two of this motors in an old and broken toy helicopter. We also wanted to add 2 bearing that we found in the house to make everything smoother.
We did some paper design, we measured our motors, our bearings and our camera and than we launched Autodesk Fusion 360 and draw our bracket. (You can use your favorite CAD program)
The final support is made from 5 different parts.
The 5 pieces are exported in STL format from Fusion 360, opened with Ultimaker Cura and 3D printed with PLA with 50% infill.
Than we assembled it with M8 bolt as axes and screw and mounted in the 3/4" tube fixed on the rover.
At the bottom of the page you can find our Autodesk Fusion File.
Step 2: Coding the roverTo control the rover you have to use a Raspberry Pi or equivalent. The project was originally made with a Raspberry Pi4, but since we won the Balenafin Board, we used that interface because it had an integrated 4G module, so we could use it instead of a 4G external modem. The procedure to get things working it's completely the same.
In brief we're going to create a Python server that drives motors and servos by listening data from an HTML page. In that page we have implemented two joysticks, to factually drive the rover, and the video, which is taken from another rendered Apache webserver.
- Step 2.0: Setup Raspberry Pi/BalenaFin with latest Raspbian
The first thing we are going to do is to install the latest version of Raspbian. I followed the official guide from the site. I recommend to download the version with desktop and recommended software from here.
This is the official guide. You have to download the software, and mount it into an SD card (at least 16GB raccomanded) with the PI imager. You have to connect a screen, a mouse and a keyboard to the Pi and to boot it up. (USB-C phone charger is ok to get things done)
When you install the OS after the flash, things are simpler if you choose visual install. After the process is done you should see something like this:
- Step 2.1: Install Libraries
This program uses lots of libraries, so, before coding, we have to install all of them. If you already have some installed, you can skip relative passages.
First thing, we're going to update dependancies, by typing on a terminal:
sudo apt-get update
So, the first thing we're going to install is Flask. Flask is a microframework written in Python. It's used to create a simple web server to host our python program. As the official site says:
“Micro” does not mean that your whole web application has to fit into a single Python file (although it certainly can), nor does it mean that Flask is lacking in functionality. The “micro” in microframework means Flask aims to keep the core simple but extensible.
So we're create a simple but powerful web server which can elaborate efficient requests. Here's the code to install it:
sudo apt-get install python3-flask
Then we have to install the flask CORS library. This is a Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible. CORS is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served. So if you have not implemented CORS, you can't get or send data to the server. If you want to know more about CORS wiki it
$ pip install -U flask-cors
We are also installing a library to control the PWM expander (pca9685) to drive servo motors. I got this simple but strong library from here
sudo pip install adafruit-pca9685
if you have installed a non complete Raspbian, you also have to install Numpy for maths, csv to read csv files, and also RPi.GPIO to control inputs and outputs of the Pi.
- Step 2.2: InstallRPi-Cam-Web-Interface
Last but not least we have to install RPi-Cam-Web-Interface. I tried lot of video stream libraries, starting from the cool project made by Miguel Gringberg who used Motion-JPG, or UV4L, but both had too high latency, so the robot was pretty undriveable in real time. So I came to this very complete and solid project. RPi-Cam-Web-Interface is hosted in an Apache web server, so there will be a second web server just to handle the video. It may seem complicated, but it's the most effective way I found out to manage the video latency issue.
So, as the official documentation suggests, here is the installation guide:
Step 1: Install Raspbian on your RPi
Step 2: Attach camera to RPi
Step 3: Important : Enable camera support - for Desktop Raspbian, see http://www.raspberrypi.org/camera, or for Raspbian Lite, run:
sudo raspi-config
Select Option 5 Interfacing Options, then P1 Camera, then Yes. Exit and reboot your Pi (this is important!)
Step 4: Update your RPi with the following commands:
sudo apt-get update
sudo apt-get dist-upgrade
sudo apt-get install git
(git will already be installed on non-Lite installations of Raspbian, but won't hurt to make sure.)
Occasionally if camera core software updates have been done then a sudo rpi-update may be used to benefit from these before they become available as standard.
Step 5:
Clone the code from github and enable and run the install script with the following commands:
git clone https://github.com/silvanmelchior/RPi_Cam_Web_Interface.git
cd RPi_Cam_Web_Interface
Then carry on with the installation:
./install.sh
Make sure to choose a port which is free during the installation. In our case we chose port 8118. So when you success in installing the library, if you type in the web navigation barhttp://localhost:8118/html/, you should see something like this:
I recommend from this point to know what are IP addresses and ports so how to use it to access to web servers.
If you already know something about this topic it's time to get our local RPi IP address, to access to it over LAN. Type in your terminal:
ifconfig
From this moment, you can access to the RPi-Cam-Web-Interface web server from every device connected to your local network by typing in the web bar:
http://YourIPAddress
:8118/html
- Step 2.3: Getting started
The best thing to do when you start a new project is to create a folder to organize data. For example, you can create a workspace from the terminal. In my case:
cd Documents
Create a new folder:
mkdir Pepsi
The above command will create a folder named "Pepsi". This will be the main one where we will save the main python file.
/home/pi/Documents/Pepsi
Now, on this folder, let's create 2 other sub-folders: static for JavaScript files and csv (you'll see below) and templates for HTML files:
cd Pepsi
And create the 2 new sub-folders:
mkdir static
and
mkdir templates
The final folder tree will look like:
/Pepsi
/static
/templates
- Step 2.4: Dive into Python Code
We are using Python to create the main file in which we are creating a web server in port 5000 to render an HTML webpage and to manage website requests to move motors and servos. So the website will send data to the Flask python server, which will be elaborated into electrical signals for motors. Let's start from importing libraries:
from flask import Flask, render_template, request
import RPi.GPIO as GPIO
import Adafruit_PCA9685
from time import sleep
import json
from flask_cors import CORS
import csv
import numpy
Then we are going to define PINs. A stands for motor 1, B for motor 2 ledON is a led which will be always on to know if the script is running. So in the setup we'll set it to HIGH. Servo min and max are the corrisponding normal numbers for -90 and 90 degrees position.
pinPWMA = 32
pinAIN = 10
pinPWMB = 33
pinBIN = 8
ledON = 7
servo_min = 150
servo_max = 600
servo_0 = (servo_min+servo_max)/2
servoRatio = (servo_max - servo_0)/100
Then we're creating the Flask server app and implementing CORS
app = Flask(__name__)
CORS(app)
So it's time to start the input/output initialization. Here we're setting the pins we discussed before as PWM outputs to set motor speed, INs to motors directions and led. BOARD mode is the simplest pin numeration for RPi. Here is the scheme, valid for every raspberry pinout:
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(pinPWMA,GPIO.OUT)
GPIO.setup(pinPWMB,GPIO.OUT)
GPIO.setup(pinAIN,GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(pinBIN,GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(ledON,GPIO.OUT, initial=GPIO.HIGH)
Now it's time to setup PWM port. PWM stands for pulse-width-modulation and it's a particular kind of electrical signal which can be read by a motor driver and be used to modulate motor speed. So two PWM objects are created with a frequency of 20kHZ. Frequency varies from driver to driver, if it's too high there's a risk to get something burnt, if it's too low, motor will change speed in a non-linear way.
When the frequency is set, we can change motor speed simply by adjusting PWM duty cycle, which varies from 0 to 100. We're starting from a 0 value.
PWMA = GPIO.PWM(pinPWMA, 20000)
PWMB = GPIO.PWM(pinPWMB, 20000)
PWMA.start(0)
PWMB.start(0)
Then we're creating a Servo object. This Object is used to drive the PCA9685 board. This is a programmable circuit which extend the number of PWM ports of RPi. In fact the standard RPi only has 2 PWM ports and we need another 2 to drive servos. Servo object is made to drive all the 16 PWM ports of the device. We'll use 1 and 2. We'll set the frequency to 60Hz which is the standard for Servos. Then we're setting the position to the centre, which we defined as servo_0 before.
servo = Adafruit_PCA9685.PCA9685()
servo.set_pwm_freq(60)
servo.set_pwm(1, 0, servo_0)
servo.set_pwm(2, 0, servo_0)
We are now importing two.csv arrays [201]x[201] from the two files in the static folder, one for each motor, which are functions that translate joysticks positions to motor outputs. We are discussing this part later in the guide.
# SX motor
readerSX = csv.reader(open("static/motorSX.csv", "rb"), delimiter=",")
SX = list(readerSX)
funcSX = numpy.array(SX).astype("float")
# DX motor
readerDX = csv.reader(open("static/motorDX.csv", "rb"), delimiter=",")
DX = list(readerDX)
funcDX = numpy.array(DX).astype("float")
It's time to define our Flask Server. We create elements which are called routes. These are functions which are called when a host connects to the server by typing a certain path after its IP address in the browser navigation bar. For example in this case, we defined the route "/", which is the standard path called when host connect to http://yourIP:yourport/. So here we will create the main function of the server, the one which is called when a new host is connecting. This is about rendering the index.html page. This is the home webpage of the server. We are discussing it later. The if clause is to make sure the host is trying to retrieve data, in this case the HTML page. If you want to know more about HTTP methods and how websites work there's a lot of documentation online, we suggest to start from here.
@app.route("/", methods=['GET','POST'])
def index()
if request.method == "GET":
return render_template("index.html")
After main route was created with success, we're creating another important route, the route post. This is, probably the most important part of the program. It's the function which is called when a POST HTTP request is called from a host passing through /post url. In fact into the HTML webpage we will create 2 joysticks which will send their position data through this method with a refresh rate of 50ms. So every 50ms information will be sent from the host playing with joysticks into the HTML rendered page to this route.
@app.route("/post", methods=['GET','POST'])
def poster():
if request.method == "POST":
So, as we said, we have to catch data, and to to do this, we are using the flask.request class. We are retrieving JSON data, which is the typical way data is sent and received in web environments. In this case we will extract from raw data variables such as motorX or servoY.
content = request.json
motorX = json.dumps(content['motorX'])
motorY = json.dumps(content['motorY'])
servo1 = json.dumps(content['servoX'])
servo2 = json.dumps(content['servoY'])
Then we're translating new data into INT variables to use them as matrix indexes
intMotorX = int(motorX)
intMotorY = int(motorY)
intServo1 = int(servo1)
intServo2 = int(servo2)
Now we're using the motor function results matrix (See Using Matlab to translate joystick position into motor Input) to create the two variables which will drive motors. These variables vary from -100 to 100, with the + or - sign to indicate the verse, and the module to indicate the speed. For example a 100 stands for max speed clockwise, a -50 half speed counterclockwise.
motor1Dir = int(funcSX[intMotorX+100][intMotorY+100])
motor2Dir = int(funcDX[intMotorX+100][intMotorY+100])
So we're translating this numbers into PWM signal to motor:
# Motor1
if motor1Dir > 0:
GPIO.output(pinAIN, GPIO.HIGH)
PWMA.ChangeDutyCycle(abs(motor1Dir))
else:
GPIO.output(pinAIN, GPIO.LOW)
PWMA.ChangeDutyCycle(abs(motor1Dir))
# Motor2
if motor2Dir > 0:
GPIO.output(pinBIN, GPIO.HIGH)
PWMB.ChangeDutyCycle(abs(motor2Dir))
else:
GPIO.output(pinBIN, GPIO.LOW)
PWMB.ChangeDutyCycle(abs(motor2Dir))
To close the Post route we're matching the servos positions with joysticks ones by using the set_pwm class to write joysticks' positions multiplied by the constant servoRatio. Minus or plus is to invert axes.
servo.set_pwm(1, 0, servo_0 - int(intServo1*servoRatio))
servo.set_pwm(2, 0, servo_0 - int(intServo2*servoRatio))
sleep(0.05)
Last we're creating the Flask server on 0.0.0.0 address with default port 5000
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
- Step 2.4: Creating the index.html HTML main webpage
In this section we're creating the webpage rendered by Flask server when a host connect to device's IP address. To better get into the program, I recommend to download the index.html file from the documentation of the project and to open it beside this tutorial.
In the first part contained into the tag <style> is to organize the webpage, formed by a row with two lateral columns where we'll put two joysticks.
Than as we've done with Python code we're importing some libraries, in this case 2, a joystick library and AJAX.
<script src="static/joy.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
The first one is a very solid and well written library made by Roberto d'Amico aka Bobbotek, which you can find here. The second is AJAX, a set of web development techniques using many web technologies on client side to create asynchronous web requests. We're using this to send POST requests to Flask server.
Then we're creating into the body an iframe object that will render the RPi-Cam-Web-Interface. We are rendering the min.php file which is formed by the only video. If you'll click on the video it will occupy all the frame.
<iframe id="myFrame" width=100% height=600 style="border:none"></iframe>
Now we are creating divs to insert joystick object. Then we will start coding in Javascript.
function POSTer(toLolcalHosta, toLolcalHostb,toLolcalHostc, toLolcalHostd)
We start from creating the POSTer function, which uses AJAX library to post data from this webpage to Flask server we created before. AJAX known as Asynchronous JavaScriptand XML is a library which can create POST request and send JSON data. In this case we are sending joysticks' X and Y coordinates to the server.
formDATI = {
"motorX" : toLolcalHosta,
"motorY" : toLolcalHostb,
"servoX" : toLolcalHostc,
"servoY" : toLolcalHostd
};
var formData = JSON.stringify(formDATI);
This is to prepare data. JSON data has a particular structure made by a header related to a value. For example "motorX" : 3.
$.ajax({
type: "POST",
url: window.location.href + "post",
data: formData, // Data is JSON dataset
success: function(){},
dataType: "json",
contentType : "application/json",
secure: true,
headers: { // Header is made for CORS policy
'Access-Control-Allow-Origin' : '*',
}
Then we are creating the AJAX request. We are sending a POST request to site/post url, in json format with a header to fit in the CORS policy.
document.getElementById("myFrame").src = window.location.href.replace("5000", "8118") +"html/min.php"
Now we are setting the source for the iframe object. It's the page url with changed port.
var Joy1 = new JoyStick('joy1Div');
var Joy2 = new JoyStick('joy2Div');
We are creating the two joystick objects in the places we created before. They will create values from -100 to 100 depending by position.
setInterval(function(){
joy1Xvar = Joy1.GetX();
joy1Yvar = Joy1.GetX();
joy2Xvar = Joy2.GetX();
joy2Yvar = Joy2.GetY();
POSTer(parseInt(joy2Xvar), parseInt(joy2Yvar), parseInt(joy1Xvar), parseInt(joy1Yvar))
}, 50);
Finally we are sending data collected by joysticks in variables every 50ms with the setInterval class.
- Step 2.5: Using Matlab to translate joystick position into motor Input
This part is about maths. You can understand it just with a little knowledge about 2 variables function and interpolation or you can just skip it by knowing that those.csv matrixes traslate joystick positions into motors input.
In the previous section we introduced DX/SX matrixes loaded from two .csv files. Probably you were asking yourself what that was about. We created with Matlab a function which translates values sent from joystick into input to motors. We interpolated a continuous two variables curve for each motor which generate a value having a limited [-100, 100] domain and codomain. We wanted the output to follow this scheme, red for left motor, blue for the right one.
We use the module of the output as the PWM duty cycle of the motor, and the sign for the verse.
From this values we want to create a continuous variation to get motors change speed in an analog way. So we are using MatLab to create a linear fit from these data. This is the final result:
We are using MATLAB_R2020a in this guide. We are using the Curve Fitting app which provides a flexible interface where you can interactively fit curves and surfaces to data and view plots. You can open it by typing in Command Window:
cftool
I'll explain the procedure by creating motorSX (left) function. Before starting to fit the two curves you'll have to create data matrix to fit the curve. So, in this case:
X = [ -100 0 100 -100 0 100 -100 0 100];
Y = [ 100 100 100 0 0 0 -100 -100 -100];
Z = [ 50 100 100 0 0 100 -50 -100 -100];
Now we are opening the tool to fit the curve. You'll have to select data we created before and to fit the curve with a linear method. If the curve doesn't fit as well as you expected, you'll have to add in the source data some other points.
It's time to export the fitted curve as a Matlab function to use it to create the matrix. You have just to export the interpolation by clicking Fit - Save to Workspace. I'm exporting the fit as fitMotorSX. So it's time to create the matrix.
A=ones(1,201);
We are creating a 201 columns vector to use it in a cycle to load data into a MotorSX matrix with this cycle:
MotorSX = [fitMotorSX(A*(-100) ,[-100:1:100]) ];
for k= -99:1:100 MotorSX = [MotorSX; fitMotorSX(A*(k) ,[-100:1:100]) ];
End
Now we can see if the result was as expected by typing:
surf ([-100:1:100], [-100:1:100], MotorSX)
Last thing to do is to export it as a .csv file:
xlswrite('motorSX.csv', MotorSX)
You can now redo the procedure for motorDX.
- Step 2.5: Exiting the LAN
Now you can drive your robot connected to your wifi local network just by typing in your web browser its IP address, in my case:
http://192.168.0.60:5000
If you are planning to use it often in that particular network, I suggest to set a static IP distribution from your router/firewall to use always the same IP. In other cases you can always search for RPI IP address from its terminal or with lots of apps which scan local devices like Fing.
If you want to go online and drive your unique Pepsi from everywhere in the world, the first thing you got to do is to get it connected to internet from everywhere. If you are using Balenafin you just have to go get a 4G SIM, because an internet modem is integrated in the board. If you are using a normal Raspberry PI, you have to buy an internet modem, which could be an USB one, a battery Router or a 220V classical modem (You'll need a voltage transformer!). A cheaper way is to use an old smartphone connected with hotspot (or also your smartphone).
Now you can drive it just by connecting in local to the router's wifi as before. You are driving it everywhere, but you got to be in router's wifi range. Now comes the problem. Your IP when is Local it's simple to catch, but if you want to access to it from outside it's problematic. IP address are not always public and easy to find from everywhere in the world.
This part is very tough, and it's not solvable with just some passages in a univocal way. This is about static-dynamic IP addresses, private IPs, VPN and lot of other stuff which change by the country you live in and internet providers.
The easiest way to cope with it is to get a Static IP sim from your internet provider. This could be very expensive if you live in a country like Italy, because there are basically no phone companies which sell them. However, this is the easiest and the most efficient solution to drive the robot without latency from everywhere without problems. If you have a public static IP, you'll just have to connect to it as a local one to drive the robot.
There are some other DIY ways to get connected to your robot. There are lot of services online like DYN.com which can make your public IP static. There are also lots of solutions very easy to use and free which tunnel your private ip like remote.it.
I tried to use this one, it's easy to use, but latency starts to be high and I don't raccomend it unless if you have a very strong 4G connection. (to manage to see video you got to do some work with APIs to catch Apache server IP address)
You can also create a VPN server to get your IP address. If your ip is under NAT it's the only way around to have enough mobility to get video working. It's very complicated, there are lots of guides and you need to pay for a server with a public static IP.
So every way is good to get your RPI visible from everywhere.
Conclusions and go furtherIf you followed this guide until here and you got things done congratulations! You'll have your unique robot done! Thanks for giving us faith! We hope you liked our project and that you'll use the robot to help people in difficulty by carrying goods. This project was made to help to flatten the COVID-19 spreading virus curve, but can also be integrated with lots of sensors, mechanical parts and other stuff to get almost everything done.
To help with Coronavirus it would be very helpful to add a thermal camera to know if people around are infected. They are a bit expensive but very easy to implement also into the html page (I suggest to use a MJPEG streaming method).
You can also implement speakers and microphone in the webpage to talk with people around or to just send messages (always with post method to send commands and audios served by Python)
Thanks for Reading!