PID Motor Position Control using ESP8266 WiFi Module, US Digital E4P-100-079, LMD18200 H-Bridge Break Out, and HN-GH12-1634T 30:1 200RPM Motor

Dependencies:   4DGL-uLCD-SE PID QEI SDFileSystem mbed ESP8266_pid_mtrPos_webserver_SDcard_v2

Dependents:   ESP8266_pid_mtrPos_webserver_SDcard_v2

Committer:
electromotivated
Date:
Wed Nov 25 01:22:14 2015 +0000
Revision:
2:af4befcd02d6
Parent:
1:26a13ee574e9
Child:
3:6067780e2f45
Some more minor comment changes, notably this works well with FireFox but Chrome and Explorer don't seem to play nice... future bug fix;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
electromotivated 0:a2a238159653 1 /*
electromotivated 0:a2a238159653 2 Uses the ESP8266 WiFi Chip to set up a WiFi Webserver used to control
electromotivated 2:af4befcd02d6 3 the position of a motor using a PID controller. USE FIREFOX Web
electromotivated 2:af4befcd02d6 4 Browser
electromotivated 0:a2a238159653 5
electromotivated 2:af4befcd02d6 6 NOTES:
electromotivated 2:af4befcd02d6 7 1. Webpage Handling in this program is specific to a CUSTOM
electromotivated 0:a2a238159653 8 WEBPAGE. Program must be modified to handle specfically a new
electromotivated 0:a2a238159653 9 webpage. A copy of the webpage for this program can be found at
electromotivated 0:a2a238159653 10 the end of this program page. Simply copy and past text into a
electromotivated 0:a2a238159653 11 html file and save as the given name.
electromotivated 0:a2a238159653 12
electromotivated 2:af4befcd02d6 13 2. Developed and tested with FireFox 42.0 Web Browser. Does not seem to work
electromotivated 2:af4befcd02d6 14 well with Google Chrome or Internet Explorer for some reason... they seem
electromotivated 2:af4befcd02d6 15 to generate two post requests which messes with the user input values.
electromotivated 2:af4befcd02d6 16
electromotivated 2:af4befcd02d6 17
electromotivated 0:a2a238159653 18 TODO: ESP8366 has a max packet send size. Make sure we implement
electromotivated 0:a2a238159653 19 a method to send webpages that exceed this value. The max size is
electromotivated 0:a2a238159653 20 listed in the official ESP8266 AT Commands Documentation, I think
electromotivated 0:a2a238159653 21 it is 2048 bytes/chars
electromotivated 0:a2a238159653 22
electromotivated 0:a2a238159653 23 TODO: CREATE CONFIG FUNCTION TO SET SSID, PASSWORD, BAUDRATE ETC.
electromotivated 0:a2a238159653 24
electromotivated 0:a2a238159653 25 TODO: CREATE FUCNTIONS FOR WIFI AND SERVER!!! GET RID OF "MAGIC NUMBER"
electromotivated 0:a2a238159653 26 MAKE THIS AWESOME!!!!
electromotivated 0:a2a238159653 27
electromotivated 0:a2a238159653 28 TODO: COMMENT AND DOCUMENT THE HELL OUT OF THIS PROGRAM!!!
electromotivated 0:a2a238159653 29 */
electromotivated 0:a2a238159653 30
electromotivated 0:a2a238159653 31
electromotivated 0:a2a238159653 32 #include "mbed.h"
electromotivated 0:a2a238159653 33 #include "SDFileSystem.h"
electromotivated 0:a2a238159653 34 #include "PID.h"
electromotivated 0:a2a238159653 35 #include "QEI.h"
electromotivated 0:a2a238159653 36 #include <algorithm>
electromotivated 0:a2a238159653 37
electromotivated 0:a2a238159653 38 /**********WEB SERVER SPECIFIC DECLARTATIONS**********************************/
electromotivated 0:a2a238159653 39 /*****************************************************************************/
electromotivated 0:a2a238159653 40 SDFileSystem sd(p5,p6,p7,p8,"sd"); // MOSI, MISO, SCLK, CS,
electromotivated 0:a2a238159653 41 // Virtual File System Name
electromotivated 0:a2a238159653 42 Serial esp(p13, p14); // tx, rx
electromotivated 0:a2a238159653 43 DigitalOut espRstPin(p26); // ESP Reset
electromotivated 0:a2a238159653 44 DigitalOut led(LED4);
electromotivated 0:a2a238159653 45
electromotivated 0:a2a238159653 46 Timer t1;
electromotivated 0:a2a238159653 47 Timer t2;
electromotivated 0:a2a238159653 48
electromotivated 0:a2a238159653 49 void init(char* buffer, int size);
electromotivated 0:a2a238159653 50 void getreply(int timeout_ms, char* buffer, int size, int numBytes);
electromotivated 0:a2a238159653 51 void startserver(char* buffer, int size);
electromotivated 0:a2a238159653 52 void update_webpage(char* webpage, float setpoint, float kp, float ki, float kd);
electromotivated 0:a2a238159653 53 void parse_input(char* webpage_user_data, float* setpoint, float* kp, float* ki, float* kd);
electromotivated 0:a2a238159653 54 int port =80; // set server port
electromotivated 0:a2a238159653 55 int serverTimeout_secs =5; // set server timeout in seconds in case
electromotivated 0:a2a238159653 56 // link breaks.
electromotivated 0:a2a238159653 57 /*****************************************************************************/
electromotivated 0:a2a238159653 58 /*****************************************************************************/
electromotivated 0:a2a238159653 59
electromotivated 0:a2a238159653 60 /*********PID CONTROLLER SPECIFIC DECLARATIONS********************************/
electromotivated 0:a2a238159653 61 /*****************************************************************************/
electromotivated 0:a2a238159653 62 static float setpoint, feedback, output;
electromotivated 0:a2a238159653 63 const float output_lower_limit = -1.0;
electromotivated 0:a2a238159653 64 const float output_upper_limit = 1.0;
electromotivated 0:a2a238159653 65 const float FEEDBACK_SCALE = 1.0/3000.0; // Scale feedback to 1rev/3000cnts
electromotivated 0:a2a238159653 66 // this is encoder specific.
electromotivated 0:a2a238159653 67 const float setpoint_init = 0.0;
electromotivated 0:a2a238159653 68 const float kp_init = 2.5;
electromotivated 0:a2a238159653 69 const float ki_init = 5.0;
electromotivated 0:a2a238159653 70 const float kd_init = 0.5;
electromotivated 0:a2a238159653 71 const float Ts_init = 0.04; // 25Hz Sample Freq (40ms Sample Time)
electromotivated 0:a2a238159653 72
electromotivated 0:a2a238159653 73 PID pid(&setpoint, &feedback, &output, output_lower_limit, output_upper_limit,
electromotivated 0:a2a238159653 74 kp_init, ki_init, kd_init, Ts_init);
electromotivated 0:a2a238159653 75 QEI encoder(p15, p16);
electromotivated 0:a2a238159653 76 PwmOut mtr_pwm(p25);
electromotivated 0:a2a238159653 77 DigitalOut mtr_dir(p24);
electromotivated 0:a2a238159653 78 void pid_callback(); // Updates encoder feedback and motor output
electromotivated 0:a2a238159653 79 Ticker motor;
electromotivated 0:a2a238159653 80 /*****************************************************************************/
electromotivated 0:a2a238159653 81 /*****************************************************************************/
electromotivated 0:a2a238159653 82
electromotivated 0:a2a238159653 83 // Common Application Declarations
electromotivated 0:a2a238159653 84 Serial pc(USBTX, USBRX);
electromotivated 0:a2a238159653 85 float clip(float value, float lower, float upper);
electromotivated 0:a2a238159653 86
electromotivated 0:a2a238159653 87 int main()
electromotivated 0:a2a238159653 88 {
electromotivated 0:a2a238159653 89 printf("Starting\n");
electromotivated 0:a2a238159653 90
electromotivated 0:a2a238159653 91 /****************** Load Webpage from SD Card***************************************/
electromotivated 0:a2a238159653 92 /***********************************************************************************/
electromotivated 0:a2a238159653 93 char file[] = "/sd/pid_pos.html";
electromotivated 0:a2a238159653 94
electromotivated 0:a2a238159653 95 // Get file size so we can dynamically allocate buffer size
electromotivated 0:a2a238159653 96 int num_chars = 0;
electromotivated 0:a2a238159653 97 FILE *fp = fopen(file, "r");
electromotivated 0:a2a238159653 98 while(!feof(fp)){
electromotivated 0:a2a238159653 99 fgetc(fp);
electromotivated 0:a2a238159653 100 num_chars++;
electromotivated 0:a2a238159653 101 }
electromotivated 0:a2a238159653 102 rewind(fp); // Go to beginning of file
electromotivated 0:a2a238159653 103
electromotivated 0:a2a238159653 104 // printf("Webpage Data Size: %d byte\r\n", num_chars);
electromotivated 0:a2a238159653 105
electromotivated 0:a2a238159653 106 const int WEBPAGE_SIZE = num_chars;
electromotivated 0:a2a238159653 107 char webpage[WEBPAGE_SIZE];
electromotivated 0:a2a238159653 108 webpage[0] = NULL; // Init our array so that element zero contains a null
electromotivated 0:a2a238159653 109 // This is important, ensures strings are placed into
electromotivated 0:a2a238159653 110 // buffer starting at element 0... not some random
electromotivated 0:a2a238159653 111 // elment
electromotivated 0:a2a238159653 112 // Read in and buffer file to memory
electromotivated 0:a2a238159653 113 if(fp == NULL){
electromotivated 0:a2a238159653 114 printf("Error: No Such File or something :(");
electromotivated 0:a2a238159653 115 return 1;
electromotivated 0:a2a238159653 116 }
electromotivated 0:a2a238159653 117 else{
electromotivated 0:a2a238159653 118 while(!feof(fp)){
electromotivated 0:a2a238159653 119 fgets(webpage + strlen(webpage), WEBPAGE_SIZE, fp); // Get a string from stream, add to buffer
electromotivated 0:a2a238159653 120 }
electromotivated 0:a2a238159653 121 }
electromotivated 0:a2a238159653 122 fclose(fp);
electromotivated 0:a2a238159653 123 printf("Webpage Buffer Size: %d bytes\r\n", sizeof(webpage));
electromotivated 0:a2a238159653 124 update_webpage(webpage, setpoint, kp_init, ki_init, kd_init);
electromotivated 0:a2a238159653 125 /***********************************************************************************/
electromotivated 0:a2a238159653 126 /***********************************************************************************/
electromotivated 0:a2a238159653 127
electromotivated 0:a2a238159653 128 /***************BRING UP SERVER*****************************************************/
electromotivated 0:a2a238159653 129 /***********************************************************************************/
electromotivated 0:a2a238159653 130 char buff[5000]; // Working buffer
electromotivated 0:a2a238159653 131 init(buff, sizeof(buff)); // Init ESP8266
electromotivated 0:a2a238159653 132
electromotivated 0:a2a238159653 133 esp.baud(115200); // ESP8266 baudrate. Maximum on KLxx' is 115200, 230400 works on K20 and K22F
electromotivated 0:a2a238159653 134
electromotivated 0:a2a238159653 135 startserver(buff, sizeof(buff)); // Configure the ESP8266 and Setup as Server
electromotivated 0:a2a238159653 136
electromotivated 0:a2a238159653 137 printf(buff); // If start successful buff contains IP address...
electromotivated 0:a2a238159653 138 // if not if contains an error.
electromotivated 0:a2a238159653 139 led =1;
electromotivated 0:a2a238159653 140 /***********************************************************************************/
electromotivated 0:a2a238159653 141 /***********************************************************************************/
electromotivated 0:a2a238159653 142
electromotivated 0:a2a238159653 143 /************Initialize the PID*****************************************************/
electromotivated 0:a2a238159653 144 /***********************************************************************************/
electromotivated 0:a2a238159653 145 // Working paramater variables
electromotivated 0:a2a238159653 146 setpoint = setpoint_init;
electromotivated 1:26a13ee574e9 147 encoder.reset();
electromotivated 0:a2a238159653 148 feedback = encoder.read();
electromotivated 0:a2a238159653 149 float kp = kp_init;
electromotivated 0:a2a238159653 150 float ki = ki_init;
electromotivated 0:a2a238159653 151 float kd = kd_init;
electromotivated 0:a2a238159653 152 pid.set_parameters(kp, ki, kd, Ts_init);
electromotivated 0:a2a238159653 153
electromotivated 0:a2a238159653 154 // Init the motor
electromotivated 0:a2a238159653 155 mtr_dir = 0; // Can be 0 or 1, sets the direction
electromotivated 0:a2a238159653 156 mtr_pwm = 0.0;
electromotivated 0:a2a238159653 157
electromotivated 0:a2a238159653 158 // Clear encoder count
electromotivated 0:a2a238159653 159 encoder.reset();
electromotivated 0:a2a238159653 160
electromotivated 0:a2a238159653 161 // Update sensors and feedback twice as fast as PID sample time
electromotivated 0:a2a238159653 162 // this makes pid react in real-time avoiding errors due to
electromotivated 0:a2a238159653 163 // missing counts etc.
electromotivated 0:a2a238159653 164 motor.attach(&pid_callback, Ts_init/2.0);
electromotivated 0:a2a238159653 165
electromotivated 0:a2a238159653 166 // Start PID sampling
electromotivated 0:a2a238159653 167 pid.start();
electromotivated 0:a2a238159653 168
electromotivated 0:a2a238159653 169 /***********************************************************************************/
electromotivated 0:a2a238159653 170 /***********************************************************************************/
electromotivated 0:a2a238159653 171
electromotivated 0:a2a238159653 172 while(1){
electromotivated 0:a2a238159653 173 /**************SERVICE WEBPAGE******************************************************/
electromotivated 0:a2a238159653 174 /***********************************************************************************/
electromotivated 0:a2a238159653 175 if(esp.readable()){
electromotivated 0:a2a238159653 176 getreply(500, buff, sizeof(buff), sizeof(buff) -1); // Get full buff, leave last element for null char
electromotivated 0:a2a238159653 177 // printf("\r\n*************WORKING BUFFER******************************\r\n");
electromotivated 0:a2a238159653 178 printf(buff); printf("\n");
electromotivated 0:a2a238159653 179 // printf("\r\n**************END WORKING BUFFER**************************\r\n");
electromotivated 0:a2a238159653 180
electromotivated 0:a2a238159653 181 // If Recieved Data get ID, Length, and Data
electromotivated 0:a2a238159653 182 char* rqstPnt = strstr(buff, "+IPD");
electromotivated 0:a2a238159653 183 if(rqstPnt != NULL){
electromotivated 0:a2a238159653 184 int id, len;
electromotivated 0:a2a238159653 185 char type[10]; memset(type, '\0', sizeof(type)); // Create and null out data buff
electromotivated 0:a2a238159653 186 sscanf(rqstPnt, "+IPD,%d,%d:%s ", &id, &len, type);
electromotivated 0:a2a238159653 187 // printf("ID: %i\nLen: %i\nType: %s\n", id, len, type);
electromotivated 0:a2a238159653 188
electromotivated 0:a2a238159653 189 // If GET or POST request "type" parse and update user input then send webpage
electromotivated 0:a2a238159653 190 if(strstr(type, "GET") != NULL || strstr(type, "POST") != NULL){
electromotivated 0:a2a238159653 191 // printf("I got web request\n");
electromotivated 0:a2a238159653 192
electromotivated 0:a2a238159653 193 /* Read Webpage <Form> data sent using "method=POST"...
electromotivated 0:a2a238159653 194 Note: Input elements in the <Form> need a set name attribute to
electromotivated 0:a2a238159653 195 appear in the returned HTML body. Thus to "POST" data ensure:
electromotivated 0:a2a238159653 196 <Form method="POST"> <input type="xxx" name="xxx" value="xxx">
electromotivated 0:a2a238159653 197 <input type="xxx" value="xxx"> </Form>
electromotivated 0:a2a238159653 198 Only the input with name="xxx" will appear in body of HTML
electromotivated 0:a2a238159653 199 */
electromotivated 0:a2a238159653 200 printf("\r\n*************USER INPUT**********************************\r\n");
electromotivated 0:a2a238159653 201 parse_input(buff, &setpoint, &kp, &ki, &kd);
electromotivated 0:a2a238159653 202 setpoint = clip(setpoint, -999.99, 999.99);
electromotivated 0:a2a238159653 203 kp = clip(kp, 0.00, 999.99);
electromotivated 0:a2a238159653 204 ki = clip(ki, 0.00, 999.99);
electromotivated 0:a2a238159653 205 kd = clip(kd, 0.00, 999.99);
electromotivated 0:a2a238159653 206 printf("User Entered: \nSetpoint: %7.2f\nKp: %6.2f\nKi: %6.2f\nKd: %6.2f\n", setpoint, kp, ki, kd);
electromotivated 0:a2a238159653 207 pid.set_parameters(kp, ki, kd, Ts_init); // Updata PID params
electromotivated 0:a2a238159653 208 printf("Updated to Kp: %1.2f Ki: %1.2f Kd: %1.2f Ts: %1.2f\r\n",
electromotivated 0:a2a238159653 209 pid.getKp(), pid.getKi(), pid.getKd(), pid.getTs());
electromotivated 0:a2a238159653 210 printf("Setpoint: %1.2f\r\n", setpoint);
electromotivated 0:a2a238159653 211 printf("Output: %1.2f\r\n", output);
electromotivated 0:a2a238159653 212 printf("\r\n*************END USER INPUT******************************\r\n");
electromotivated 0:a2a238159653 213
electromotivated 0:a2a238159653 214 // Update Webpage to reflect new values POSTED by client
electromotivated 0:a2a238159653 215 static bool isFirstRequest = true;
electromotivated 0:a2a238159653 216 if(!isFirstRequest) update_webpage(webpage, setpoint, kp, ki, kd);
electromotivated 0:a2a238159653 217 else isFirstRequest = false; // First Request just send page with initial values
electromotivated 0:a2a238159653 218 printf(webpage); // DEBUGGING ONLY!!! REMOVE FOR RELEASE!!!
electromotivated 0:a2a238159653 219
electromotivated 0:a2a238159653 220 // Command TCP/IP Data Tx
electromotivated 0:a2a238159653 221 esp.printf("AT+CIPSEND=%d,%d\r\n", id, strlen(webpage));
electromotivated 0:a2a238159653 222 getreply(200, buff, sizeof(buff), 15); /*TODO: Wait for "OK\r\n>"*/
electromotivated 0:a2a238159653 223 // printf(buff); printf("\n");
electromotivated 0:a2a238159653 224
electromotivated 0:a2a238159653 225 // Send webpage
electromotivated 0:a2a238159653 226 // while(!esp.writeable()); // Wait until esp ready to send data
electromotivated 0:a2a238159653 227 int idx = 0;
electromotivated 0:a2a238159653 228 while(webpage[idx] != '\0'){
electromotivated 0:a2a238159653 229 esp.putc(webpage[idx]);
electromotivated 0:a2a238159653 230 idx++;
electromotivated 0:a2a238159653 231 }
electromotivated 0:a2a238159653 232
electromotivated 0:a2a238159653 233 // Check status - Success: close channel and update PID controller, Error: reconnect
electromotivated 0:a2a238159653 234 bool weberror = true;
electromotivated 0:a2a238159653 235 t2.reset(); t2.start();
electromotivated 0:a2a238159653 236 while(weberror ==1 && t2.read_ms() < 5000){
electromotivated 0:a2a238159653 237 getreply(500, buff, sizeof(buff), 24);
electromotivated 0:a2a238159653 238 if(strstr(buff, "SEND OK") != NULL) weberror = false;
electromotivated 0:a2a238159653 239 }
electromotivated 0:a2a238159653 240 if(weberror){
electromotivated 0:a2a238159653 241 esp.printf("AT+CIPMUX=1\r\n");
electromotivated 0:a2a238159653 242 getreply(500, buff, sizeof(buff), 10);
electromotivated 0:a2a238159653 243 // printf(buff); printf("\n");
electromotivated 0:a2a238159653 244
electromotivated 0:a2a238159653 245 esp.printf("AT+CIPSERVER=1,%d\r\n", port);
electromotivated 0:a2a238159653 246 getreply(500, buff, sizeof(buff), 10);
electromotivated 0:a2a238159653 247 // printf(buff); printf("\n");
electromotivated 0:a2a238159653 248 }
electromotivated 0:a2a238159653 249 else{
electromotivated 0:a2a238159653 250 esp.printf("AT+CIPCLOSE=%d\r\n", id); // Notice id is an int formatted to string
electromotivated 0:a2a238159653 251 getreply(500, buff, sizeof(buff), 24);
electromotivated 0:a2a238159653 252 // printf(buff); printf("\n");
electromotivated 0:a2a238159653 253 }
electromotivated 0:a2a238159653 254 }
electromotivated 0:a2a238159653 255 }
electromotivated 0:a2a238159653 256 }
electromotivated 0:a2a238159653 257 /*********************************************************************/
electromotivated 0:a2a238159653 258 /*********************************************************************/
electromotivated 0:a2a238159653 259
electromotivated 0:a2a238159653 260
electromotivated 0:a2a238159653 261 }
electromotivated 0:a2a238159653 262 }
electromotivated 0:a2a238159653 263
electromotivated 0:a2a238159653 264 // Initialize ESP8266
electromotivated 0:a2a238159653 265 void init(char* buffer, int size){
electromotivated 0:a2a238159653 266 // Hardware Reset ESP
electromotivated 0:a2a238159653 267 espRstPin=0;
electromotivated 0:a2a238159653 268 wait(0.5);
electromotivated 0:a2a238159653 269 espRstPin=1;
electromotivated 0:a2a238159653 270 // Get start up junk from ESP8266
electromotivated 0:a2a238159653 271 getreply(6000, buffer, size, 500);
electromotivated 0:a2a238159653 272 }
electromotivated 0:a2a238159653 273
electromotivated 0:a2a238159653 274 // Get Command and ESP status replies
electromotivated 0:a2a238159653 275 void getreply(int timeout_ms, char* buffer, int size, int numBytes)
electromotivated 0:a2a238159653 276 {
electromotivated 0:a2a238159653 277 memset(buffer, '\0', size); // Null out buffer
electromotivated 0:a2a238159653 278 t1.reset();
electromotivated 0:a2a238159653 279 t1.start();
electromotivated 0:a2a238159653 280 int idx = 0;
electromotivated 0:a2a238159653 281 while(t1.read_ms()< timeout_ms && idx < numBytes) {
electromotivated 0:a2a238159653 282 if(esp.readable()) {
electromotivated 0:a2a238159653 283 buffer[idx] = esp.getc();
electromotivated 0:a2a238159653 284 idx++;
electromotivated 0:a2a238159653 285 }
electromotivated 0:a2a238159653 286 }
electromotivated 0:a2a238159653 287 t1.stop();
electromotivated 0:a2a238159653 288 }
electromotivated 0:a2a238159653 289
electromotivated 0:a2a238159653 290 // Starts and restarts webserver if errors detected.
electromotivated 0:a2a238159653 291 void startserver(char* buffer, int size)
electromotivated 0:a2a238159653 292 {
electromotivated 0:a2a238159653 293 esp.printf("AT+RST\r\n"); // BWW: Reset the ESP8266
electromotivated 0:a2a238159653 294 getreply(8000, buffer, size, 1000);
electromotivated 0:a2a238159653 295
electromotivated 0:a2a238159653 296 if (strstr(buffer, "OK") != NULL) {
electromotivated 0:a2a238159653 297 // BWW: Set ESP8266 for multiple connections
electromotivated 0:a2a238159653 298 esp.printf("AT+CIPMUX=1\r\n");
electromotivated 0:a2a238159653 299 getreply(500, buffer, size, 20);
electromotivated 0:a2a238159653 300
electromotivated 0:a2a238159653 301 // BWW: Set ESP8266 as Server on given port
electromotivated 0:a2a238159653 302 esp.printf("AT+CIPSERVER=1,%d\r\n", port);
electromotivated 0:a2a238159653 303 getreply(500, buffer, size, 20); // BWW: Wait for reply
electromotivated 0:a2a238159653 304
electromotivated 0:a2a238159653 305 // wait(1);
electromotivated 0:a2a238159653 306
electromotivated 0:a2a238159653 307 // BWW: Set ESP8266 Server Timeout
electromotivated 0:a2a238159653 308 esp.printf("AT+CIPSTO=%d\r\n", serverTimeout_secs);
electromotivated 0:a2a238159653 309 getreply(500, buffer, size, 50); // BWW: Wait for reply
electromotivated 0:a2a238159653 310
electromotivated 0:a2a238159653 311 // wait(5);
electromotivated 0:a2a238159653 312
electromotivated 0:a2a238159653 313 // BWW: Request IP Address from router for ESP8266
electromotivated 0:a2a238159653 314 int weberror = 0;
electromotivated 0:a2a238159653 315 while(weberror==0) {
electromotivated 0:a2a238159653 316 esp.printf("AT+CIFSR\r\n");
electromotivated 0:a2a238159653 317 getreply(2500, buffer, size, 200);
electromotivated 0:a2a238159653 318 if(strstr(buffer, "0.0.0.0") == NULL) {
electromotivated 0:a2a238159653 319 weberror=1; // wait for valid IP
electromotivated 0:a2a238159653 320 }
electromotivated 0:a2a238159653 321 }
electromotivated 0:a2a238159653 322 }
electromotivated 0:a2a238159653 323 // else ESP8266 did not reply "OK" something is messed up
electromotivated 0:a2a238159653 324 else {
electromotivated 0:a2a238159653 325 strcpy(buffer, "ESP8266 Error\n");
electromotivated 0:a2a238159653 326 }
electromotivated 0:a2a238159653 327 }
electromotivated 0:a2a238159653 328
electromotivated 0:a2a238159653 329 /*
electromotivated 0:a2a238159653 330 update_webpage() updates output fields based on webpage user inputs "POSTED"
electromotivated 0:a2a238159653 331 Preconditions: webpage[] must have the following elements
electromotivated 0:a2a238159653 332 "kp_output" value="xxx.xx"
electromotivated 0:a2a238159653 333 "ki_output" value="xxx.xx"
electromotivated 0:a2a238159653 334 "kp_output" value="xxx.xx"
electromotivated 0:a2a238159653 335 @param webpage Pointer to webpage char[]
electromotivated 0:a2a238159653 336 @param kp New kp value posted by user
electromotivated 0:a2a238159653 337 @param ki New ki value posted by user
electromotivated 0:a2a238159653 338 @param kd New kd value posted by user
electromotivated 0:a2a238159653 339
electromotivated 0:a2a238159653 340 NOTE: THIS IS WEBPAGE SPECIFIC!!!! CHANGE THE CODE IN HERE TO SUITE THE
electromotivated 0:a2a238159653 341 SPECIFIC APPLICATION WEBPAGE!!! ALSO USED TO REFLECT THE CUSTOM
electromotivated 0:a2a238159653 342 IMPLEMENTATION OF THE parse_intput() function. MAKE SURE THESE TWO FUNCTIONS
electromotivated 0:a2a238159653 343 INTEGRATE PROPERLY!!!
electromotivated 0:a2a238159653 344 */
electromotivated 0:a2a238159653 345 void update_webpage(char* webpage, float setpoint, float kp, float ki, float kd){
electromotivated 0:a2a238159653 346 // Change output value to reflect new setpoint kp, ki, kd values
electromotivated 0:a2a238159653 347 char* begin;
electromotivated 0:a2a238159653 348 // char* end;
electromotivated 0:a2a238159653 349 char temp[8];
electromotivated 0:a2a238159653 350 int idx;
electromotivated 0:a2a238159653 351
electromotivated 0:a2a238159653 352 memset(temp, '\0', sizeof(temp));
electromotivated 0:a2a238159653 353 idx = 0;
electromotivated 0:a2a238159653 354 begin = strstr(webpage, "name=\"kp_input\" value=\"") +
electromotivated 0:a2a238159653 355 sizeof("name=\"kp_input\" value="); // Points to start of kp_output field
electromotivated 0:a2a238159653 356 // end = begin + 5; // Points to end of kp_output value
electromotivated 0:a2a238159653 357 // Determine precision of float such temp string has no empty spaces;
electromotivated 0:a2a238159653 358 // i.e. each space must have a value or a decimal point, other wise webbrowser may not recognize value
electromotivated 0:a2a238159653 359 if(kp >= 100) sprintf(temp, "%6.2f", kp); // xxx.00
electromotivated 0:a2a238159653 360 else if(10 <= kp && kp < 100) sprintf(temp, "%6.3f", kp); // xx.000
electromotivated 0:a2a238159653 361 else sprintf(temp, "%6.4f", kp); // x.0000
electromotivated 0:a2a238159653 362 while(temp[idx] != '\0'){ // Overwrite old digits with new digits
electromotivated 0:a2a238159653 363 begin[idx] = temp[idx];
electromotivated 0:a2a238159653 364 idx++;
electromotivated 0:a2a238159653 365 }
electromotivated 0:a2a238159653 366
electromotivated 0:a2a238159653 367 memset(temp, '\0', sizeof(temp));
electromotivated 0:a2a238159653 368 idx = 0;
electromotivated 0:a2a238159653 369 begin = strstr(webpage, "name=\"ki_input\" value=\"") +
electromotivated 0:a2a238159653 370 sizeof("name=\"ki_input\" value="); // Points to start of ki_output field
electromotivated 0:a2a238159653 371 // end = begin + 5; // Points to end of ki_output value
electromotivated 0:a2a238159653 372 if(ki >= 100) sprintf(temp, "%6.2f", ki); // xxx.00
electromotivated 0:a2a238159653 373 else if(10 <= ki && ki < 100) sprintf(temp, "%6.3f", ki); // xx.000
electromotivated 0:a2a238159653 374 else sprintf(temp, "%6.4f", ki); // x.0000
electromotivated 0:a2a238159653 375 while(temp[idx] != '\0'){ // Overwrite old digits with new digits
electromotivated 0:a2a238159653 376 begin[idx] = temp[idx];
electromotivated 0:a2a238159653 377 idx++;
electromotivated 0:a2a238159653 378 }
electromotivated 0:a2a238159653 379
electromotivated 0:a2a238159653 380 memset(temp, '\0', sizeof(temp));
electromotivated 0:a2a238159653 381 idx = 0;
electromotivated 0:a2a238159653 382 begin = strstr(webpage, "name=\"kd_input\" value=\"")+
electromotivated 0:a2a238159653 383 sizeof("name=\"kd_input\" value="); // Points to start of kd_output field
electromotivated 0:a2a238159653 384 // end = begin + 5; // Points to end of kd_output value
electromotivated 0:a2a238159653 385 if(kd >= 100) sprintf(temp, "%6.2f", kd); // xxx.00
electromotivated 0:a2a238159653 386 else if(10 <= kd && kd < 100) sprintf(temp, "%6.3f", kd); // xx.000
electromotivated 0:a2a238159653 387 else sprintf(temp, "%6.4f", kd); // x.0000
electromotivated 0:a2a238159653 388 while(temp[idx] != '\0'){ // Overwrite old digits with new digits
electromotivated 0:a2a238159653 389 begin[idx] = temp[idx];
electromotivated 0:a2a238159653 390 idx++;
electromotivated 0:a2a238159653 391 }
electromotivated 0:a2a238159653 392
electromotivated 0:a2a238159653 393 // Determine precision of float such temp string has no empty spaces;
electromotivated 0:a2a238159653 394 // i.e. each space must have a value or a decimal point or neg sign,
electromotivated 0:a2a238159653 395 // other wise webbrowser may not recognize value
electromotivated 0:a2a238159653 396 memset(temp, '\0', sizeof(temp));
electromotivated 0:a2a238159653 397 idx = 0;
electromotivated 0:a2a238159653 398 begin = strstr(webpage, "name=\"setpoint_input\" value=\"")+
electromotivated 0:a2a238159653 399 sizeof("name=\"setpoint_input\" value="); // Points to start of kp_output field
electromotivated 0:a2a238159653 400 // end = begin + 6; // Points to end of kp_output value. +6 to accomadate negative sign
electromotivated 0:a2a238159653 401 if(setpoint >= 0.00){
electromotivated 0:a2a238159653 402 if(setpoint >= 100) sprintf(temp, "%6.3f", setpoint); // xxx.000
electromotivated 0:a2a238159653 403 else if(10 <= setpoint && setpoint < 100) sprintf(temp, "%7.4f", setpoint); // xx.0000
electromotivated 0:a2a238159653 404 else sprintf(temp, "%6.5f", setpoint); // x.00000
electromotivated 0:a2a238159653 405 }
electromotivated 0:a2a238159653 406 else{
electromotivated 0:a2a238159653 407 if(setpoint <= -100) sprintf(temp, "%6.2f", setpoint); // -xxx.00
electromotivated 0:a2a238159653 408 else if(-100 < setpoint && setpoint <= -10) sprintf(temp, "%6.3f", setpoint); // -xx.000
electromotivated 0:a2a238159653 409 else sprintf(temp, "%6.4f", setpoint); // -x.0000
electromotivated 0:a2a238159653 410 }
electromotivated 0:a2a238159653 411 while(temp[idx] != '\0'){ // Overwrite old digits with new digits
electromotivated 0:a2a238159653 412 begin[idx] = temp[idx];
electromotivated 0:a2a238159653 413 idx++;
electromotivated 0:a2a238159653 414 }
electromotivated 0:a2a238159653 415 }
electromotivated 0:a2a238159653 416
electromotivated 0:a2a238159653 417 /*
electromotivated 0:a2a238159653 418 parse_input() take a char*, in particular a pointer to Webpage User
electromotivated 0:a2a238159653 419 Input Data, for example:
electromotivated 0:a2a238159653 420 char str[] = "+IPD,0,44:kp_input=0.12&ki_input=14.25&kd_input=125.42";
electromotivated 0:a2a238159653 421
electromotivated 0:a2a238159653 422 and parses out the Setpoint Kp, Ki, Kd values that the user entered
electromotivated 0:a2a238159653 423 and posted in the webpage. Values are converted to floats and
electromotivated 0:a2a238159653 424 assigned to the given argurments.
electromotivated 0:a2a238159653 425
electromotivated 0:a2a238159653 426 NOTE: THIS IS WEBPAGE SPECIFIC!!!! CHANGE THE CODE IN HERE TO SUITE THE
electromotivated 0:a2a238159653 427 SPECIFIC APPLICATION WEBPAGE!!! THESE EXTRACTED VALUES WILL BE USED IN
electromotivated 0:a2a238159653 428 THE update_webpage() function. MAKE SURE THESE TWO FUNCTIONS INTEGRATE
electromotivated 0:a2a238159653 429 PROPERLY!!!
electromotivated 0:a2a238159653 430 */
electromotivated 0:a2a238159653 431 void parse_input(char* webpage_user_data,float *setpoint, float* kp, float* ki, float* kd){
electromotivated 0:a2a238159653 432 char keys[] = {'&', '\0'};
electromotivated 0:a2a238159653 433
electromotivated 0:a2a238159653 434 // Parse out user input values
electromotivated 0:a2a238159653 435 char input_buff[50];
electromotivated 0:a2a238159653 436 char* begin;
electromotivated 0:a2a238159653 437 char* end;
electromotivated 0:a2a238159653 438 printf("**************Parsing**************\n");
electromotivated 0:a2a238159653 439 memset(input_buff, '\0', sizeof(input_buff)); // Null out input buff
electromotivated 0:a2a238159653 440 begin = strstr(webpage_user_data, "setpoint_input=") +
electromotivated 0:a2a238159653 441 sizeof("setpoint_input"); // Points to start of setpoint_input value
electromotivated 0:a2a238159653 442 end = begin + strcspn(begin, keys); // Points to end of setpoint_input value
electromotivated 0:a2a238159653 443 for(long i = 0; i < end - begin; i++){ // Parse out the value one char at a time
electromotivated 0:a2a238159653 444 input_buff[i] = begin[i];
electromotivated 0:a2a238159653 445 }
electromotivated 0:a2a238159653 446 printf("Setpoint Parsed Data: %s\n", input_buff);
electromotivated 0:a2a238159653 447 *setpoint = atof(input_buff);
electromotivated 0:a2a238159653 448
electromotivated 0:a2a238159653 449 memset(input_buff, '\0', sizeof(input_buff)); // Null out input buff
electromotivated 0:a2a238159653 450 begin = strstr(webpage_user_data, "kp_input=") +
electromotivated 0:a2a238159653 451 sizeof("kp_input"); // Points to start of kp_input value
electromotivated 0:a2a238159653 452 end = begin + strcspn(begin, keys); // Points to end of kp_input value
electromotivated 0:a2a238159653 453 for(long i = 0; i < end - begin; i++){ // Parse out the value one char at a time
electromotivated 0:a2a238159653 454 input_buff[i] = begin[i];
electromotivated 0:a2a238159653 455 }
electromotivated 0:a2a238159653 456 printf("Kp Parsed Data: %s\n", input_buff);
electromotivated 0:a2a238159653 457 *kp = atof(input_buff);
electromotivated 0:a2a238159653 458
electromotivated 0:a2a238159653 459 memset(input_buff, '\0', sizeof(input_buff)); // Null out input buff
electromotivated 0:a2a238159653 460 begin = strstr(webpage_user_data, "ki_input=") +
electromotivated 0:a2a238159653 461 sizeof("ki_input"); // Points to start of ki_input value
electromotivated 0:a2a238159653 462 end = begin + strcspn(begin, keys); // Points to end of ki_input value
electromotivated 0:a2a238159653 463 for(long i = 0; i < end - begin; i++){ // Parse out the value one char at a time
electromotivated 0:a2a238159653 464 input_buff[i] = begin[i];
electromotivated 0:a2a238159653 465 }
electromotivated 0:a2a238159653 466 printf("Ki Parsed Data: %s\n", input_buff);
electromotivated 0:a2a238159653 467 *ki = atof(input_buff);
electromotivated 0:a2a238159653 468
electromotivated 0:a2a238159653 469 memset(input_buff, '\0', sizeof(input_buff)); // Null out input buff
electromotivated 0:a2a238159653 470 begin = strstr(webpage_user_data, "kd_input=") +
electromotivated 0:a2a238159653 471 sizeof("kd_input"); // Points to start of kd_input value
electromotivated 0:a2a238159653 472 end = begin + strcspn(begin, keys); // Points to end of kd_input value
electromotivated 0:a2a238159653 473 for(long i = 0; i < end - begin; i++){ // Parse out the value one char at a time
electromotivated 0:a2a238159653 474 input_buff[i] = begin[i];
electromotivated 0:a2a238159653 475 }
electromotivated 0:a2a238159653 476 printf("Kd Parsed Data: %s\n", input_buff);
electromotivated 0:a2a238159653 477 *kd = atof(input_buff);
electromotivated 0:a2a238159653 478 printf("**********End Parsing***************\n");
electromotivated 0:a2a238159653 479 }
electromotivated 0:a2a238159653 480
electromotivated 0:a2a238159653 481 void pid_callback(){
electromotivated 0:a2a238159653 482 // Update motor
electromotivated 0:a2a238159653 483 if(output >= 0.0) mtr_dir = 1; // Set direction to sign of output
electromotivated 0:a2a238159653 484 else mtr_dir = 0;
electromotivated 0:a2a238159653 485 mtr_pwm = abs(output); // Apply motor output
electromotivated 0:a2a238159653 486
electromotivated 0:a2a238159653 487 // Update feedback
electromotivated 0:a2a238159653 488 feedback = encoder.read()*FEEDBACK_SCALE;// Scale feedback to num wheel revs
electromotivated 0:a2a238159653 489 }
electromotivated 0:a2a238159653 490
electromotivated 0:a2a238159653 491 /*
electromotivated 0:a2a238159653 492 Clips value to lower/ uppper
electromotivated 0:a2a238159653 493 @param value The value to clip
electromotivated 0:a2a238159653 494 @param lower The mininum allowable value
electromotivated 0:a2a238159653 495 @param upper The maximum allowable value
electromotivated 0:a2a238159653 496 @return The resulting clipped value
electromotivated 0:a2a238159653 497 */
electromotivated 0:a2a238159653 498 float clip(float value, float lower, float upper){
electromotivated 0:a2a238159653 499 return std::max(lower, std::min(value, upper));
electromotivated 0:a2a238159653 500 }
electromotivated 0:a2a238159653 501
electromotivated 0:a2a238159653 502 /**************************WEB PAGE TEXT**************************************/
electromotivated 0:a2a238159653 503 /*****************************************************************************
electromotivated 0:a2a238159653 504 Copy and past text below into a html file and save as the given file name to
electromotivated 0:a2a238159653 505 your SD card.
electromotivated 0:a2a238159653 506
electromotivated 0:a2a238159653 507 file name: pid_pos.html
electromotivated 0:a2a238159653 508
electromotivated 0:a2a238159653 509 html text:
electromotivated 0:a2a238159653 510
electromotivated 0:a2a238159653 511 <!DOCTYPE html>
electromotivated 0:a2a238159653 512 <html>
electromotivated 0:a2a238159653 513 <head>
electromotivated 0:a2a238159653 514 <title>PID Motor Position Control</title>
electromotivated 0:a2a238159653 515 </head>
electromotivated 0:a2a238159653 516 <body>
electromotivated 0:a2a238159653 517 <h1>PID Motor Position Control</h1>
electromotivated 0:a2a238159653 518 <h2>Motor Status</h2>
electromotivated 0:a2a238159653 519 <p>
electromotivated 0:a2a238159653 520 <form title="Motor Status">
electromotivated 0:a2a238159653 521 <input type="text" value="Some user information" size="25" readonly /><br>
electromotivated 0:a2a238159653 522 Current Setpoint:
electromotivated 0:a2a238159653 523 <input type="number" name="current_setpoint" value="0000.00" readonly /><br>
electromotivated 0:a2a238159653 524 Current Position:
electromotivated 0:a2a238159653 525 <input type="number" name="current_position" value="0000.00" readonly /><br>
electromotivated 0:a2a238159653 526 </form>
electromotivated 0:a2a238159653 527 </p>
electromotivated 0:a2a238159653 528 <h2>PID Status</h2>
electromotivated 0:a2a238159653 529 <form title="User Input" method="post">
electromotivated 0:a2a238159653 530 PID Controls: <br>
electromotivated 0:a2a238159653 531 Setpoint:
electromotivated 0:a2a238159653 532 <input type="number" name="setpoint_input" value="0000.00" step="0.01" size="6" /><br>
electromotivated 0:a2a238159653 533 Proportional Gain:
electromotivated 0:a2a238159653 534 <input type="number" name="kp_input" value="002.50" step="0.01" size="6" /><br>
electromotivated 0:a2a238159653 535 Integral Gain:
electromotivated 0:a2a238159653 536 <input type="number" name="ki_input" value="005.00" step="0.01" size="6" /><br>
electromotivated 0:a2a238159653 537 Derivative Gain:
electromotivated 0:a2a238159653 538 <input type="number" name="kd_input" value="000.25" step="0.01" size="6" /><br>
electromotivated 0:a2a238159653 539 <br>
electromotivated 0:a2a238159653 540 <input type="submit" value="Submit" />
electromotivated 0:a2a238159653 541 <input type="submit" name="update" value="Update">
electromotivated 0:a2a238159653 542 <input type="submit" name="estop" value="STOP">
electromotivated 0:a2a238159653 543 </form>
electromotivated 0:a2a238159653 544 </body>
electromotivated 0:a2a238159653 545 </html>
electromotivated 0:a2a238159653 546
electromotivated 0:a2a238159653 547
electromotivated 0:a2a238159653 548 *****************************************************************************/
electromotivated 0:a2a238159653 549 /*****************************************************************************/