WiFi Webserver Robot with PID Motor Control

Dependencies:   HALLFX_ENCODER MotorDriver PID SDFileSystem mbed

Committer:
electromotivated
Date:
Fri Nov 27 15:30:19 2015 +0000
Revision:
0:11bc7a815367
Child:
1:d4a95e3a8aeb
Banishing of a magic number

Who changed what in which revision?

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