Virtual Maze Solver Robot

by Ashraf Minhaj in Circuits > Robots

5552 Views, 35 Favorites, 0 Comments

Virtual Maze Solver Robot

WhatsApp Image 2021-02-18 at 10.34.04 PM.jpeg

Autonomous cars are now the most talked topics. Hobbyists try to make them using raspberry pi and computer vision technology. That's an approach. Another but easier way of making autonomous cars are line follower, path follower, maze solver robot. Such robots follow a certain color line drawn in certain environment's floor. We can make them using camera or IR sensor. What if I say that I don't want any line to be drawn on the floor, I want it to run on invisible line. This is what I did here actually. This Virtual Maze Solver/Path follower robot follows a path from a remote PC. So the robot doesn't have any sensors, it just gets coordinates from the PC - where another software robot tries to solve puzzle - and the hardware robot/car moves the way the software robot car moves. Watch the video for better understanding. Let me share now how I made this.

Parts You'll Need

IMG_20210214_150818.jpg
Arduino nano.jpg
IMG_20210214_150257.jpg
IMG_20210214_150128.jpg
IMG_20210214_150322.jpg
IMG_20210214_150217.jpg
IMG_20210214_151431.jpg

Hardware -

Electronics -

  1. Arduino Nano (Any board will do, but my PCB supports this) - 1x
  2. L298n Motor Driver module (for motor control operation) - 1x
  3. Motors - 4x
  4. Wheels (Compatible with motors) - 4x
  5. HC05 Bluetooth module (to send/receive data) - 1x
  6. Multi-functional robot PCB that I made (click here to see) - 1x
  7. Some male and female header pins
  8. soldering wire (to solder things on the PCB)

To Make the Body -

  1. PVC Sheets (You can use any boards or even papers, I love working with them)
  2. Hot Glue and Glue Gun

Software -

  1. Arduino.ide
  2. Python3 (Don't worry, I'll guide on how to install that)

That's it. Now let's see how everything will work.

Principle (How Everything Will Work)

track1.png

Simple, the robot will a Bluetooth controlled robot car. A python code will load a map/maze on computer and try to solve it. The hardware robot will get data from Python program using Bluetooth and move accordingly.

The python program will find path by comparing color value. Our map will consist white path. As long as there is a white pixel, the software car will go forward, so will the hardware robot.
Now let's make it.

Making Robot Chassis

IMG_20210214_223911.jpg
IMG_20210214_204712.jpg
IMG_20210214_204755.jpg
IMG_20210214_203310.jpg
IMG_20210214_205601.jpg
IMG_20210214_212843.jpg
IMG_20210214_222645.jpg

I took some two PVC sheets and cut them according to my need. It's your choice how you want to make it. After cutting the boards/sheets I placed the motors, connected them with proper wires. Both motors of same side acts as one motor, so they are connected together. In image6 I used some female-to-female jumper wires to connect motor control pins to the PCB. After that I added two blue PVC pieces to decorate the body and connected the wheels.

Circuit Diagram and PCB

Schematic_try2_2020-11-15_05-56-45.png
IMG_20210214_150217.jpg
PCB.jpg
IMG_20210214_213552.jpg
IMG_20210215_123827.jpg
IMG_20210214_223043.jpg

I designed the circuit using EasyEDA. It's simple enough, I left all the analog pins except A4, A5 (those are for I2C communication) and added a SD card reader, bluetooth module and place for Arduino nano. The bluetooth module is separted by jumper (while uploading data, we need to disconnect that). We don't need resistors as Arduino will only receive data, it won't write.

After that I printed the PCB from PCBWay.com. I find their service very impressive. As they offer quality product in less amount of money, I prefer using their service for my PCB's. I went to pcb quick order and uploaded the gerber file. Everything was done automatically by the site. And after my PCB was inspected by their engineers, I paid and got them within 3 days to Bangladesh from China. The quality is amazing, solder mask, lines, glassy look amazes me as always.

Get the PCB from here.

Connections:

I connected

  • Left motors to D5, D6
  • Right motors to D3, D4

The Bluetooth module is connected on the dedicated port but to be precise

  • VCC to 5v
  • Gnd to gnd
  • tx to Arduino Rx
  • Rx to Arduino Tx

What is your sending, is receiving on my end. So Arduino's receiving pin (Rx) is connected to Bluetooth modules sending pin (Tx).

After that powered the PCB from motor driver module. I always like to use a 7.4V power source for my robotics projects. Two lipo batteries will do the job. 3.7+3.7=7.4V, which is ideal for such projects.

So now our bluetooth robot is ready. Next step is programming it.

Programming1: Arduino Code

Now it's time to upload the program to the robot. As bluetooth module is connected on hardware serial, I unplugged the jumper before uploading the code.

First I defined in which pin the motors are connected -

 // Declare motor pins
 // motors of same side work as one
 // so we can consider both as one.
int rightMotor1 = 2;                // right side
int rightMotor2 = 3;
int leftMotor1 = 5;                 // left side
int leftMotor2 = 6;

Then I declared the motor pins as output in setup() function -

  // Set pin modes
  pinMode(rightMotor1, OUTPUT);
  pinMode(rightMotor2, OUTPUT);
  pinMode(leftMotor1, OUTPUT);
  pinMode(leftMotor2, OUTPUT);

Then I initialized serial communication to receive data from Bluetooth module -

  // Initialize serial communication
  Serial.begin(9600);

It checks for byte data from serial port on which the bluetooth module is connected to.

// Variable to store received data
byte command;
// Get command data from bluetooth serial port
  command = Serial.read();

If it receives -

  • 'f' goes forward
  • 'b' for backward
  • l' for left and
  • 'r' for right motion

For each motors there's two pins. If we need to run them to a direction we need to make a pin HIGH and other one LOW. If both of them are HIGH or LOW at the same time the motors won't spin. See this example to move the car forward -

if (command == 'f'){
    // indicates forward motion
    digitalWrite(rightMotor1, HIGH);
    digitalWrite(rightMotor2, LOW);
    digitalWrite(leftMotor1, HIGH);
    digitalWrite(leftMotor2, LOW);

With this combination we can make the robot to work.

Download the code from github or copy from below. I prefer downloading to avoid errors.

/* ** Virtual Path Following Robot *
 *  Robot Actuator's program
 *  
 *  This robot takes commands from a python program
 *  and follows those commands. This robot demonstrates
 *  virtual path following robots and it's scopes.
 *  
 *  *********** License: GPL3+  *************
 *  You should receive a copy of the license
 *  with this program.
 *  
 *  (c) author: ashraf minhaj
 *      mail  : ashraf_minhaj@yahoo.com
 *      
 *  Tutorial for this project:
 *       http://youtube.com/fusebatti

 *       http://youtube.com/fusebatti

 *      
 *  written on 15th Feb 2021
 */

 // Declare motor pins
 // motors of same side work as one
 // so we can consider both as one.
int rightMotor1 = 2;                // right side
int rightMotor2 = 3;
int leftMotor1 = 5;                 // left side
int leftMotor2 = 6;

// Variable to store received data
byte command;

void setup() {
  // Set pin modes
  pinMode(rightMotor1, OUTPUT);
  pinMode(rightMotor2, OUTPUT);
  pinMode(leftMotor1, OUTPUT);
  pinMode(leftMotor2, OUTPUT);

  // Initialize serial communication
  // at 9600 buad rate
  // sender/python code will also use
  // the same buad
  Serial.begin(9600);
}

void loop() {
  // Get command data from bluetooth serial port
  command = Serial.read();

  // Decide which way to go based on received data
  if (command == 'f'){
    // indicates forward motion
    digitalWrite(rightMotor1, HIGH);
    digitalWrite(rightMotor2, LOW);
    digitalWrite(leftMotor1, HIGH);
    digitalWrite(leftMotor2, LOW);
  }

  if (command == 'b'){
    // Backward motion
    digitalWrite(rightMotor1, LOW);
    digitalWrite(rightMotor2, HIGH);
    digitalWrite(leftMotor1, LOW);
    digitalWrite(leftMotor2, HIGH);
  }

  if (command == 'r'){
    // Right turn
    digitalWrite(rightMotor1, LOW);
    digitalWrite(rightMotor2, HIGH);
    digitalWrite(leftMotor1, HIGH);
    digitalWrite(leftMotor2, LOW);
  }

  if (command == 'l'){
    // Left turn
    digitalWrite(rightMotor1, HIGH);
    digitalWrite(rightMotor2, LOW);
    digitalWrite(leftMotor1, LOW);
    digitalWrite(leftMotor2, HIGH);
  }

  if (command == 's'){
    // Stops the robot/car
    digitalWrite(rightMotor1, LOW);
    digitalWrite(rightMotor2, LOW);
    digitalWrite(leftMotor1, LOW);
    digitalWrite(leftMotor2, LOW);
  }
}

Now upload the code using Arduino.ide and proceed to next step.

Programmin2: Python Code

track1.png
car.png

I suppose you have python installed on your computer. If you don't, go to python.org/downloads and install latest stable version of python. I use Python3.7.1 as I find it most stable. While downloading download executable installer, and double click it to install, then click on the box that says 'Add python to environment variable path', else you'll be in a disaster.

Anyway, let's now talk about the python program.

I needed two libraries for this program, pygame and pySerial. I installed them from my command prompt like this -

$ pip install pygame
$ pip install pySerial

The two images you are seeing at the top are the maze and the software car. The python program reads them -

bg  = pygame.image.load("track1.png")
car = pygame.image.load("car.png")

To send data from the PC to Arduino bluetooth I first connected the bluetooth module to my pc. Steps are -

  • Turn on Bluetooth
  • Go to control panel > device manager
  • Search for new devices
  • Add device (HC05) with password [default password is '0000' or '1234']

That's it. Then clicked on device properties to get the port no. of the HC05, in py PC it was in 'COM8'. So the python connects like this -

PORT = "COM8"
BUADRATE = 9600
robot = serial.Serial(PORT, BUADRATE)  # connect robot

For the robot to check for surroundings first I found the center of the car and then checked it surrounding -

# find the center of the car and draw a point on that
center_x, center_y = (int(car_x + 40 /2), int(car_y + 40 / 2))

The rest of the code is checking surroundings and turning or moving the car. If it goes forward or any direction it sends that data to Arduino via serial port like this (byte data) -

# start the robot
robot.write(b'f')
# turn left
robot.write(b'l')

Now download the full code from github or copy from below -

"""
    ** Virtual Path Follower Robot **

    License: GPL3
    You should receive a copy of license with this program.

    (c) author: ashraf minhaj
        mail  : ashraf_minhaj@yahoo.com
    
    Written on 15th Feb 2021
"""

""" install - 
$ pip install pygame
$ pip install pySerial
"""

# import library
import pygame
import serial
from time import sleep

# robot port and buadrate
# change these according to your need
PORT = "COM8"
BUADRATE = 9600

# initialize things
pygame.init()
robot = serial.Serial(PORT, BUADRATE)  # connect robot

# create window with size (our image size)
window = pygame.display.set_mode((700,400))  # track 1
#window = pygame.display.set_mode((1155,399))   # track 2

# load image file
bg  = pygame.image.load("track1.png")
#bg  = pygame.image.load("track2.png")
car = pygame.image.load("car.png")
car = pygame.transform.scale(car, (40, 40)) # resize car image

""" main loop varibales and things """
# set up timer clock 
clock = pygame.time.Clock()

# initial x y axis position of the car
car_x = 30   
car_y = 260  

JUMP_VALUE = 25     # turning point value
direction = 'y_up'  # cars current direction
run = 1

# start the robot
robot.write(b'f')
DELAY = .400
# main loop
while run:
    clock.tick(30)         # update the window/run loop by this speed
    #check for events
    for event in pygame.event.get():
        # quit button clicked
        if event.type == pygame.QUIT:
            run = 0

    # position images
    window.blit(bg, (0, 0))          # load the track image
    window.blit(car, (car_x, car_y)) # the car image

    # record last x, y pos of car
    last_x, last_y = car_x, car_y
    
    # find the center of the car and draw a point on that
    center_x, center_y = (int(car_x + 40 /2), int(car_y + 40 / 2))
    pygame.draw.circle(window, (0,255,255), (center_x, center_y), 5, 5)

    # check surrounding (4 direction data)
    # the calibration value is the pixel from car's sensor/mid point
    # so it checks for road info 30 pixels far from the sensor.
    # 255 means we have a clear white road
    cal_value = 30              # calibrate this to get good data
    y_up      = window.get_at((center_x, center_y - cal_value))[0]
    y_down    = window.get_at((center_x, center_y + cal_value))[0]
    x_right   = window.get_at((center_x + cal_value, center_y))[0]
    x_left    = window.get_at((center_x - cal_value, center_y))[0]
    #print("y_up   ", y_up)
    #print("y_down ", y_down)
    #print("x_right", x_right)
    #print("x_left ", x_left)
    #print("-----------")

    # determine which way to go
    # go up
    if y_up == 255 and direction == 'y_up' and x_left != 255 and x_right != 255:
        # move up
        car_y -= 2  # decrease pixel and move the car on y axis
        
    # make the turn
    if y_up == 255 and direction == 'y_up' and x_left != 255 and x_right == 255:
        # make a right turn
        direction = 'x_right'
        car_y -= JUMP_VALUE
        car_x += JUMP_VALUE
        car = pygame.transform.rotate(car, -90)
        window.blit(car, (car_x, car_y))
        print('Turn Right')
        robot.write(b'r')
        sleep(DELAY)
        robot.write(b'f')

    # go x right
    if y_up != 255 and direction == 'x_right' and y_down != 255 and x_right == 255:
        car_x += 2

    if y_down == 255 and direction == 'x_right' and x_left == 255 and x_right == 255:
        # make a turn from x_right
        car = pygame.transform.rotate(car, -90)
        direction = 'y_down'
        car_y += JUMP_VALUE + 5
        car_x += JUMP_VALUE
        window.blit(car, (car_x, car_y))
        print('Turn Right')
        robot.write(b'r')
        sleep(DELAY)
        robot.write(b'f')

    # go y down
    if y_down == 255 and direction == 'y_down' and x_left != 255 and x_right != 255:
        # move down
        car_y += 2

    # left turn
    if y_down == 255 and direction == 'y_down' and x_left != 255 and x_right == 255:
        # turn from y_down
        car = pygame.transform.rotate(car, 90)
        direction = 'x_right'
        car_y += JUMP_VALUE
        car_x += JUMP_VALUE
        print('Turn left')
        robot.write(b'l')
        sleep(DELAY)
        robot.write(b'f')
    
    # turn to y up
    if y_up == 255 and direction == 'x_right' and x_left == 255 and x_right == 255:
        # turn from y_down
        car = pygame.transform.rotate(car, 90)
        direction = 'y_up'
        car_y -= JUMP_VALUE + 5
        car_x += JUMP_VALUE
        print('Turn left')
        robot.write(b'l')
        sleep(DELAY)
        robot.write(b'f')
    
    # if car is stopped
    if car_x == last_x and car_y == last_y:
        # stop the engine sound
        print("STOPPED")
        robot.write(b's')
        
    pygame.display.update()  # update the window

pygame.quit()      #close everything

And that's it.

Power Up and Let's Go

IMG_20210215_123801.jpg
IMG_20210215_123911.jpg

I powered the robot using two 18650 batteries. Then ran the Python program. How does it perform? You can see that in the video.

The best part of this robot is that you don't need to change robot's code time to time. You just need to change the python program accordingly. That's it.

Future Scope:

This robot can be used in industries with some sensors on board to determine errors or in case it slips out of path and also to avoid obstacles. The sky is the limit, your brain is the master.

Thank you.