4180 Wireless Robot Project

Project by

Evan Davies

Overview

This is my documentation for ECE 4180 Lab 4. For this project, I worked on creating a Remote controlled robot using an Mbed and a wireless transceiver. The Sparkfun Shadow Chassis was used as the robot platform with Toshiba’s TB6612FNG dual motor driver used to control the motors and an ESP8266 WiFi Module used as the wireless transceiver. /media/uploads/edavies/img_1726.jpg

Parts List

  • 1 Mbed Lpc 1768
  • 1 ESP8266 WiFi Module
  • 1 TB6612FNG dual motor driver
  • 1 Sparkfun Shadow Chassis
  • 1 4xAA in series for 6V power supply
  • 2 330nF decoupling capacitors

Pin Diagram

The mbed and the motors were powered by 4AA batteries in series going to Vin on the mbed and VMOT on the H-bridge.

/media/uploads/edavies/screen_shot_2015-10-21_at_1.41.10_am.png

Wiring table for ESP8266

ESP8266Mbed
RXTX-p28
VCC3.3V
GPIO 0NC
RESETp26
CH_PD3.3V
GPIO2NC
TXRX-p27
GNDGND

A 330uf capacitor was added from Vout to gnd to stabilize the voltage as the wifi module tends to draw too much power for the mbed.

/media/uploads/edavies/screen_shot_2015-10-21_at_1.47.41_am.png

Wiring table for H-bridge

ESP8266Mbed
GNDGND
VCC3.3V
A01Left Motor +
A02Left Motor -
B02Right Motor -
B02Right Motor +
VMOT5V
GNDGND
PWMAp22
AIN2p6
AIN1p5
STBY3.3V
BIN1p8
BIN2p7
PWMBp21
GNDGND

Wifi module

The wifi module was configued using the following guide. https://developer.mbed.org/users/4180_1/notebook/using-the-esp8266-with-the-mbed-lpc1768/ The wif module draws around 200mA, which is near the max power that the mbed can provide. To avoid the mbed reseting due to low power when only connected by USB, decoupling capacitor can use used across the 3.3V line. My module still drew too much power even with the capacitor, so I always made sure mine was hooked up to an external power source.

H-bridge

The H-bridge was configured so that the left motor was the A output and the Right motor was the B output of the H-bridge. The H-bridge was supplied 3.3V for logic from the mbed and 6V to drive the motors using 4xAA connected in series. A decoupling cap was applied across the 6V supply to account for high loads. To control the H-bridge the Motordriver Library was used. This allowed for the setting of speed and controlling how hard the motors broke.

Video

Code

The program can be found in the following repository.

Import programWireless_Robot

Evan Davies ECE 4180 Lab4: Wifi equipped Robot

// Evan Davies ECE 4180 Lab 4 Wireless Robot

#include "mbed.h"
#include "motordriver.h"


Serial pc(USBTX, USBRX);

// setup for wifi module
Serial esp(p28, p27); // tx, rx
DigitalOut  reset(p26);

//Setup motors
Motor A(p22, p6, p5, 1); // pwm, fwd, rev, can brake 
Motor B(p21, p7, p8, 1); // pwm, fwd, rev, can brake

// Standard Mbed LED definitions
DigitalOut  led1(LED1);      // (PTB18)
DigitalOut  led2(LED2);    // (PTB19)
DigitalOut  led3(LED3);     // (PTD1)
DigitalOut  led4(LED4);
int LeftWheelDir;
int LeftWheelSpeed;
int RightWheelSpeed;
int RightWheelDir; 


Timer t1;
Timer t2;

struct tm t;

int bufflen, DataRX, count, getcount, replycount, servreq, timeout;
int bufl, ipdLen, linkID, weberror, webcounter;
float temperature, AdcIn, Ht;
float R1=100000, R2=10000; // resistor values to give a 10:1 reduction of measured AnalogIn voltage
char Vcc[10];
char Temp[10];
char temp[10];
char webcount[8];
char lasthit[30];
char timebuf[30];
char type[16];
char type1[16];
char channel[2];
char cmdbuff[32];
char replybuff[1024];
char webdata[1024]; // This may need to be bigger depending on WEB browser used
char webbuff[4096];     // Currently using 1986 characters, Increase this if more web page data added

void SendCMD(),getreply(),ReadWebData(),startserver(),sendpage(),SendWEB(),sendcheck();
void gettime(),setRTC();

// manual set RTC values
int minute      =00;    // 0-59
int hour        =12;    // 2-23
int dayofmonth  =26;    // 1-31
int month       =8;     // 1-12
int year        =15;    // last 2 digits

int port        =80;  // set server port
int SERVtimeout =5;    // set server timeout in seconds in case link breaks.

// Serial Interrupt read ESP data
void callback()
{
    //RightWheelSpeed=1;
    while (esp.readable()) {
        webbuff[count] = esp.getc();
        count++;
    }
    if(strlen(webbuff)>bufflen) {
        DataRX=1;
        //RightWheelSpeed=0;
    }
}

int main()
{
    A.speed(0);
    B.speed(0);
    reset=0;
    pc.baud(115200);

    pc.printf("\f\n\r------------ ESP8266 Hardware Reset --------------\n\r");
    wait(0.5);
    reset=1;
    LeftWheelSpeed=0,LeftWheelDir=0,RightWheelSpeed=0, RightWheelDir=0;
    timeout=6000;
    getcount=500;
    getreply();
    esp.baud(115200);   // ESP8266 baudrate. Maximum on KLxx' is 115200, 230400 works on K20 and K22F
    if (time(NULL) < 1420070400) {
        setRTC();
    }
 
    startserver();

    while(1) {
        if(DataRX==1) {
            ReadWebData();
            if (servreq == 1 && weberror == 0) {
                sendpage();
            }
            esp.attach(&callback);
            pc.printf(" IPD Data:\r\n\n Link ID = %d,\r\n IPD Header Length = %d \r\n IPD Type = %s\r\n", linkID, ipdLen, type);
            pc.printf("\n\n  HTTP Packet: \n\n%s\n", webdata);
            pc.printf("  Web Characters sent : %d\n\n", bufl);
            pc.printf("  -------------------------------------\n\n");
            strcpy(lasthit, timebuf);
            servreq=0;
        }
    }
}
// Static WEB page
void sendpage()
{

    gettime();

// WEB page data
    strcpy(webbuff, "<!DOCTYPE html>");
    strcat(webbuff, "<html><head><title>4180 Wireless Robot</title></head>");
    strcat(webbuff, "<body>");
    strcat(webbuff, "<div style=\"text-align:center; background-color:#F4F4F4; color:#00AEDB;\"><h1>4180 Wireless Robot</h1>");
    strcat(webbuff, "Hit Count - ");
    strcat(webbuff, webcount);
    strcat(webbuff, "<br>Last Hit - ");
    strcat(webbuff, lasthit);
    strcat(webbuff, "</div><br /><hr>");
    strcat(webbuff, "<h3>Mbed RTC Time -&nbsp&nbsp");
    strcat(webbuff, timebuf);
    strcat(webbuff, "</h3>\r\n");
    strcat(webbuff, "<p><form method=\"POST\"><strong>");

//    strcat(webbuff, "<p><form method=\"POST\"><strong> Analog 1:&nbsp&nbsp<input type=\"text\" size=6 value=\"");
//    strcat(webbuff, Temp);
//    strcat(webbuff, "\"> </sup>V <form method=\"POST\"> <strong> &nbsp&nbspAnalog 2:&nbsp&nbsp<input type=\"text\" size=4 value=\"");
//    strcat(webbuff, Vcc);
//    strcat(webbuff, "\"> </sup>V");
    if(LeftWheelSpeed==0) {
        strcat(webbuff, "<p><input type=\"radio\" name=\"LeftWheelSpeed\" value=\"1\" >  Left Wheel on");
        strcat(webbuff, "<br><input type=\"radio\" name=\"LeftWheelSpeed\" value=\"0\" checked>  Left Wheel off");
    } else {
        strcat(webbuff, "<p><input type=\"radio\" name=\"LeftWheelSpeed\" value=\"1\" checked>  Left Wheel on");
        strcat(webbuff, "<br><input type=\"radio\" name=\"LeftWheelSpeed\" value=\"0\" >  Left Wheel off");
    }
    
    if(LeftWheelDir==0) {
        strcat(webbuff, "<p><input type=\"radio\" name=\"LeftWheelDir\" value=\"1\" >  Left Wheel Forward");
        strcat(webbuff, "<br><input type=\"radio\" name=\"LeftWheelDir\" value=\"0\" checked>  Left Wheel Reverse");
    } else {
        strcat(webbuff, "<p><input type=\"radio\" name=\"LeftWheelDir\" value=\"1\" checked>  Left Wheel Forward");
        strcat(webbuff, "<br><input type=\"radio\" name=\"LeftWheelDir\" value=\"0\" >  Left Wheel Reverse");
    }
    
        if(RightWheelSpeed==0) {
        strcat(webbuff, "<p><input type=\"radio\" name=\"RightWheelSpeed\" value=\"1\" >  Right Wheel on");
        strcat(webbuff, "<br><input type=\"radio\" name=\"RightWheelSpeed\" value=\"0\" checked>  Right Wheel off");
    } else {
        strcat(webbuff, "<p><input type=\"radio\" name=\"RightWheelSpeed\" value=\"1\" checked>  Right Wheel on");
        strcat(webbuff, "<br><input type=\"radio\" name=\"RightWheelSpeed\" value=\"0\" >  Right Wheel off");
    }
    
    if(RightWheelDir==0) {
        strcat(webbuff, "<p><input type=\"radio\" name=\"RightWheelDir\" value=\"1\" >  Right Wheel Forward");
        strcat(webbuff, "<br><input type=\"radio\" name=\"RightWheelDir\" value=\"0\" checked>  Right Wheel Reverse");
    } else {
        strcat(webbuff, "<p><input type=\"radio\" name=\"RightWheelDir\" value=\"1\" checked>  Right Wheel Forward");
        strcat(webbuff, "<br><input type=\"radio\" name=\"RightWheelDir\" value=\"0\" >  Right Wheel Reverse");
    }
    
    strcat(webbuff, "</strong><p><input type=\"submit\" value=\"send-refresh\" style=\"background: #3498db;");
    strcat(webbuff, "background-image:-webkit-linear-gradient(top, #3498db, #2980b9);");
    strcat(webbuff, "background-image:linear-gradient(to bottom, #3498db, #2980b9);");
    strcat(webbuff, "-webkit-border-radius:12;border-radius: 12px;font-family: Arial;color:#ffffff;font-size:20px;padding:");
    strcat(webbuff, "10px 20px 10px 20px; border:solid #103c57 3px;text-decoration: none;");
    strcat(webbuff, "background: #3cb0fd;");
    strcat(webbuff, "background-image:-webkit-linear-gradient(top,#3cb0fd,#1a5f8a);");
    strcat(webbuff, "background-image:linear-gradient(to bottom,#3cb0fd,#1a5f8a);");
    strcat(webbuff, "text-decoration:none;\"></form></span>");
    strcat(webbuff, "<p/><h2>How to use:</h2><ul>");
    strcat(webbuff, "<li>Select the Radio buttons to control the digital out pins.</li>");
    strcat(webbuff, "<li>Click 'Send-Refresh' to send.</li>");
    strcat(webbuff, "<li>Use the 'Send-Refresh' button to refresh the data.</li>");
    strcat(webbuff, "</ul>");
    strcat(webbuff, "</body></html>");
// end of WEB page data
    bufl = strlen(webbuff); // get total page buffer length
    sprintf(cmdbuff,"AT+CIPSEND=%d,%d\r\n", linkID, bufl); // send IPD link channel and buffer character length.
    timeout=200;
    getcount=7;
    SendCMD();
    getreply();
    SendWEB();  // send web page
    memset(webbuff, '\0', sizeof(webbuff));
    sendcheck();
}

//  wait for ESP "SEND OK" reply, then close IP to load web page
void sendcheck()
{
    weberror=1;
    timeout=500;
    getcount=24;
    t2.reset();
    t2.start();
    while(weberror==1 && t2.read() <5) {
        getreply();
        if (strstr(replybuff, "SEND OK") != NULL) {
            weberror=0;   // wait for valid SEND OK
        }
    }
    if(weberror==1) { // restart connection
        strcpy(cmdbuff, "AT+CIPMUX=1\r\n");
        timeout=500;
        getcount=10;
        SendCMD();
        getreply();
        pc.printf(replybuff);
        sprintf(cmdbuff,"AT+CIPSERVER=1,%d\r\n", port);
        timeout=500;
        getcount=10;
        SendCMD();
        getreply();
        pc.printf(replybuff);
    } else {
        sprintf(cmdbuff, "AT+CIPCLOSE=%s\r\n",channel); // close current connection
        SendCMD();
        getreply();
        pc.printf(replybuff);
    }
    t2.reset();
}

// Reads and processes GET and POST web data
void ReadWebData()
{
    wait_ms(200);
    esp.attach(NULL);
    count=0;
    DataRX=0;
    weberror=0;
    memset(webdata, '\0', sizeof(webdata));
    int x = strcspn (webbuff,"+");
    if(x) {
        strcpy(webdata, webbuff + x);
        weberror=0;
        int numMatched = sscanf(webdata,"+IPD,%d,%d:%s", &linkID, &ipdLen, type);
        if( strstr(webdata, "LeftWheelSpeed=1") != NULL ) {
            LeftWheelSpeed=1;
            led1 = LeftWheelSpeed;
        }
        if( strstr(webdata, "LeftWheelSpeed=0") != NULL ) {
            LeftWheelSpeed=0;
            led1 = LeftWheelSpeed;
        }
        
        if( strstr(webdata, "LeftWheelDir=1") != NULL ) {
            LeftWheelDir=1;
            led2 = LeftWheelDir;
            
        }
        if( strstr(webdata, "LeftWheelDir=0") != NULL ) {
            LeftWheelDir=0;
            led2 = LeftWheelDir;
        }
                if( strstr(webdata, "RightWheelSpeed=1") != NULL ) {
            RightWheelSpeed=1;
            led3 = RightWheelSpeed;
        }
        if( strstr(webdata, "RightWheelSpeed=0") != NULL ) {
            RightWheelSpeed=0;
            led3 = RightWheelSpeed;
        }
        
        if( strstr(webdata, "RightWheelDir=1") != NULL ) {
            RightWheelDir=1;
            led4 = RightWheelDir;
        }
        if( strstr(webdata, "RightWheelDir=0") != NULL ) {
            RightWheelDir=0;
            led4 = RightWheelDir;
        }
        A.speed((LeftWheelSpeed)*((LeftWheelDir-.5))*-1);
        
        B.speed((RightWheelSpeed)*((RightWheelDir-.5)));
        sprintf(channel, "%d",linkID);
        if (strstr(webdata, "GET") != NULL) {
            servreq=1;
        }
        if (strstr(webdata, "POST") != NULL) {
            servreq=1;
        }
        webcounter++;
        sprintf(webcount, "%d",webcounter);
    } else {
        memset(webbuff, '\0', sizeof(webbuff));
        esp.attach(&callback);
        weberror=1;
    }
}
// Starts and restarts webserver if errors detected.
void startserver()
{

    pc.printf("\n\n RTC time   %s\r\n\n",timebuf);
    pc.printf("++++++++++ Resetting ESP ++++++++++\r\n");
    strcpy(cmdbuff,"AT+RST\r\n");
    timeout=8000;
    getcount=1000;
    SendCMD();
    getreply();
    pc.printf(replybuff);
    pc.printf("%d",count);
    if (strstr(replybuff, "OK") != NULL) {
        pc.printf("\n++++++++++ Starting Server ++++++++++\r\n");
        strcpy(cmdbuff, "AT+CIPMUX=1\r\n");  // set multiple connections.
        timeout=500;
        getcount=20;
        SendCMD();
        getreply();
        pc.printf(replybuff);
        sprintf(cmdbuff,"AT+CIPSERVER=1,%d\r\n", port);
        timeout=500;
        getcount=20;
        SendCMD();
        getreply();
        pc.printf(replybuff);
        wait(1);
        sprintf(cmdbuff,"AT+CIPSTO=%d\r\n",SERVtimeout);
        timeout=500;
        getcount=50;
        SendCMD();
        getreply();
        pc.printf(replybuff);
        wait(5);
        pc.printf("\n Getting Server IP \r\n");
        strcpy(cmdbuff, "AT+CIFSR\r\n");
        timeout=2500;
        getcount=200;
        while(weberror==0) {
            SendCMD();
            getreply();
            if (strstr(replybuff, "0.0.0.0") == NULL) {
                weberror=1;   // wait for valid IP
            }
        }
        pc.printf("\n Enter WEB address (IP) found below in your browser \r\n\n");
        pc.printf("\n The MAC address is also shown below,if it is needed \r\n\n");
        replybuff[strlen(replybuff)-1] = '\0';
        //char* IP = replybuff + 5;
        sprintf(webdata,"%s", replybuff);
        pc.printf(webdata);
        LeftWheelDir=1;
        bufflen=200;
        count=0;
        pc.printf("\n\n++++++++++ Ready ++++++++++\r\n\n");
        esp.attach(&callback);
    } else {
        pc.printf("\n++++++++++ ESP8266 error, check power/connections ++++++++++\r\n");
        while(1) {}
    }
    t2.reset();
    t2.start();

}
// ESP Command data send
void SendCMD()
{
    esp.printf("%s", cmdbuff);
}
// Large WEB buffer data send
void SendWEB()
{
    int i=0;
    if(esp.writeable()) {
        while(webbuff[i]!='\0') {
            esp.putc(webbuff[i]);
            i++;
        }
    }
}
// Get Command and ESP status replies
void getreply()
{
    memset(replybuff, '\0', sizeof(replybuff));
    t1.reset();
    t1.start();
    replycount=0;
    while(t1.read_ms()< timeout && replycount < getcount) {
        if(esp.readable()) {
            replybuff[replycount] = esp.getc();
            replycount++;
        }
    }
    t1.stop();
}
// Analog in example

// Get RTC time
void gettime()
{
    time_t seconds = time(NULL);
    strftime(timebuf,50,"%H:%M:%S %a %d %b %y", localtime(&seconds));
}



void setRTC()
{
    t.tm_sec = (0);             // 0-59
    t.tm_min = (minute);        // 0-59
    t.tm_hour = (hour);         // 0-23
    t.tm_mday = (dayofmonth);   // 1-31
    t.tm_mon = (month-1);       // 0-11  "0" = Jan, -1 added for Mbed RCT clock format
    t.tm_year = ((year)+100);   // year since 1900,  current DCF year + 100 + 1900 = correct year
    set_time(mktime(&t));       // set RTC clock
}


Please log in to post comments.