Project showcase
Image transmit and Control by Smartphone 4WD Robot Car

Image transmit and Control by Smartphone 4WD Robot Car © LGPL

Image transmit and Control by Smartphone 4WD Robot Car over Bluetooth

  • 1,607 views
  • 0 comments
  • 11 respects

Components and supplies

About this project

This article will be devoted to the development of a 4WD Robot that has "vision" using a common and inexpensive camera ОV7670, which will transmit images from the camera to a smartphone (in real time) over Bluetooth. The robot will also be controlled over Bluetooth from a smartphone.

This article will not describe in detail the process of programming Arduino UNO (only a sketch will be posted). The programming process is described in detail in another article.

Needed components

Ordered in various online stores:

  • 4WD Robot platform;
  • L293D drivers (two pieces);
  • Bluetooth module HС-05;
  • Prototyping board (in the Arduino UNO format);
  • Arduino UNO board.

Everything else (in stock):

  • TFT shield;
  • Batteries;
  • Sockets;
  • Wires;
  • Connectors
  • etc.

Pre-Build Assembly 4WD Robot Platform

The first thing you need to do is build a 4WD Robot platform. The following is the assembly process as detailed as possible.

Prototype Motor Driver Board

Due to the fact that there were not many free pins on the Arduino UNO board (most pins are used for the TFT screen), it was decided to solder the L293D driver control circuit taking into account the available pins. This layout is installed between the Arduino UNO board and the TFT screen. The scheme is as follows:

Final Assembly of 4WD Robot Platform

Program in Arduino UNO shield TFT_shield_Robot.ino (+ ov7670_regs.h). The process is described in detail in the article.

Connect the OV7670 camera and the Bluetooth module HC-05 to the TFT shield. Connect together the TFT shield, the breadboard of the motor driver, Arduino UNO. Install the assembly "TFT shield / Motor driver / Arduino UNO", 7.2 V battery on the chassis. Connect wires from 4 motors to the driver board (I experimentally connected one motor each :-)).

Demonstration

To work with 4WD Robot, you need to install the MyRobot.apk application on your phone, turn on Bluetooth, launch the application, select the identifier of the module detected by Bluetooth. In case of successful execution of all actions, the image of the Robot 4WD with the control buttons at the bottom of the screen should appear on the phone screen. Please note that the phone must be held upright. By clicking on the buttons you can make the 4WD Robot:

  • take a single photo,
  • start sequential image transfer,
  • stop image transfer,
  • turn on / off the backlight,
  • turn left,
  • move forward,
  • move backward,
  • turn right.

For a visual demonstration, I am attaching a video of working with 4WD Robot. If you liked (or did not like) my project, please evaluate my work. Thanks for your attention!

Code

TFT_shield_Robot.inoC/C++
/*
 * Arduino TFT_shield_v1.00 ROBOT example
 * 
 * Authors: Kamil Lee, Iron Khan (2018)
 * 
 * Comments:
 * 
 * 
 */

#include <YATFT.h> // Hardware-specific library
#include <util/yasdc.h>
#include <util/yacam.h>
#include <util/yacodec.h>
#include "ov7670_regs.h"

int mode = 0;
uint8_t start_capt = 0;
int k;

YATFT tft(0);
CAM   cam;
INTRFC ifc;
SDC   sdc;
CODEC codec;

/* 
   If using the shield, all control and data lines are fixed, and
   a simpler declaration can optionally be used:
*/
uint16_t  err;
bool      f_light = false;

#define RIGHT_TRACK_FORWARD 13
#define RIGHT_TRACK_ON       2 //12
#define LEFT_TRACK_BACK     11
#define LEFT_TRACK_ON        2

//#define IMG_VGA
#define IMG_QVGA

#ifdef IMG_VGA
#define IMG_SizeX    640
#define IMG_SizeY    480
#else // IMG_QVGA
#define IMG_SizeX    320
#define IMG_SizeY    240
#endif

/*********************************************************************************
*
*********************************************************************************/
void setup()
{
    uint8_t state;

    // initialize the serial port
    Serial.begin(115200);
    Serial.println(F("TFT_shield_Robot example!"));

    pinMode(    LEFT_TRACK_BACK, OUTPUT);
    pinMode(RIGHT_TRACK_FORWARD, OUTPUT);
    pinMode(      LEFT_TRACK_ON, OUTPUT);
    pinMode(     RIGHT_TRACK_ON, OUTPUT);

    digitalWrite(    LEFT_TRACK_BACK, LOW);
    digitalWrite(RIGHT_TRACK_FORWARD, LOW);
    digitalWrite(      LEFT_TRACK_ON, LOW);
    digitalWrite(     RIGHT_TRACK_ON, LOW);

    // initialize the display
    tft.begin();

    tft.SetColor(BLACK);
    tft.ClearDevice();

    delay(100);

    err = cam.CamInit(&OV7670_QVGA[0][0]);
    cam.CamVideoPreview(0, 0, 1, true);

    delay(1000);

    tft.SetColor(BLACK);
    tft.ClearDevice();

    codec.JPEGInit();
    codec.JPEGSetRegs(IMG_SizeX, IMG_SizeY);

    pinMode(    LEFT_TRACK_BACK, OUTPUT);
    pinMode(RIGHT_TRACK_FORWARD, OUTPUT);
    pinMode(      LEFT_TRACK_ON, OUTPUT);
    pinMode(     RIGHT_TRACK_ON, OUTPUT);
}


/*********************************************************************************
*
*********************************************************************************/
void loop()
{
    // put your main code here, to run repeatedly:
    uint8_t temp = 0xff, temp_last = 0;
    bool is_header = false;
    if (Serial.available())
    {
        temp = Serial.read();

        SerialRoutine(temp);
        temp = 0xff;
    }
    if (mode == 1)
    {
        if (start_capt == 1)
        {
            start_capt = 0;
        }
        Serial.println(F("ACK CMD CAM Capture Done."));

        uint8_t temp, temp_last;
        uint32_t length = 0;

        codec.JPEGSetRegs(IMG_SizeX, IMG_SizeY);
        length = codec.JPEGStart();
        uint32_t en_jpeg_address = ifc.rdReg32(0x414)<<2;
        k = 0;

        if (length >= 0x5FFFF) 
        {
            Serial.println(F("ACK CMD Over size."));
            return;
        }
        if (length == 0 ) //0 kb
        {
            Serial.println(F("ACK CMD Size is 0."));
            return;
        }
        temp = ifc.GetMem(en_jpeg_address+k);
        k++;
        length --;
        while ( length-- )
        {
            temp_last = temp;
            temp = ifc.GetMem(en_jpeg_address+k);
            k++;
            if (is_header == true)
            {
                Serial.write(temp);
            }
            else if ((temp == 0xD8) & (temp_last == 0xFF))
            {
                is_header = true;
                Serial.println(F("ACK IMG"));
                Serial.write(temp_last);
                Serial.write(temp);
            }
            if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
            {
                break;
            }
        }
        is_header = false;

        start_capt = 0;
        mode = 0;
    
        Serial.println("");
        Serial.println(F("ACK END"));
    }
    else if (mode == 2)
    {
        while (1)
        {
            temp = Serial.read();
            if (temp == 0x21)
            {
                start_capt = 0;
                mode = 0;
                Serial.println(F("ACK CMD CAM stop video streaming."));
                break;
            }
            if (start_capt == 2)
            {
                //Start capture
                start_capt = 0;
            }
            SerialRoutine2 (temp);
            uint32_t length = 0;

            codec.JPEGSetRegs(IMG_SizeX, IMG_SizeY);
            length = codec.JPEGStart();
            uint32_t en_jpeg_address = ifc.rdReg32(0x414)<<2;
            k = 0;
                
            if ((length >= 0x5FFFF) | (length == 0))
            {
                start_capt = 2;
                continue;
            }
            temp = ifc.GetMem(en_jpeg_address+k);
            k++;
            length --;
            while ( length-- )
            {
                temp_last = temp;
                temp = ifc.GetMem(en_jpeg_address+k);
                k++;
                if (is_header == true)
                {
                    Serial.write(temp);
                }
                else if ((temp == 0xD8) & (temp_last == 0xFF))
                {
                    is_header = true;
                    Serial.println(F("ACK IMG"));
                    Serial.write(temp_last);
                    Serial.write(temp);
                }
                if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
                {
                    break;
                }
            }
            start_capt = 2;
            is_header = false;
        }
    }
    else if (mode == 3)
    {
    }
}

void SerialRoutine (uint8_t temp)
{
    switch (temp)
    {
        case 0x10:
             mode = 1;
             start_capt = 1;
             Serial.println(F("ACK CMD CAM start single shoot."));
             break;
        case 0x11: 
             break;
        case 0x20:
             mode = 2;
             start_capt = 2;
             Serial.println(F("ACK CMD CAM start video streaming."));
             break;
        case 0x21:
             start_capt = 0;
             mode = 0;
             Serial.println(F("ACK CMD CAM stop video streaming."));
             break;
        case 0x31:
             break;
        case 'F':    // Forward
             Forward();
             break;
        case 'B':    // Back
             Back();
             break;
        case 'L':    // Left
             Left();
             break;
        case 'R':    // Right
             Right();
             break;
        case 'S':    // Stop
             Stop();
             break;
        case 'I':    // Illuminate
             if (f_light == true)
             {
                 tft.gpio_bl(0); // Backlight Off
                 f_light = false;
             } else {
                 tft.gpio_bl(1); // Backlight On
                 f_light = true;
             }
             break;
        default:
//             Serial.println(temp, HEX);
             break;
    }
}

void SerialRoutine2 (uint8_t temp)
{
    switch (temp)
    {
        case 'F':    // Forward
             digitalWrite( LEFT_TRACK_BACK,     LOW);
             digitalWrite(RIGHT_TRACK_FORWARD, HIGH);
             digitalWrite(      LEFT_TRACK_ON, HIGH);
             digitalWrite(     RIGHT_TRACK_ON, HIGH);
             break;
        case 'B':    // Back
             digitalWrite( LEFT_TRACK_BACK,    HIGH);
             digitalWrite(RIGHT_TRACK_FORWARD,  LOW);
             digitalWrite(      LEFT_TRACK_ON, HIGH);
             digitalWrite(     RIGHT_TRACK_ON, HIGH);
             break;
        case 'L':    // Left
             digitalWrite( LEFT_TRACK_BACK,    HIGH);
             digitalWrite(RIGHT_TRACK_FORWARD, HIGH);
             digitalWrite(      LEFT_TRACK_ON, HIGH);
             digitalWrite(     RIGHT_TRACK_ON, HIGH);
             delay(200);
             digitalWrite(     RIGHT_TRACK_ON,  LOW);
             digitalWrite(      LEFT_TRACK_ON,  LOW);
             break;
        case 'R':    // Right
             digitalWrite( LEFT_TRACK_BACK,     LOW);
             digitalWrite(RIGHT_TRACK_FORWARD,  LOW);
             digitalWrite(      LEFT_TRACK_ON, HIGH);
             digitalWrite(     RIGHT_TRACK_ON, HIGH);
             delay(200);
             digitalWrite(     RIGHT_TRACK_ON,  LOW);
             digitalWrite(      LEFT_TRACK_ON,  LOW);
             break;
        case 'S':    // Stop
             Stop();
             break;
        default:
             digitalWrite(     RIGHT_TRACK_ON,  LOW);
             digitalWrite(      LEFT_TRACK_ON,  LOW);
             break;
    }
}



void Forward (void)
{
    pinMode(    LEFT_TRACK_BACK, OUTPUT);
    pinMode(RIGHT_TRACK_FORWARD, OUTPUT);
    pinMode(      LEFT_TRACK_ON, OUTPUT);
    pinMode(     RIGHT_TRACK_ON, OUTPUT);

    digitalWrite( LEFT_TRACK_BACK,     LOW);
    digitalWrite(RIGHT_TRACK_FORWARD, HIGH);
    digitalWrite(      LEFT_TRACK_ON, HIGH);
    digitalWrite(     RIGHT_TRACK_ON, HIGH);
    delay(500);
    digitalWrite(     RIGHT_TRACK_ON,  LOW);
    digitalWrite(      LEFT_TRACK_ON,  LOW);
}

void Back (void)
{
    pinMode(    LEFT_TRACK_BACK, OUTPUT);
    pinMode(RIGHT_TRACK_FORWARD, OUTPUT);
    pinMode(      LEFT_TRACK_ON, OUTPUT);
    pinMode(     RIGHT_TRACK_ON, OUTPUT);

    digitalWrite( LEFT_TRACK_BACK,    HIGH);
    digitalWrite(RIGHT_TRACK_FORWARD,  LOW);
    digitalWrite(      LEFT_TRACK_ON, HIGH);
    digitalWrite(     RIGHT_TRACK_ON, HIGH);
    delay(500);
    digitalWrite(     RIGHT_TRACK_ON,  LOW);
    digitalWrite(      LEFT_TRACK_ON,  LOW);
}

void Left (void)
{
    pinMode(    LEFT_TRACK_BACK, OUTPUT);
    pinMode(RIGHT_TRACK_FORWARD, OUTPUT);
    pinMode(      LEFT_TRACK_ON, OUTPUT);
    pinMode(     RIGHT_TRACK_ON, OUTPUT);

    digitalWrite( LEFT_TRACK_BACK,    HIGH);
    digitalWrite(RIGHT_TRACK_FORWARD, HIGH);
    digitalWrite(      LEFT_TRACK_ON, HIGH);
    digitalWrite(     RIGHT_TRACK_ON, HIGH);
    delay(500);
    digitalWrite(     RIGHT_TRACK_ON,  LOW);
    digitalWrite(      LEFT_TRACK_ON,  LOW);
}

void Right (void)
{
    pinMode(    LEFT_TRACK_BACK, OUTPUT);
    pinMode(RIGHT_TRACK_FORWARD, OUTPUT);
    pinMode(      LEFT_TRACK_ON, OUTPUT);
    pinMode(     RIGHT_TRACK_ON, OUTPUT);

    digitalWrite( LEFT_TRACK_BACK,     LOW);
    digitalWrite(RIGHT_TRACK_FORWARD,  LOW);
    digitalWrite(      LEFT_TRACK_ON, HIGH);
    digitalWrite(     RIGHT_TRACK_ON, HIGH);
    delay(500);
    digitalWrite(     RIGHT_TRACK_ON,  LOW);
    digitalWrite(      LEFT_TRACK_ON,  LOW);
}

void Stop (void)
{
    digitalWrite(     RIGHT_TRACK_ON,  LOW);
    digitalWrite(      LEFT_TRACK_ON,  LOW);
}
ov7670_regs.hC/C++
#ifndef OV7670_REGS_H
#define OV7670_REGS_H

const uint8_t OV7670_VGA[][2] PROGMEM =
{
    {   1, 0x42}, // Size of byte, Address (ID) 
    { 640/16,  480/16}, // Size X, Size Y
    {0b01000010, 0b00000100}, // Reset_Enable_N, 7|6|5|4|3|Vsync Invert|Hsync Invert|0

    {0x3a, 0x0C},
    {0x40, 0xC0},
    {0x12, 0x00}, // VGA
    {0x0c, 0x00},
    {0x3e, 0x00},
    {0x70, 0x3A},
    {0x71, 0x35},
    {0x72, 0x11},
    {0x73, 0xF0},
    {0xa2, 0x02},
    {0x11, 0x80},
    {0x7a, 0x18},
    {0x7b, 0x02},
    {0x7c, 0x07},
    {0x7d, 0x1F},
    {0x7e, 0x49},
    {0x7f, 0x5A},
    {0x80, 0x6A},
    {0x81, 0x79},
    {0x82, 0x87},
    {0x83, 0x94},
    {0x84, 0x9F},
    {0x85, 0xAF},
    {0x86, 0xBB},
    {0x87, 0xCF},
    {0x88, 0xEE},
    {0x89, 0xEE},
    {0x13, 0xE0},
    {0x00, 0x00},
    {0x10, 0x00},
    {0x0d, 0x00},
    {0x24, 0x98},
    {0x25, 0x63},
    {0x26, 0xD3},
    {0x2a, 0x00},
    {0x2b, 0x00},
    {0x2d, 0x00},
    {0x13, 0xe5},
    {0x13, 0xe7},
    {0x1e, 0x30},
    {0x74, 0x60},
    {0x01, 0x80},
    {0x02, 0x80},
    {0x15, 0x10},
    {0x4f, 0x40},
    {0x50, 0x34},
    {0x51, 0x0C},
    {0x52, 0x17},
    {0x53, 0x29},
    {0x54, 0x40},
    {0x57, 0x80},
    {0x58, 0x1e},
    {0x41, 0x10},
    {0x75, 0x60},
    {0x76, 0x50},
    {0x77, 0x48},
    {0x3d, 0x92},
    {0x3b, 0x00},
    {0x04, 0x00},
    {0xff, 0xff},
};        

const uint8_t OV7670_QVGA[][2] PROGMEM =
{
    {   1, 0x42}, // Size of byte, Address (ID) 
    { 320/16,  240/16}, // Size X, Size Y
    {0b01000010, 0b00000100}, // Reset_Enable_N, 7|6|5|4|3|Vsync Invert|Hsync Invert|0

    {0x3a, 0x0C},
    {0x40, 0xC0},
    {0x12, 0x10}, // QVGA
    {0x0c, 0x00},
    {0x3e, 0x00},
    {0x70, 0x3A},
    {0x71, 0x35},
    {0x72, 0x11},
    {0x73, 0xF0},
    {0xa2, 0x02},
    {0x11, 0x80},
    {0x7a, 0x18},
    {0x7b, 0x02},
    {0x7c, 0x07},
    {0x7d, 0x1F},
    {0x7e, 0x49},
    {0x7f, 0x5A},
    {0x80, 0x6A},
    {0x81, 0x79},
    {0x82, 0x87},
    {0x83, 0x94},
    {0x84, 0x9F},
    {0x85, 0xAF},
    {0x86, 0xBB},
    {0x87, 0xCF},
    {0x88, 0xEE},
    {0x89, 0xEE},
    {0x13, 0xE0},
    {0x00, 0x00},
    {0x10, 0x00},
    {0x0d, 0x00},
    {0x24, 0x98},
    {0x25, 0x63},
    {0x26, 0xD3},
    {0x2a, 0x00},
    {0x2b, 0x00},
    {0x2d, 0x00},
    {0x13, 0xe5},
    {0x13, 0xe7},
    {0x1e, 0x30},
    {0x74, 0x60},
    {0x01, 0x80},
    {0x02, 0x80},
    {0x15, 0x10},
    {0x4f, 0x40},
    {0x50, 0x34},
    {0x51, 0x0C},
    {0x52, 0x17},
    {0x53, 0x29},
    {0x54, 0x40},
    {0x57, 0x80},
    {0x58, 0x1e},
    {0x41, 0x10},
    {0x75, 0x60},
    {0x76, 0x50},
    {0x77, 0x48},
    {0x3d, 0x92},
    {0x3b, 0x00},
    {0x04, 0x00},
    {0xff, 0xff},
};        

#endif

Schematics

Motor driver scheme

Comments

Similar projects you might like

Smartphone Controlled Arduino 4WD Robot Car

Project in progress by Andriy Baranov

  • 91,554 views
  • 58 comments
  • 169 respects

4WD Smart Robot Car

Project tutorial by TheTNR

  • 8,280 views
  • 3 comments
  • 20 respects

Jrobot - Android and Arduino-Based Global Control Robot Car

Project showcase by joechen

  • 7,633 views
  • 4 comments
  • 27 respects

Control MeArm Robot With MKR1000 And Your Smartphone

Project in progress by Lightrider

  • 682 views
  • 1 comment
  • 6 respects

Servo Control with TV Remote Control

Project showcase by eldo85

  • 13,030 views
  • 6 comments
  • 35 respects

Control an LED with the Remote Control

Project showcase by Nicholas_N

  • 12,307 views
  • 7 comments
  • 18 respects
Add projectSign up / Login