Bluetooth app controlled robot

Dependencies:   ESP8266 HALLFX_ENCODER LSM9DS1_Library_cal MotorDriver PID mbed

Fork of ESP8266_pid_redbot_webserver by Bryce Williams

Revision:
2:3466e9e16c99
Parent:
1:d4a95e3a8aeb
Child:
3:bf6e71964ceb
diff -r d4a95e3a8aeb -r 3466e9e16c99 main.cpp
--- a/main.cpp	Tue Dec 08 00:17:04 2015 +0000
+++ b/main.cpp	Wed Mar 16 16:03:44 2016 +0000
@@ -1,51 +1,17 @@
-/*
-    Uses the ESP8266 WiFi Chip to set up a WiFi Webserver used to control 
-    the speed of a Sparkfun Redbot Rotbot. USE FIREFOX 
-    Web Browser
-
-    NOTES: 
-    1. Webpage Handling in this program is specific to a CUSTOM 
-    WEBPAGE. Program must be modified to handle specfically a new 
-    webpage. A copy of the webpage for this program can be found at 
-    the end of this program page. Simply copy and past text into a
-    html file and save as the given name.
-    
-    2. Developed and tested with FireFox 42.0 Web Browser. Does not seem to work
-    well with Google Chrome or Internet Explorer for some reason... they seem 
-    to generate two post requests which messes with the user input values. 
-    
-    3. There are a bunch of printf statements in the code that can be
-    uncommented for debugging in a serial terminal progrom. 
-
-    
-    TODO: ESP8366 has a max packet send size. Make sure we implement
-    a method to send webpages that exceed this value. The max size is
-    listed in the official ESP8266 AT Commands Documentation, I think
-    it is 2048 bytes/chars
-    
-    TODO: CREATE CONFIG FUNCTION TO SET SSID, PASSWORD, BAUDRATE ETC.
-    Perhaps have a serial terminal method to take user input, and 
-    put the function call into a #ifdef WiFiConfig statement, so 
-    that the user can enable it to config Wifi module then turn 
-    it off once Wifi module is configed so that this program can 
-    run in a "stand alone" mode. 
-    
-    Reference/ Sources: This code is based on 
-    https://developer.mbed.org/users/4180_1/notebook/using-the-esp8266-with-the-mbed-lpc1768/
-*/
-
 #include "mbed.h"
-#include "SDFileSystem.h"
 #include "PID.h"
 #include "HALLFX_ENCODER.h"
 #include "MotorDriver.h"
+#include "LSM9DS1.h"
 #include <algorithm>
+#define PI 3.14159
+#define DECLINATION -4.94 // Declination (degrees) in Atlanta,GA.
+#define REFRESH_TIME_MS 1
+#define DEBUG
 
-//#define DEBUG   // Uncomment for serial terminal print debugging
-                // Comment out to turn prints off for normal op
-
-/*********PID CONTROLLER SPECIFIC DECLARATIONS********************************/
-/*****************************************************************************/
+Serial blue(p28,p27);
+BusOut myled(LED1,LED2,LED3,LED4);
+Serial pc(USBTX, USBRX);
 float kp, ki, kd;                               // Working gain vars
 float working_setpoint;                         // Used for web parsing and updating
 float setpoint;                                 // This is used by PID objects, because 
@@ -62,8 +28,6 @@
 const float output_upper_limit = 1.0;
 const float FEEDBACK_SCALE = 1.0/384.0;         // Scale feedback to 1rev/3000cnts
                                                 // this is encoder specific.
-enum CONTROL_MODE{PID_OFF = 0, PID_ON = 1};
-int control_mode = PID_ON;
 const float Ts = 0.04;                         // 25Hz Sample Freq (40ms Sample Time)
 const float Ts_PID_CALLBACK = Ts/2.0;          // Update Motors and sensers twice as 
                                                // fast as PID sample rate, ensures
@@ -85,97 +49,80 @@
 HALLFX_ENCODER encR(p21);
 HALLFX_ENCODER encL(p22);
 void pid_callback();            // Updates encoder feedback and motor output
+        
 Ticker motor;                   // Interrupt for feedback and motor updates
-/*****************************************************************************/
-/*****************************************************************************/                
-
-/**********WEB SERVER SPECIFIC DECLARTATIONS**********************************/
-/*****************************************************************************/
-SDFileSystem sd(p5,p6,p7,p8,"sd");  // MOSI, MISO, SCLK, CS, 
-                                    // Virtual File System Name
-Serial esp(p13, p14);           // tx, rx
-DigitalOut  espRstPin(p26);     // ESP Reset
-DigitalOut led(LED4);
+//global variables for main and interrupt routine
 
-Timer t1;
-Timer t2;
+char state_num = 0, bnum =0 ;
+int dirL = 0, dirR = 0;
 
-void init(char* buffer, int size);
-void getreply(int timeout_ms, char* buffer, int size, int numBytes);
-void startserver(char* buffer, int size);
-void update_webpage(char* webpage, float working_setpoint, float kp, float ki, float kd);
-void parse_input(char* webpage_user_data, int* control_mode, float* working_setpoint, float* kp, float* ki, float* kd);
-int port        =80;         // set server port
-int serverTimeout_secs =5;   // set server timeout in seconds in case 
-                             // link breaks.
-/*****************************************************************************/
-/*****************************************************************************/
+//Interrupt routine to parse message with one new character per serial RX interrupt
 
-// Common Application Declarations
-Serial pc(USBTX, USBRX);
 float clip(float value, float lower, float upper);
 
+LSM9DS1 imu(p9, p10, 0xD6, 0x3C);
+void calculate_heading(float mx, float my, float mz);
+float oldX = 0;
+float oldY = 0;
+float oldZ = 0;
+float x= 0;
+float y = 0;
+float z  = 0;
+
+float posx = 0;
+float velx = 0;
+float oldPosx = 0;
+float oldVelx = 0;
+
+float posy = 0;
+float vely = 0;
+float oldPosy = 0;
+float oldVely = 0;
+
+float posz = 0;
+float velz = 0;
+float oldPosz = 0;
+float oldVelz = 0;
+int sample_time = 0;
+
+float accelx = 0, accely = 0, accelz = 0;
+Serial esp(p13, p14);           // tx, rx
+DigitalOut reset(p26);
+
+Timer t;
+void send_data(float *accelx, float *accely, float *accelz, float *velx, float *vely, float *velz);
+int  count,ended,timeout;
+float heading = 0.0;
+char buf[1024];
+char snd[1024];
+char str_buf[80];
+ 
+char ssid[32] = "4180_test";     // enter WiFi router ssid inside the quotes
+char pwd [32] = "4180isawesome"; // enter WiFi router password inside the quotes
+ 
+void SendCMD(),getreply(),ESPconfig(),ESPsetbaudrate();
 int main()
 {
-    printf("Starting\n");
-    
-    /****************** Load Webpage from SD Card***************************************/
-    /***********************************************************************************/
-    char file[] = "/sd/pid_bot.html";
+    pc.printf("\f---------- Program Start ----------\r\n\n");
+    reset=0; //hardware reset for 8266
+    pc.baud(9600);  // set what you want here depending on your terminal program speed
+    pc.printf("\f\n\r-------------ESP8266 Hardware Reset-------------\n\r");
+    wait(0.5);
+    reset=1;
+    timeout=2;
+    getreply();
     
-    // Get file size so we can dynamically allocate buffer size 
-    int num_chars = 0;
-    FILE *fp = fopen(file, "r");
-    while(!feof(fp)){
-        fgetc(fp);
-        num_chars++;
-    } 
-    rewind(fp);                     // Go to beginning of file
+    ESPconfig();        //******************  include Config to set the ESP8266 configuration  ***********************
 
-    #ifdef DEBUG
-    printf("Webpage Data Size: %d byte\r\n", num_chars);
-    #endif
-
-    const int WEBPAGE_SIZE = num_chars;
-    char webpage[WEBPAGE_SIZE];                   
-    webpage[0] = NULL;               // Init our array so that element zero contains a null
-                                    // This is important, ensures strings are placed into
-                                    // buffer starting at element 0... not some random 
-                                    // elment                                           
-    // Read in and buffer file to memory
-    if(fp == NULL){
-         printf("Error: No Such File or something :(");
-         return 1;
+    imu.begin();
+    if (!imu.begin()) {
+        pc.printf("Failed to communicate with LSM9DS1.\n");
     }
-    else{
-        while(!feof(fp)){
-            fgets(webpage + strlen(webpage), WEBPAGE_SIZE, fp);  // Get a string from stream, add to buffer
-        }
-    }
-    fclose(fp);
-    printf("Webpage Buffer Size: %d bytes\r\n", sizeof(webpage));
-    update_webpage(webpage, working_setpoint, kp_init, ki_init, kd_init);  // Update Webpage for 
-                                                                   // Position Mode   
-    /***********************************************************************************/
-    /***********************************************************************************/
+    imu.calibrate(1);
+    imu.calibrateMag(0);
+
+    working_setpoint = 0.0;
     
-    /***************BRING UP SERVER*****************************************************/
-    /***********************************************************************************/
-    char buff[5000];                // Working buffer
-    init(buff, sizeof(buff));       // Init ESP8266
-    
-    esp.baud(115200);               // ESP8266 baudrate. Maximum on KLxx' is 115200, 230400 works on K20 and K22F
-  
-    startserver(buff, sizeof(buff));      // Configure the ESP8266 and Setup as Server
-
-    printf(buff);                   // If start successful buff contains IP address...
-                                    // if not if contains an error.
-    /***********************************************************************************/
-    /***********************************************************************************/
-    
-    /************Initialize the PID*****************************************************/
-    /***********************************************************************************/
-    working_setpoint = 0.0;
     encL.reset();
     encR.reset();
     feedbackL = encL.read();
@@ -184,453 +131,327 @@
     // Update sensors and feedback twice as fast as PID sample time
     // this makes pid react in real-time avoiding errors due to 
     // missing counts etc. 
+    
     motor.attach(&pid_callback, Ts_PID_CALLBACK);
-    
+
     // Start PID sampling
     pidL.start();
     pidR.start();
-    
-    /***********************************************************************************/
-    /***********************************************************************************/
-    
-    while(1){
-        /**************SERVICE WEBPAGE******************************************************/
-        /***********************************************************************************/
-        if(esp.readable()){
-            getreply(500, buff, sizeof(buff), sizeof(buff) -1); // Get full buff, leave last element for null char
-            #ifdef DEBUG
-            printf("\r\n*************WORKING BUFFER******************************\r\n");
-            printf(buff); printf("\n");
-            printf("\r\n**************END WORKING BUFFER**************************\r\n");
-            #endif            
-            // If Recieved Data get ID, Length, and Data
-            char* rqstPnt = strstr(buff, "+IPD");
-            if(rqstPnt != NULL){
-                int id, len;
-                char type[10]; memset(type, '\0', sizeof(type)); // Create and null out data buff
-                sscanf(rqstPnt, "+IPD,%d,%d:%s ", &id, &len, type);
-                #ifdef DEBUG
-                printf("ID: %i\nLen: %i\nType: %s\n", id, len, type);
-                #endif                
-                // If GET or POST request "type" parse and update user input then send webpage
-                if(strstr(type, "GET") != NULL || strstr(type, "POST") != NULL){
-                    #ifdef DEBUG
-                    printf("I got web request\n");
-                    #endif                   
-                    /* Read Webpage <Form> data sent using "method=POST"...
-                       Note: Input elements in the <Form> need a set name attribute to 
-                       appear in the returned HTML body. Thus to "POST" data ensure:
-                       <Form method="POST"> <input type="xxx" name="xxx" value="xxx"> 
-                       <input type="xxx" value="xxx"> </Form>
-                       Only the input with name="xxx" will appear in body of HTML
-                    */
-                    #ifdef DEBUG
-                    printf("\r\n*************USER INPUT**********************************\r\n");
-                    #endif
-                    
-                    parse_input(buff, &control_mode, &working_setpoint, &kp, &ki, &kd);
-                    working_setpoint = clip(working_setpoint, -90.0, 90.0); // Redbot motors are ~90 RPM; max html field size for setpoint is 7 (to accomodate for a "-" sign
-                    kp = clip(kp, 0.00, 999.99); // 999.99 is max size that can be updated to webpage, i.e. field is 6 digits (see html)
-                    ki = clip(ki, 0.00, 999.99); // 999.99 is max size that can be updated to webpage, i.e. field is 6 digits (see html)
-                    kd = clip(kd, 0.00, 999.99); // 999.99 is max size that can be updated to webpage, i.e. field is 6 digits (see html)
-                    
-                    #ifdef DEBUG
-                    printf("User Entered: \ncontrol_mode: %i\nSetpoint: %7.4f\nKp: %6.4f\nKi: %6.4f\nKd: %6.4f\n", 
-                            control_mode, working_setpoint, kp, ki, kd);
-                    #endif                    
-                     
-                    pidL.set_parameters(kp, ki, kd, Ts);    // Updata PID params 
-                    pidR.set_parameters(kp, ki, kd, Ts);    // Updata PID params 
-                    
-                    #ifdef DEBUG
-                    printf("Updated to Kp: %1.4f Ki: %1.4f Kd: %1.4f Ts: %1.4f\r\n",
-                            pidL.getKp(), pidL.getKi(), pidL.getKd(), pidL.getTs());
-                    printf("Setpoint: %1.4f\r\n", working_setpoint);
-                    printf("\r\n*************END USER INPUT******************************\r\n");
-                    #endif
-                                        
-                    // Update Webpage to reflect new values POSTED by client
-                    static bool isFirstRequest = true;
-                    if(!isFirstRequest) update_webpage(webpage, working_setpoint, kp, ki, kd);
-                    else isFirstRequest = false; // First Request just send page with initial values
-                    
-                    #ifdef DEBUG
-                    printf(webpage); 
-                    #endif
-                    
-                    // Command TCP/IP Data Tx
-                    esp.printf("AT+CIPSEND=%d,%d\r\n", id, strlen(webpage));
-                    getreply(200, buff, sizeof(buff), 15); /*TODO: Wait for "OK\r\n>"*/
-                    
-                    #ifdef DEBUG
-                    printf(buff); printf("\n");
-                    #endif
-                    
-                    // Send webpage
-//                    while(!esp.writeable());         // Wait until esp ready to send data
-                    int idx = 0;
-                    while(webpage[idx] != '\0'){
-                        esp.putc(webpage[idx]);
-                        idx++;
+    working_setpoint = 0;
+    dirL = 1;
+    dirR = 1;
+    while(1)
+    {
+        if(blue.readable())
+        {
+            if (blue.getc()=='!')
+            {
+                if (blue.getc()=='B') //button data
+                {
+                    bnum = blue.getc(); //button number
+                    if(bnum=='1') {
+                        working_setpoint = 50;
+                        sample_time = 1;
+                        pc.printf("setpoint: %2.0f\r\n", working_setpoint);
                     }
-                   
-                    // Check status - Success: close channel and update PID controller, Error: reconnect 
-                    bool weberror = true;
-                    t2.reset(); t2.start();
-                    while(weberror ==1 && t2.read_ms() < 5000){
-                        getreply(500, buff, sizeof(buff), 24);
-                        if(strstr(buff, "SEND OK") != NULL) weberror = false;
-                    }
-                    if(weberror){
-                        esp.printf("AT+CIPMUX=1\r\n");
-                        getreply(500, buff, sizeof(buff), 10);
-                        #ifdef DEBUG
-                        printf(buff); printf("\n");
-                        #endif
-                        esp.printf("AT+CIPSERVER=1,%d\r\n", port);
-                        getreply(500, buff, sizeof(buff), 10);
-                        #ifdef DEBUG
-                        printf(buff); printf("\n");
-                        #endif
-                    }
-                    else{
-                        esp.printf("AT+CIPCLOSE=%d\r\n", id);  // Notice id is an int formatted to string
-                        getreply(500, buff, sizeof(buff), 24);
-                        #ifdef DEBUG
-                        printf(buff); printf("\n");
-                        #endif
-                    }
-                }       
+                }
             }
+        } 
+        while(!imu.accelAvailable());
+        imu.readAccel();
+        while(!imu.magAvailable());
+        imu.readMag();
+        
+        if( sample_time % 800 == 0)
+        {
+            velx = oldVelx + REFRESH_TIME_MS * oldX/1000;     
+            posx = oldPosx + REFRESH_TIME_MS * oldVelx/1000;
+            
+            vely = oldVely + REFRESH_TIME_MS * oldY/1000;     
+            posy = oldPosy + REFRESH_TIME_MS * oldVely/1000;
+                        
+            accelx = imu.calcAccel(imu.ax);
+            accely = imu.calcAccel(imu.ay);
+            accelz = imu.calcAccel(imu.az);
+            calculate_heading(imu.calcMag(imu.mx), imu.calcMag(imu.my), imu.calcMag(imu.mz)); 
+         
+            #ifdef DEBUG
+            pc.printf("        X axis    Y axis    Z axis\n\r");
+            pc.printf("accel: %2.2f %2.2f %2.2f in Gs\r\n", imu.calcAccel(imu.ax), imu.calcAccel(imu.ay), imu.calcAccel(imu.az));
+            pc.printf("Veloc: %2.2f %2.2f %2.2f in G*s\r\n", velx, vely, velz);
+            pc.printf("Magnetic heading: %2.2f", heading);
+            #endif
+           
+            oldVelx = velx;
+            oldPosx = posx;
+            oldVely = vely;
+            oldPosy = posy;
+            oldX = imu.ax;
+            oldY = imu.ay;
         }
-        /*********************************************************************/
-        /*********************************************************************/    
-    }                      
-}
-
-// Initialize ESP8266
-void init(char* buffer, int size){
-    // Hardware Reset ESP 
-    espRstPin=0;
-    wait(0.5);
-    espRstPin=1;
-    // Get start up junk from ESP8266
-    getreply(6000, buffer, size, 500);
-}
-
-// Get Command and ESP status replies
-void getreply(int timeout_ms, char* buffer, int size, int numBytes)
-{
-    memset(buffer, '\0', size);     // Null out buffer
-    t1.reset();
-    t1.start();
-    int idx = 0;
-    while(t1.read_ms()< timeout_ms && idx < numBytes) {
-        if(esp.readable()) {
-            buffer[idx] = esp.getc();
-            idx++;
+        if(working_setpoint > 0)
+        {
+            if(sample_time % 1500 == 0)
+            {   
+                #ifdef DEBUG
+                pc.printf("Pushing data to server\r\n");
+                #endif
+                
+                myled[0] = !myled[0];
+                working_setpoint = 0;
+    
+                strcpy(snd, "srv:listen(80,function(conn)\r\n");
+                SendCMD();
+                wait(1);
+                strcpy(snd, "conn:on(\"receive\",function(conn,payload)\r\n");
+                SendCMD();
+                wait(1);
+                strcpy(snd, "print(payload)\r\n");
+                SendCMD();
+                wait(1);
+                strcpy(snd, "conn:send(\"<!DOCTYPE html>\")\r\n");
+                SendCMD();
+                wait(1);
+                
+                strcpy(snd, "conn:send(\"<html>\")\r\n");
+                SendCMD();
+                wait(1);
+                sprintf(str_buf,"%2.2f",velx);
+                strcpy(snd, "conn:send(\"<h1>Velocity x: ");
+                strcat(snd, str_buf);
+                strcat(snd, "</h1>\")\r\n");
+                SendCMD();
+                wait(1);
+                
+                sprintf(str_buf,"%2.2f",vely);
+                strcpy(snd, "conn:send(\"<h1>Velocity y: ");
+                strcat(snd, str_buf);
+                strcat(snd, "</h1>\")\r\n");
+                SendCMD();
+                wait(1);
+                
+                sprintf(str_buf,"%2.2f",heading);
+                strcpy(snd, "conn:send(\"<h1>Magnetic Heading: ");
+                strcat(snd, str_buf);
+                strcat(snd, "</h1>\")\r\n");
+                SendCMD();
+                wait(1);
+                
+                strcpy(snd, "conn:send(\"</html>\")\r\n");
+                SendCMD();
+                wait(1);
+                
+                strcpy(snd, "end)\r\n");
+                SendCMD();
+                wait(1);
+                
+                strcpy(snd, "conn:on(\"sent\",function(conn) conn:close() end)\r\n");
+                SendCMD();
+                wait(1);
+                strcpy(snd, "end)\r\n");
+                SendCMD();
+                wait(1);
+                timeout=17;
+                getreply();
+                pc.printf(buf);
+                pc.printf("\r\nDONE");
+            }
+            if(sample_time > 100000)
+            {
+                sample_time = 1;
+            } 
+            sample_time++;
         }
     }
-    t1.stop();
-}
-
-// Starts and restarts webserver if errors detected.
-void startserver(char* buffer, int size)
-{
-    esp.printf("AT+RST\r\n");       // BWW: Reset the ESP8266          
-    getreply(8000, buffer, size, 1000);                                            
-
-    if (strstr(buffer, "OK") != NULL) {
-        // BWW: Set ESP8266 for multiple connections
-        esp.printf("AT+CIPMUX=1\r\n");
-        getreply(500, buffer, size, 20);
-        
-        // BWW: Set ESP8266 as Server on given port
-        esp.printf("AT+CIPSERVER=1,%d\r\n", port);
-        getreply(500, buffer, size, 20);   // BWW: Wait for reply
-                
-        // BWW: Set ESP8266 Server Timeout
-        esp.printf("AT+CIPSTO=%d\r\n", serverTimeout_secs);
-        getreply(500, buffer, size, 50);    // BWW: Wait for reply
-        
-        // BWW: Request IP Address from router for ESP8266 
-        int weberror = 0;
-        while(weberror==0) {
-            esp.printf("AT+CIFSR\r\n");
-            getreply(2500, buffer, size, 200);
-            if(strstr(buffer, "0.0.0.0") == NULL) {
-                weberror=1;   // wait for valid IP
-            }
-        }
-    } 
-    // else ESP8266 did not reply "OK" something is messed up
-    else {
-        strcpy(buffer, "ESP8266 Error\n");
-    }
 }
 
-/*
-    update_webpage() updates output fields based on webpage user inputs "POSTED"
-    Preconditions: webpage[] must have the following elements
-        "kp_output"  value="xxx.xx"
-        "ki_output"  value="xxx.xx"
-        "kp_output"  value="xxx.xx"
-    @param webpage  Pointer to webpage char[]
-    @param kp       New kp value posted by user
-    @param ki       New ki value posted by user
-    @param kd       New kd value posted by user
-    
-    NOTE: THIS IS WEBPAGE SPECIFIC!!!! CHANGE THE CODE IN HERE TO SUITE THE 
-    SPECIFIC APPLICATION WEBPAGE!!! ALSO USED TO REFLECT THE CUSTOM 
-    IMPLEMENTATION OF THE parse_intput() function. MAKE SURE THESE TWO FUNCTIONS 
-    INTEGRATE PROPERLY!!!
-*/
-void update_webpage(char* webpage, float working_setpoint, float kp, float ki, float kd){
-    // Change output value to reflect new control mode, setpoint, kp, ki, kd values
-    char* begin; 
-    char temp[8];
-    int idx;
-    
-    // Update Control Mode Radio Buttons
-    memset(temp, '\0', sizeof(temp));
-    idx = 0;
-    begin = strstr(webpage, "name=\"control_mode\" value=\"") +     
-            sizeof("name=\"control_mode\" value=\"0");        // Update Control Mode Position Radio Button
-    if(control_mode == PID_OFF) sprintf(temp, "%s", "checked");// If PID OFF active "check" it
-    else sprintf(temp, "%s", "       ");                         // else "clear" it
-    while(temp[idx] !=  '\0'){                                  // Write "checked"/"        " to field
-        begin[idx] = temp[idx];
-        idx++;
-    }
-    memset(temp, '\0', sizeof(temp));
-    idx = 0;
-    begin = strstr(webpage, "name=\"control_mode\" value=\"") +     
-            sizeof("name=\"control_mode\" value=\"0\"");        // Nav to first Control Mode Radio Button (Position)
-    begin = strstr(begin, "name=\"control_mode\" value=\"") +     
-            sizeof("name=\"control_mode\" value=\"1");        // Nav to second Control Mode Radio Button (Speed) 
-    if(control_mode == PID_ON) sprintf(temp, "%s", "checked"); // If PID ON active "check" it
-    else sprintf(temp, "%s", "       ");                         // else "clear" it
-    while(temp[idx] !=  '\0'){                                  // Write "checked"/"        " to field
-        begin[idx] = temp[idx];
-        idx++;
-    }
+void ESPconfig()
+{
+    wait(5);
+    pc.printf("\f---------- Starting ESP Config ----------\r\n\n");
+    strcpy(snd,".\r\n.\r\n");
+    SendCMD();
+    wait(1);
+    pc.printf("---------- Reset & get Firmware ----------\r\n");
+    strcpy(snd,"node.restart()\r\n");
+    SendCMD();
+    timeout=5;
+    getreply();
+    pc.printf(buf);
+ 
+    wait(2);
+ 
+    pc.printf("\n---------- Get Version ----------\r\n");
+    strcpy(snd,"print(node.info())\r\n");
+    SendCMD();
+    timeout=4;
+    getreply();
+    pc.printf(buf);
+    wait(3);
+ 
+    // set CWMODE to 1=Station,2=AP,3=BOTH, default mode 1 (Station)
+    pc.printf("\n---------- Setting Mode ----------\r\n");
+    strcpy(snd, "wifi.setmode(wifi.STATION)\r\n");
+    SendCMD();
+    timeout=4;
+    getreply();
+    pc.printf(buf);
+ 
+    wait(2);
+
+    pc.printf("\n---------- Connecting to AP ----------\r\n");
+    pc.printf("ssid = %s   pwd = %s\r\n",ssid,pwd);
+    strcpy(snd, "wifi.sta.config(\"");
+    strcat(snd, ssid);
+    strcat(snd, "\",\"");
+    strcat(snd, pwd);
+    strcat(snd, "\")\r\n");
+    SendCMD();
+    timeout=10;
+    getreply();
+    pc.printf(buf);
+ 
+    wait(5);
+ 
+    pc.printf("\n---------- Get IP's ----------\r\n");
+    strcpy(snd, "print(wifi.sta.getip())\r\n");
+    SendCMD();
+    timeout=3;
+    getreply();
+    pc.printf(buf);
+ 
+    wait(1);
+ 
+    pc.printf("\n---------- Get Connection Status ----------\r\n");
+    strcpy(snd, "print(wifi.sta.status())\r\n");
+    SendCMD();
+    timeout=5;
+    getreply();
+    pc.printf(buf);
+      
+    pc.printf("\n---------- Setting up http server ----------\r\n");
+    strcpy(snd, "srv=net.createServer(net.TCP)\r\n");
+    SendCMD();
+    wait(1);
+    strcpy(snd, "srv:listen(80,function(conn)\r\n");
+    SendCMD();
+    wait(1);
+    strcpy(snd, "conn:on(\"receive\",function(conn,payload)\r\n");
+    SendCMD();
+    wait(1);
+    strcpy(snd, "print(payload)\r\n");
+    SendCMD();
+    wait(1);
+    strcpy(snd, "conn:send(\"<!DOCTYPE html>\")\r\n");
+    SendCMD();
+    wait(1);
     
-    // Update Kp Paramater Field
-    memset(temp, '\0', sizeof(temp));
-    idx = 0;
-    begin = strstr(webpage, "name=\"kp_input\" value=\"") + 
-            sizeof("name=\"kp_input\" value="); // Points to start of kp_output field
-    // Determine precision of float such temp string has no empty spaces; 
-    // i.e. each space must have a value or a decimal point, other wise webbrowser may not recognize value
-    if(kp >= 100) sprintf(temp, "%6.2f", kp);                             // xxx.00
-    else if(10 <= kp && kp < 100) sprintf(temp, "%6.3f", kp);             // xx.000
-    else sprintf(temp, "%6.4f", kp);                                      // x.0000
-    while(temp[idx] !=  '\0'){                                            // Overwrite old digits with new digits
-        begin[idx] = temp[idx];
-        idx++;
-    }
+    strcpy(snd, "conn:send(\"<html>\")\r\n");
+    SendCMD();
+    wait(1);
     
-    // Update Ki Parameter Field
-    memset(temp, '\0', sizeof(temp));
-    idx = 0;
-    begin = strstr(webpage, "name=\"ki_input\" value=\"") + 
-            sizeof("name=\"ki_input\" value="); // Points to start of ki_output field
-    // Determine precision of float such temp string has no empty spaces; 
-    // i.e. each space must have a value or a decimal point, other wise webbrowser may not recognize value 
-    if(ki >= 100) sprintf(temp, "%6.2f", ki);                             // xxx.00
-    else if(10 <= ki && ki < 100) sprintf(temp, "%6.3f", ki);             // xx.000
-    else sprintf(temp, "%6.4f", ki);                                      // x.0000     
-    while(temp[idx] !=  '\0'){                                            // Overwrite old digits with new digits
-        begin[idx] = temp[idx];
-        idx++;
-    }
+    strcpy(snd, "conn:send(\"<h1>WIFI Monitoring Program</h1>\")\r\n");
+    SendCMD();
+    wait(1);
+    
+    strcpy(snd, "conn:send(\"</html>\")\r\n");
+    SendCMD();
+    wait(1);
     
-    // Update Kd Parameter Field
-    memset(temp, '\0', sizeof(temp));
-    idx = 0;
-    begin = strstr(webpage, "name=\"kd_input\" value=\"")+
-            sizeof("name=\"kd_input\" value="); // Points to start of kd_output field
-    // Determine precision of float such temp string has no empty spaces; 
-    // i.e. each space must have a value or a decimal point, other wise webbrowser may not recognize value
-    if(kd >= 100) sprintf(temp, "%6.2f", kd);                             // xxx.00
-    else if(10 <= kd && kd < 100) sprintf(temp, "%6.3f", kd);             // xx.000
-    else sprintf(temp, "%6.4f", kd);                                      // x.0000
-    while(temp[idx] !=  '\0'){                                            // Overwrite old digits with new digits
-        begin[idx] = temp[idx];
-        idx++;
-    }
+    strcpy(snd, "end)\r\n");
+    SendCMD();
+    wait(1);
     
-    // Update Setpoint Parameter Field
-    // Determine precision of float such temp string has no empty spaces; 
-    // i.e. each space must have a value or a decimal point or neg sign, 
-    // other wise webbrowser may not recognize value
-    memset(temp, '\0', sizeof(temp));
-    idx = 0;
-    begin = strstr(webpage, "name=\"setpoint_input\" value=\"")+
-            sizeof("name=\"setpoint_input\" value="); // Points to start of kp_output field
-    // Determine precision of float such temp string has no empty spaces; 
-    // i.e. each space must have a value or a decimal point, other wise webbrowser may not recognize value
-    if(working_setpoint >= 0.00){
-        if(working_setpoint >= 100) sprintf(temp, "%6.3f", working_setpoint);                           // xxx.000
-        else if(10 <= working_setpoint && working_setpoint < 100) sprintf(temp, "%7.4f", working_setpoint);     // xx.0000
-        else sprintf(temp, "%6.5f", working_setpoint);                                          // x.00000
-    }
-    else{
-        if(working_setpoint <= -100) sprintf(temp, "%6.2f", working_setpoint);                          // -xxx.00
-        else if(-100 < working_setpoint && working_setpoint <= -10) sprintf(temp, "%6.3f", working_setpoint);   // -xx.000
-        else sprintf(temp, "%6.4f", working_setpoint);                                          // -x.0000
-    }
-    while(temp[idx] !=  '\0'){                                            // Overwrite old digits with new digits
-        begin[idx] = temp[idx];
-        idx++;
-    }
+    strcpy(snd, "conn:on(\"sent\",function(conn) conn:close() end)\r\n");
+    SendCMD();
+    wait(1);
+    strcpy(snd, "end)\r\n");
+    SendCMD();
+    wait(1);
+    timeout=17;
+    getreply();
+    pc.printf(buf);
+    pc.printf("\r\nDONE");
+
 }
 
-/*
-    parse_input() take a char*, in particular a pointer to Webpage User 
-    Input Data, for example: 
-    char str[] = "+IPD,0,44:kp_input=0.12&ki_input=14.25&kd_input=125.42";
-    
-    and parses out the Setpoint Kp, Ki, Kd values that the user entered
-    and posted in the webpage. Values are converted to floats and 
-    assigned to the given argurments.
-    
-    NOTE: THIS IS WEBPAGE SPECIFIC!!!! CHANGE THE CODE IN HERE TO SUITE THE 
-    SPECIFIC APPLICATION WEBPAGE!!! THESE EXTRACTED VALUES WILL BE USED IN 
-    THE update_webpage() function. MAKE SURE THESE TWO FUNCTIONS INTEGRATE
-    PROPERLY!!!
-*/
-void parse_input(char* webpage_user_data, int* control_mode, float *working_setpoint, float* kp, float* ki, float* kd){
-    char keys[] = {'&', '\0'};
-      
-    // Parse out user input values
-    char input_buff[50]; 
-    char* begin;
-    char* end;
-    
-    // Parse and Update Control Mode Value
-    memset(input_buff, '\0', sizeof(input_buff));           // Null out input buff
-    begin = strstr(webpage_user_data, "control_mode=") +
-            sizeof("control_mode");                         // Points to start of setpoint_input value
-    end = begin + strcspn(begin, keys);                     // Points to end of setpoint_input value
-    for(long i = 0; i < end - begin; i++){                  // Parse out the value one char at a time
-        input_buff[i] = begin[i];        
+void SendCMD()
+{
+    esp.printf("%s", snd);
+}
+ 
+void getreply()
+{
+    memset(buf, '\0', sizeof(buf));
+    t.start();
+    ended=0;
+    int count=0;
+    while(!ended) {
+        if(esp.readable()) {
+            buf[count] = esp.getc();
+            count++;
+        }
+        if(t.read() > timeout) {
+            ended = 1;
+            t.stop();
+            t.reset();
+        }
     }
-    *control_mode = atoi(input_buff);
+}
+void calculate_heading(float mx, float my, float mz)
+{
+
+// touchy trig stuff to use arctan to get compass heading (scale is 0..360)
+    mx = -mx;
+    if (my == 0.0)
+        heading = (mx < 0.0) ? 180.0 : 0.0;
+    else
+        heading = atan2(mx, my)*360.0/(2.0*PI);
+    heading -= DECLINATION; //correct for geo location
+    if(heading>180.0) heading = heading - 360.0;
+    else if(heading<-180.0) heading = 360.0 + heading;
+    else if(heading<0.0) heading = 360.0  + heading;
     
-    // Parse and Update Setpoint Value
-    memset(input_buff, '\0', sizeof(input_buff));           // Null out input buff
-    begin = strstr(webpage_user_data, "setpoint_input=") +
-            sizeof("setpoint_input");                       // Points to start of setpoint_input value
-    end = begin + strcspn(begin, keys);                     // Points to end of setpoint_input value
-    for(long i = 0; i < end - begin; i++){                  // Parse out the value one char at a time
-        input_buff[i] = begin[i];        
-    }
-    *working_setpoint = atof(input_buff);
-    
-    // Parse and Update Kp Value
-    memset(input_buff, '\0', sizeof(input_buff));           // Null out input buff
-    begin = strstr(webpage_user_data, "kp_input=") + 
-            sizeof("kp_input");                             // Points to start of kp_input value
-    end = begin + strcspn(begin, keys);                     // Points to end of kp_input value
-    for(long i = 0; i < end - begin; i++){                  // Parse out the value one char at a time
-        input_buff[i] = begin[i];
-    }
-    *kp = atof(input_buff);
-    
-    // Parse and Update Ki Value
-    memset(input_buff, '\0', sizeof(input_buff));           // Null out input buff
-    begin = strstr(webpage_user_data, "ki_input=") + 
-            sizeof("ki_input");                             // Points to start of ki_input value
-    end = begin + strcspn(begin, keys);                     // Points to end of ki_input value
-    for(long i = 0; i < end - begin; i++){                  // Parse out the value one char at a time
-        input_buff[i] = begin[i];
-    }
-    *ki = atof(input_buff);
-    
-    // Parse and Update Kd Value
-    memset(input_buff, '\0', sizeof(input_buff));           // Null out input buff
-    begin = strstr(webpage_user_data, "kd_input=") + 
-            sizeof("kd_input");                             // Points to start of kd_input value
-    end = begin + strcspn(begin, keys);                     // Points to end of kd_input value
-    for(long i = 0; i < end - begin; i++){                  // Parse out the value one char at a time
-        input_buff[i] = begin[i];  
-    }
-    *kd = atof(input_buff);
-    
-    // Parse for stop button press; we only have to see if "STOP" exists in the input buffer 
-    // because it is just a button and will not be included unless it is pressed!... Makes 
-    // our job easy!... if stop was pressed then set setpoint to zero!
-    if(strstr(webpage_user_data, "STOP") != NULL) *working_setpoint = 0;
+    #ifdef DEBUG
+    pc.printf("Magnetic Heading: %f degress\n\r",heading);
+    #endif
 }
 
-void pid_callback(){
-    static int lastMode = control_mode;
+void pid_callback()
+{
+
+    // Deal with feedback and update motors
+    // Motor direction based on working setpoint var
+
+    //myled[0] = dirL;
+    //myled[1] = dirR;
+    // Setpoint vars used by PID objects are concerned with 
+    // only SPEED not direction. 
+    setpoint = abs(working_setpoint);
+
+    float k = Ts_PID_CALLBACK;    // Discrete time, (Ts/2 because this callback is called
+                                  // at interval of Ts/2... or twice as fast as pid controller)
+    static int last_count_L = 0;
+    static int last_count_R = 0;
+    int countL = encL.read();
+    int countR = encR.read();
+    //pc.printf("%d\r\n", countL);
     
-    // If control_mode is PID_OFF turn off PID controllers and run motors in open loop
-    if(control_mode == PID_OFF){
-        // Mode changed; turn off PID controllers
-        if(lastMode != control_mode){
-            pidL.stop(); pidR.stop();
-            lastMode = PID_OFF;
-        }
-        // Set motor speed in open loop mode
-        // Motor direction based on working setpoint var
-        int dirL, dirR;
-        if(working_setpoint < 0.0){
-             dirL = -1; dirR = -1;
-        }
-        else{
-            dirL = 1; dirR = 1;
-        }
-        float speed = abs(working_setpoint) / 90.0; // Normalize based on 90 RPM
-        mtrL.forceSetSpeed(speed * dirL);
-        mtrR.forceSetSpeed(speed * dirR);
-    }
-    // else control_mode is PID_ON, turn on PID controllers and run motors in closed loop
-    else{
-        // Mode changed; turn on PID controllers
-        if(lastMode != control_mode){
-            pidL.start(); pidR.start();
-            lastMode = PID_ON;
-        }
-        // Deal with feedback and update motors
-        // Motor direction based on working setpoint var
-        int dirL, dirR;
-        if(working_setpoint < 0.0){
-             dirL = -1; dirR = -1;
-        }
-        else{
-            dirL = 1; dirR = 1;
-        }
-        
-        // Setpoint vars used by PID objects are concerned with 
-        // only SPEED not direction. 
-        setpoint = abs(working_setpoint);
+    // Because encoders are not quadrature we must handle the sign ourselves, 
+    // i.e. explicitly make calcs based on the direction we have set the motor
+    float raw_speed_L = ((countL - last_count_L)*FEEDBACK_SCALE) / k; 
+    float rpm_speed_L = raw_speed_L * 60.0;     // Convert speed to RPM
+    
+    float raw_speed_R = ((countR - last_count_R)*FEEDBACK_SCALE) / k; 
+    float rpm_speed_R = raw_speed_R * 60.0;     // Convert speed to RPM
     
-        float k = Ts_PID_CALLBACK;    // Discrete time, (Ts/2 because this callback is called
-                                      // at interval of Ts/2... or twice as fast as pid controller)
-        static int last_count_L = 0;
-        static int last_count_R = 0;
-        int countL = encL.read();
-        int countR = encR.read();
-        
-        // Because encoders are not quadrature we must handle the sign outselves, 
-        // i.e. explicitly make calcs based on the direction we have set the motor
-        float raw_speed_L = ((countL - last_count_L)*FEEDBACK_SCALE) / k; 
-        float rpm_speed_L = raw_speed_L * 60.0;     // Convert speed to RPM
-        
-        float raw_speed_R = ((countR - last_count_R)*FEEDBACK_SCALE) / k; 
-        float rpm_speed_R = raw_speed_R * 60.0;     // Convert speed to RPM
-        
-        last_count_L = countL;                      // Save last count
-        last_count_R = countR;
-        feedbackL = rpm_speed_L;
-        feedbackR = rpm_speed_R;
-        
-        mtrL.forceSetSpeed(outputL * dirL);
-        mtrR.forceSetSpeed(outputR * dirR);
-    }
+    last_count_L = countL;                      // Save last count
+    last_count_R = countR;
+    feedbackL = rpm_speed_L;
+    feedbackR = rpm_speed_R;
+    
+    mtrL.forceSetSpeed(outputL * dirL);
+    mtrR.forceSetSpeed(outputR * dirR);
 }
 
 /*
@@ -642,45 +463,4 @@
 */
 float clip(float value, float lower, float upper){
     return std::max(lower, std::min(value, upper));
-}
-
-/**************************WEB PAGE TEXT**************************************/
-/*****************************************************************************
-Copy and past text below into a html file and save as the given file name to 
-your SD card.
-
-file name: pid_bot.html
-
-html text:
-
-<!DOCTYPE html>
-<html>
-<head>
-<title>PID RedBot Control</title>
-</head>
-<body>
-<h1>PID Motor Control</h1>
-<h2>PID Status</h2>
-<form title="User Input" method="post">
-PID Controls: <br>
-<input type="radio" name="control_mode" value="0"checked>PID OFF
-<br>
-<input type="radio" name="control_mode" value="1"       >PID ON
-<br>
-Setpoint:<br> 
-<input type="number" name="setpoint_input" value="0000.00" step="0.0000001" size="6"  /><br>
-Proportional Gain: (Good Starting Value: 0.01)<br>
-<input type="number" name="kp_input" value="000.01" step="0.0000001" size="6"  /><br>
-Integral Gain: (Good Starting Value: 0.015)<br>
-<input type="number" name="ki_input" value="00.015" step="0.0000001" size="6"  /><br>
-Derivative Gain: (Good Starting Value: 0.0001)<br>
-<input type="number" name="kd_input" value="0.0001" step="0.0000001" size="6"  /><br>
-<br>
-<input type="submit" value="Update" />
-<input type="submit" name="STOP" value="STOP!" />
-</form>
-</body>
-</html>
-
-*****************************************************************************/
-/*****************************************************************************/
\ No newline at end of file
+}
\ No newline at end of file