Pi robot

Raspberry Pi with a motor chassis to make two versions of a roving vehicle (Figure 1). The first version allows the robot to be controlled using a web interface. The second version is autonomous and will move around in a random manner, detecting obstacles in front of it using an ultrasonic rangefinder.

Figure 1. Pi robot

1) Open up the Raspberry Pi Configuration tool and switch to the Interfaces tab. You then need to make sure that the options I2C, SSH, and VNC are all enabled (Figure 2) before closing the window.
I2C is the interface that the Raspberry Pi uses to communicate with the motor controller. This uses two GPIO pins to send commands to the motor
SSH (Secure SHell) allows you to connect a command line tool (such as Putty on Windows or the Terminal on a Linux or Unix-based computer) tothe Raspberry Pi, so that you can enter commands remotely from another computer as if you are using a Terminal on the Raspberry Pi itself.
VNC (Virtual Network Connection) is a graphical equivalent of SSH that allows you to see what you would see on your Raspberry Pi’s monitor.
Whereas SSH is text only, VNC allows you to interact with the Raspberry Pi using the keyboard and mouse of your computer. In this chapter, we will use VNC rather than SSH as it allows you to use the Raspberry Pi’s graphical desktop, which can be useful when doing things like using the Raspberry Pi Configuration tool.

Using ifconfig you will find the MAC address of your RPi will be next to the name ‘ether’ and is shown in hexadecimal numbers. Once you have the MAC address, it can be entered into the admin console of your router along with the IP address to be reserved 192.168.x.x

From now on, whenever the Raspberry Pi connects to your network using yhe Wi-Fi interface, it should always be allocated this IP address.

Figure 2. Raspberry Pi configuration for our robot

2) You can use it with a motor driver pHAT for Raspberry Pi for your Pi robot to connect motors (Figure 3) and ultrasound sensor (Figure 4).

Figure 3. Motor driver pHAT connexions

3) There are two identical looking ultrasonic rangefinders on the market.
There is the plain-old HC-SR04 that operates at 5V logic level and there is the HC-SR04P that operates at 3V. The latter is harder to find, so if you have an HC-SR04 and want to use it for this project, then you still can, but you will need a 1kOhm resistor and will also have to wire up the rangefinder as shown in Figure 1. The differences being that the HC-SR04 (NOT P) must have VCC connected to 5V rather than 3V and ECHO on the rangefinder must be connected to GPIO pin 18 via a 1kOhm resistor.


Figure 4. HC-SR04 ultrasound sensor

The HC-SR04 rangefinder uses two GPIO pins TRIG (trigger) and ECHO. The TRIG pin connects to a Raspberry Pi GPIO digital output and event though the output from the Raspberry Pi is 3V, it will still trigger the rangefinder to send a pulse of ultrasound without any extra circuitry. It’s a different matter for the ECHO output of the rangefinder and because, on an HC-SR04, this is a 5V output, you would be connecting a 5V output to the 3V logic input of the Raspberry Pi’s GPIO pin. If connected directly, too much current would flow into the input, causing heating that may immediately or over time damage your Raspberry Pi irreparably. To guard against this, a 1kOhm resistor must be used in between the output of the HC-SR04 and the input of the Raspberry Pi. This will limit any current flowing to a safe couple of milliamps. The breadboard that supports the rangefinder is the obvious place to put the resistor (Figure 5).

Figure 5. Ultrasound sensor connected to motor driver of robot

Second version to test Ultrasound sensor only with tkinter code and Arduino code

from tkinter import Tk, Label
import serial

ser = serial.Serial()
ser.port = "/dev/ttyUSB0"
ser.baudrate = 9600
except serial.SerialException:
  print("Could not open serial port: " + ser.port)

root = Tk()
root.geometry('{}x{}'.format(200, 100))
label = Label(root, font=("Helvetica", 26))

def read_serial_data():
  if ser.isOpen():
      response = ser.readline()
          text='Distance : \n' + response.decode("utf-8").rstrip() + ' cm')
    except serial.SerialException:
      print("no message received")
  root.after(100, read_serial_data)


const int triggerPin = 8;
const int echoBackPin = 7;

void setup() {
pinMode(triggerPin, OUTPUT);
pinMode(echoBackPin, INPUT);

void loop() {
long duration, distanceIncm;
// trigger ultrasound ping
digitalWrite(triggerPin, LOW);
digitalWrite(triggerPin, HIGH);
digitalWrite(triggerPin, LOW);
// receive input from the sensor
duration = pulseIn(echoBackPin, HIGH);
//calculate distance
distanceIncm = duration / 29 / 2;
// send data over serial port
Serial.print(‘distance in cm is :’);

4) Create the web interface

The W, A, S, D, and Z letters are used to identify the buttons for forward,left, stop, right, and backwards, respectively, because those keys on your keyboard will interact with the browser page, so that when steering the robot from a web page, you can use those keyboard keys which are conveniently arranged in a cross shape ( Figure 6).

And the corresponding python code

$sudo apt-get python3-bottle

# Class for motor control of Motor Drive pHAT

from PCA9685 import PCA9685
import time

pwm = PCA9685(0x40, debug=False)

class MotorDriver():
def __init__(self):
self.PWMA = 0
self.AIN1 = 1
self.AIN2 = 2
self.PWMB = 5
self.BIN1 = 3
self.BIN2 = 4

def set_motors(self, left_pwm, left_dir, right_pwm, right_dir):
pwm.setDutycycle(self.PWMA, left_pwm * 100)
if left_dir == 1:
pwm.setLevel(self.AIN1, 0)
pwm.setLevel(self.AIN2, 1)
pwm.setLevel(self.AIN1, 1)
pwm.setLevel(self.AIN2, 0)
pwm.setDutycycle(self.PWMB, right_pwm * 100)
if right_dir == 1:
pwm.setLevel(self.BIN1, 0)
pwm.setLevel(self.BIN2, 1)
pwm.setLevel(self.BIN1, 1)
pwm.setLevel(self.BIN2, 0)

def forward(self, seconds=0, speed=1.0):
self.set_motors(speed, 0, speed, 0)
if seconds > 0:

def stop(self):
self.set_motors(0, 0, 0, 0)

def reverse(self, seconds=0, speed=1.0):
self.set_motors(speed, 1, speed, 1)
if seconds > 0:

def left(self, seconds=0, speed=0.5):
self.set_motors(speed, 0, speed, 1)
if seconds > 0:

def right(self, seconds=0, speed=0.5):
self.set_motors(speed, 1, speed, 0)
if seconds > 0:

# m = MotorDriver()
# m.set_motors(1, 1, 0.25, 0)
# input(“stop”)
# m.stop()
# input(“forward”)
# m.forward(3, 0.5)
# input(“stop”)
# m.stop()
# input(“left”)
# m.left(5)
# input(“stop”)
# m.stop()

#A second version with pi robot avoiding
from gpiozero import DistanceSensor
from motor_driver_i2c import MotorDriver
import time, random

motors = MotorDriver()
rangefinder = DistanceSensor(echo=18, trigger=17)

def turn_randomly():
turn_time = random.randint(1, 3)
if random.randint(1, 2) == 1:

while True:
distance = rangefinder.distance * 100 # convert to cm
if distance < 20:
elif distance < 50:

L298N — H Bridge Motor Driver is an alternative