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.
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.
Wiring table for ESP8266
ESP8266 | Mbed |
---|---|
RX | TX-p28 |
VCC | 3.3V |
GPIO 0 | NC |
RESET | p26 |
CH_PD | 3.3V |
GPIO2 | NC |
TX | RX-p27 |
GND | GND |
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.
Wiring table for H-bridge
ESP8266 | Mbed |
---|---|
GND | GND |
VCC | 3.3V |
A01 | Left Motor + |
A02 | Left Motor - |
B02 | Right Motor - |
B02 | Right Motor + |
VMOT | 5V |
GND | GND |
PWMA | p22 |
AIN2 | p6 |
AIN1 | p5 |
STBY | 3.3V |
BIN1 | p8 |
BIN2 | p7 |
PWMB | p21 |
GND | GND |
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 -  "); strcat(webbuff, timebuf); strcat(webbuff, "</h3>\r\n"); strcat(webbuff, "<p><form method=\"POST\"><strong>"); // strcat(webbuff, "<p><form method=\"POST\"><strong> Analog 1:  <input type=\"text\" size=6 value=\""); // strcat(webbuff, Temp); // strcat(webbuff, "\"> </sup>V <form method=\"POST\"> <strong>   Analog 2:  <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.