├── MPU6050_calibration └── MPU6050_calibration.ino ├── README.md ├── accelerometerTest └── accelerometerTest.ino ├── esp8266Alone.ino ├── esp8266Code └── esp8266Code.ino ├── gyroTest └── gyroTest.ino ├── nanoCode └── nanoCode.ino └── web-interface ├── css └── style.css ├── index.html └── js └── zepto.min.js /MPU6050_calibration/MPU6050_calibration.ino: -------------------------------------------------------------------------------- 1 | // Arduino sketch that returns calibration offsets for MPU6050 // Version 1.1 (31th January 2014) 2 | // Done by Luis Ródenas 3 | // Based on the I2Cdev library and previous work by Jeff Rowberg 4 | // Updates (of the library) should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib 5 | 6 | // These offsets were meant to calibrate MPU6050's internal DMP, but can be also useful for reading sensors. 7 | // The effect of temperature has not been taken into account so I can't promise that it will work if you 8 | // calibrate indoors and then use it outdoors. Best is to calibrate and use at the same room temperature. 9 | 10 | /* ========== LICENSE ================================== 11 | I2Cdev device library code is placed under the MIT license 12 | Copyright (c) 2011 Jeff Rowberg 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy 15 | of this software and associated documentation files (the "Software"), to deal 16 | in the Software without restriction, including without limitation the rights 17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the Software is 19 | furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in 22 | all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | THE SOFTWARE. 31 | ========================================================= 32 | */ 33 | 34 | // I2Cdev and MPU6050 must be installed as libraries 35 | #include "I2Cdev.h" 36 | #include "MPU6050.h" 37 | #include "Wire.h" 38 | 39 | /////////////////////////////////// CONFIGURATION ///////////////////////////// 40 | //Change this 3 variables if you want to fine tune the skecth to your needs. 41 | int buffersize=1000; //Amount of readings used to average, make it higher to get more precision but sketch will be slower (default:1000) 42 | int acel_deadzone=8; //Acelerometer error allowed, make it lower to get more precision, but sketch may not converge (default:8) 43 | int giro_deadzone=1; //Giro error allowed, make it lower to get more precision, but sketch may not converge (default:1) 44 | 45 | // default I2C address is 0x68 46 | // specific I2C addresses may be passed as a parameter here 47 | // AD0 low = 0x68 (default for InvenSense evaluation board) 48 | // AD0 high = 0x69 49 | //MPU6050 accelgyro; 50 | MPU6050 accelgyro(0x68); // <-- use for AD0 high 51 | 52 | int16_t ax, ay, az,gx, gy, gz; 53 | 54 | int mean_ax,mean_ay,mean_az,mean_gx,mean_gy,mean_gz,state=0; 55 | int ax_offset,ay_offset,az_offset,gx_offset,gy_offset,gz_offset; 56 | 57 | /////////////////////////////////// SETUP //////////////////////////////////// 58 | void setup() { 59 | // join I2C bus (I2Cdev library doesn't do this automatically) 60 | Wire.begin(); 61 | // COMMENT NEXT LINE IF YOU ARE USING ARDUINO DUE 62 | TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz). Leonardo measured 250kHz. 63 | 64 | // initialize serial communication 65 | Serial.begin(115200); 66 | 67 | // initialize device 68 | accelgyro.initialize(); 69 | 70 | // wait for ready 71 | while (Serial.available() && Serial.read()); // empty buffer 72 | while (!Serial.available()){ 73 | Serial.println(F("Send any character to start sketch.\n")); 74 | delay(1500); 75 | } 76 | while (Serial.available() && Serial.read()); // empty buffer again 77 | 78 | // start message 79 | Serial.println("\nMPU6050 Calibration Sketch"); 80 | delay(2000); 81 | Serial.println("\nYour MPU6050 should be placed in horizontal position, with package letters facing up. \nDon't touch it until you see a finish message.\n"); 82 | delay(3000); 83 | // verify connection 84 | Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed"); 85 | delay(1000); 86 | // reset offsets 87 | accelgyro.setXAccelOffset(0); 88 | accelgyro.setYAccelOffset(0); 89 | accelgyro.setZAccelOffset(0); 90 | accelgyro.setXGyroOffset(0); 91 | accelgyro.setYGyroOffset(0); 92 | accelgyro.setZGyroOffset(0); 93 | } 94 | 95 | /////////////////////////////////// LOOP //////////////////////////////////// 96 | void loop() { 97 | if (state==0){ 98 | Serial.println("\nReading sensors for first time..."); 99 | meansensors(); 100 | state++; 101 | delay(1000); 102 | } 103 | 104 | if (state==1) { 105 | Serial.println("\nCalculating offsets..."); 106 | calibration(); 107 | state++; 108 | delay(1000); 109 | } 110 | 111 | if (state==2) { 112 | meansensors(); 113 | Serial.println("\nFINISHED!"); 114 | Serial.print("\nSensor readings with offsets:\t"); 115 | Serial.print(mean_ax); 116 | Serial.print("\t"); 117 | Serial.print(mean_ay); 118 | Serial.print("\t"); 119 | Serial.print(mean_az); 120 | Serial.print("\t"); 121 | Serial.print(mean_gx); 122 | Serial.print("\t"); 123 | Serial.print(mean_gy); 124 | Serial.print("\t"); 125 | Serial.println(mean_gz); 126 | Serial.print("Your offsets:\t"); 127 | Serial.print(ax_offset); 128 | Serial.print("\t"); 129 | Serial.print(ay_offset); 130 | Serial.print("\t"); 131 | Serial.print(az_offset); 132 | Serial.print("\t"); 133 | Serial.print(gx_offset); 134 | Serial.print("\t"); 135 | Serial.print(gy_offset); 136 | Serial.print("\t"); 137 | Serial.println(gz_offset); 138 | Serial.println("\nData is printed as: acelX acelY acelZ giroX giroY giroZ"); 139 | Serial.println("Check that your sensor readings are close to 0 0 16384 0 0 0"); 140 | Serial.println("If calibration was succesful write down your offsets so you can set them in your projects using something similar to mpu.setXAccelOffset(youroffset)"); 141 | while (1); 142 | } 143 | } 144 | 145 | /////////////////////////////////// FUNCTIONS //////////////////////////////////// 146 | void meansensors(){ 147 | long i=0,buff_ax=0,buff_ay=0,buff_az=0,buff_gx=0,buff_gy=0,buff_gz=0; 148 | 149 | while (i<(buffersize+101)){ 150 | // read raw accel/gyro measurements from device 151 | accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); 152 | 153 | if (i>100 && i<=(buffersize+100)){ //First 100 measures are discarded 154 | buff_ax=buff_ax+ax; 155 | buff_ay=buff_ay+ay; 156 | buff_az=buff_az+az; 157 | buff_gx=buff_gx+gx; 158 | buff_gy=buff_gy+gy; 159 | buff_gz=buff_gz+gz; 160 | } 161 | if (i==(buffersize+100)){ 162 | mean_ax=buff_ax/buffersize; 163 | mean_ay=buff_ay/buffersize; 164 | mean_az=buff_az/buffersize; 165 | mean_gx=buff_gx/buffersize; 166 | mean_gy=buff_gy/buffersize; 167 | mean_gz=buff_gz/buffersize; 168 | } 169 | i++; 170 | delay(2); //Needed so we don't get repeated measures 171 | } 172 | } 173 | 174 | void calibration(){ 175 | ax_offset=-mean_ax/8; 176 | ay_offset=-mean_ay/8; 177 | az_offset=(16384-mean_az)/8; 178 | 179 | gx_offset=-mean_gx/4; 180 | gy_offset=-mean_gy/4; 181 | gz_offset=-mean_gz/4; 182 | while (1){ 183 | int ready=0; 184 | accelgyro.setXAccelOffset(ax_offset); 185 | accelgyro.setYAccelOffset(ay_offset); 186 | accelgyro.setZAccelOffset(az_offset); 187 | 188 | accelgyro.setXGyroOffset(gx_offset); 189 | accelgyro.setYGyroOffset(gy_offset); 190 | accelgyro.setZGyroOffset(gz_offset); 191 | 192 | meansensors(); 193 | Serial.println("..."); 194 | 195 | if (abs(mean_ax)<=acel_deadzone) ready++; 196 | else ax_offset=ax_offset-mean_ax/acel_deadzone; 197 | 198 | if (abs(mean_ay)<=acel_deadzone) ready++; 199 | else ay_offset=ay_offset-mean_ay/acel_deadzone; 200 | 201 | if (abs(16384-mean_az)<=acel_deadzone) ready++; 202 | else az_offset=az_offset+(16384-mean_az)/acel_deadzone; 203 | 204 | if (abs(mean_gx)<=giro_deadzone) ready++; 205 | else gx_offset=gx_offset-mean_gx/(giro_deadzone+1); 206 | 207 | if (abs(mean_gy)<=giro_deadzone) ready++; 208 | else gy_offset=gy_offset-mean_gy/(giro_deadzone+1); 209 | 210 | if (abs(mean_gz)<=giro_deadzone) ready++; 211 | else gz_offset=gz_offset-mean_gz/(giro_deadzone+1); 212 | 213 | if (ready==6) break; 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # arduino-esp8266-self-balancing-robot 2 | 3 | download and install this library 4 | https://github.com/jrowberg/i2cdevlib 5 | 6 | demonstration here 7 | https://youtu.be/gLAljH-oAIQ 8 | 9 | All instructions here 10 | https://www.instructables.com/id/Self-Balancing-Robot-With-ESP8266-WiFi-PID-Tuning-/ 11 | 12 | To do 13 | 14 | 1. update webpage, add a text field to show pid configured data, remove JS alert. 15 | 16 | 2. robot sometimes goes out of control, need fix 17 | 18 | 3. utilize ESP EEPROM to store configured PID parameters, 19 | -------------------------------------------------------------------------------- /accelerometerTest/accelerometerTest.ino: -------------------------------------------------------------------------------- 1 | #include "Wire.h" 2 | #include "I2Cdev.h" 3 | #include "MPU6050.h" 4 | #include "math.h" 5 | 6 | MPU6050 mpu; 7 | 8 | int16_t accY, accZ; 9 | float accAngle; 10 | 11 | void setup() { 12 | mpu.initialize(); 13 | //-2763 585 1628 -7 33 92 14 | mpu.setXAccelOffset(-2763); 15 | mpu.setYAccelOffset(585); 16 | mpu.setZAccelOffset(1628); 17 | mpu.setXGyroOffset(-7); 18 | mpu.setYGyroOffset(33); 19 | mpu.setZGyroOffset(92); 20 | Serial.begin(115200); 21 | } 22 | 23 | void loop() { 24 | 25 | accZ = mpu.getAccelerationZ(); 26 | accY = mpu.getAccelerationY(); 27 | 28 | accAngle = atan2(accY, accZ)*RAD_TO_DEG; 29 | 30 | if(isnan(accAngle)); 31 | else 32 | Serial.println(accAngle); 33 | } 34 | -------------------------------------------------------------------------------- /esp8266Alone.ino: -------------------------------------------------------------------------------- 1 | //#define AP_MODE 1 2 | #define STA_MODE 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Wire.h" 9 | #include "I2Cdev.h" 10 | #include "MPU6050.h" 11 | #include "math.h" 12 | ESP8266WebServer httpServer(80); 13 | ESP8266HTTPUpdateServer httpUpdater; 14 | 15 | #ifdef STA_MODE 16 | #include 17 | #include //https://github.com/tzapu/WiFiManager 18 | #include "Adafruit_MQTT.h" 19 | #include "Adafruit_MQTT_Client.h" 20 | WiFiClient client; 21 | #define AIO_SERVER "io.adafruit.com" 22 | #define AIO_SERVERPORT 1883 // use 8883 for SSL 23 | #define AIO_USERNAME "programmer5" //your adafruit IO user name 24 | #define AIO_KEY "16d6fbd3ac9944e4823cdae46e5348e6" //your adafruit IO key 25 | Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY); 26 | Adafruit_MQTT_Publish espIp = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/espIP"); 27 | void MQTT_connect() { 28 | if (mqtt.connected()) { 29 | return; 30 | } 31 | mqtt.connect(); 32 | delay(1000); 33 | } 34 | #endif 35 | 36 | 37 | float Kp= 55; 38 | float Kd= -0.5 ; 39 | float Ki= 70; 40 | float targetAngle = -0.35; 41 | const char jquery_js[] PROGMEM={"var Zepto=function(){function L(t){return null==t?String(t):j[S.call(t)]||\"object\"}function Z(t){return\"function\"==L(t)}function _(t){return null!=t&&t==t.window}function $(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function D(t){return\"object\"==L(t)}function M(t){return D(t)&&!_(t)&&Object.getPrototypeOf(t)==Object.prototype}function R(t){return\"number\"==typeof t.length}function k(t){return s.call(t,function(t){return null!=t})}function z(t){return t.length>0?n.fn.concat.apply([],t):t}function F(t){return t.replace(/::/g,\"/\").replace(/([A-Z]+)([A-Z][a-z])/g,\"$1_$2\").replace(/([a-z\\d])([A-Z])/g,\"$1_$2\").replace(/_/g,\"-\").toLowerCase()}function q(t){return t in f?f[t]:f[t]=new RegExp(\"(^|\\\\s)\"+t+\"(\\\\s|$)\")}function H(t,e){return\"number\"!=typeof e||c[F(t)]?e:e+\"px\"}function I(t){var e,n;return u[t]||(e=a.createElement(t),a.body.appendChild(e),n=getComputedStyle(e,\"\").getPropertyValue(\"display\"),e.parentNode.removeChild(e),\"none\"==n&&(n=\"block\"),u[t]=n),u[t]}function V(t){return\"children\"in t?o.call(t.children):n.map(t.childNodes,function(t){return 1==t.nodeType?t:void 0})}function B(n,i,r){for(e in i)r&&(M(i[e])||A(i[e]))?(M(i[e])&&!M(n[e])&&(n[e]={}),A(i[e])&&!A(n[e])&&(n[e]=[]),B(n[e],i[e],r)):i[e]!==t&&(n[e]=i[e])}function U(t,e){return null==e?n(t):n(t).filter(e)}function J(t,e,n,i){return Z(e)?e.call(t,n,i):e}function X(t,e,n){null==n?t.removeAttribute(e):t.setAttribute(e,n)}function W(e,n){var i=e.className||\"\",r=i&&i.baseVal!==t;return n===t?r?i.baseVal:i:void(r?i.baseVal=n:e.className=n)}function Y(t){try{return t?\"true\"==t||(\"false\"==t?!1:\"null\"==t?null:+t+\"\"==t?+t:/^[\\[\\{]/.test(t)?n.parseJSON(t):t):t}catch(e){return t}}function G(t,e){e(t);for(var n=0,i=t.childNodes.length;i>n;n++)G(t.childNodes[n],e)}var t,e,n,i,C,N,r=[],o=r.slice,s=r.filter,a=window.document,u={},f={},c={\"column-count\":1,columns:1,\"font-weight\":1,\"line-height\":1,opacity:1,\"z-index\":1,zoom:1},l=/^\\s*<(\\w+|!)[^>]*>/,h=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/,p=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,d=/^(?:body|html)$/i,m=/([A-Z])/g,g=[\"val\",\"css\",\"html\",\"text\",\"data\",\"width\",\"height\",\"offset\"],v=[\"after\",\"prepend\",\"before\",\"append\"],y=a.createElement(\"table\"),x=a.createElement(\"tr\"),b={tr:a.createElement(\"tbody\"),tbody:y,thead:y,tfoot:y,td:x,th:x,\"*\":a.createElement(\"div\")},w=/complete|loaded|interactive/,E=/^[\\w-]*$/,j={},S=j.toString,T={},O=a.createElement(\"div\"),P={tabindex:\"tabIndex\",readonly:\"readOnly\",\"for\":\"htmlFor\",\"class\":\"className\",maxlength:\"maxLength\",cellspacing:\"cellSpacing\",cellpadding:\"cellPadding\",rowspan:\"rowSpan\",colspan:\"colSpan\",usemap:\"useMap\",frameborder:\"frameBorder\",contenteditable:\"contentEditable\"},A=Array.isArray||function(t){return t instanceof Array};return T.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var i,r=t.parentNode,o=!r;return o&&(r=O).appendChild(t),i=~T.qsa(r,e).indexOf(t),o&&O.removeChild(t),i},C=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():\"\"})},N=function(t){return s.call(t,function(e,n){return t.indexOf(e)==n})},T.fragment=function(e,i,r){var s,u,f;return h.test(e)&&(s=n(a.createElement(RegExp.$1))),s||(e.replace&&(e=e.replace(p,\"<$1>\")),i===t&&(i=l.test(e)&&RegExp.$1),i in b||(i=\"*\"),f=b[i],f.innerHTML=\"\"+e,s=n.each(o.call(f.childNodes),function(){f.removeChild(this)})),M(r)&&(u=n(s),n.each(r,function(t,e){g.indexOf(t)>-1?u[t](e):u.attr(t,e)})),s},T.Z=function(t,e){return t=t||[],t.__proto__=n.fn,t.selector=e||\"\",t},T.isZ=function(t){return t instanceof T.Z},T.init=function(e,i){var r;if(!e)return T.Z();if(\"string\"==typeof e)if(e=e.trim(),\"<\"==e[0]&&l.test(e))r=T.fragment(e,RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=T.qsa(a,e)}else{if(Z(e))return n(a).ready(e);if(T.isZ(e))return e;if(A(e))r=k(e);else if(D(e))r=[e],e=null;else if(l.test(e))r=T.fragment(e.trim(),RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=T.qsa(a,e)}}return T.Z(r,e)},n=function(t,e){return T.init(t,e)},n.extend=function(t){var e,n=o.call(arguments,1);return\"boolean\"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){B(t,n,e)}),t},T.qsa=function(t,e){var n,i=\"#\"==e[0],r=!i&&\".\"==e[0],s=i||r?e.slice(1):e,a=E.test(s);return $(t)&&a&&i?(n=t.getElementById(s))?[n]:[]:1!==t.nodeType&&9!==t.nodeType?[]:o.call(a&&!i?r?t.getElementsByClassName(s):t.getElementsByTagName(e):t.querySelectorAll(e))},n.contains=a.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},n.type=L,n.isFunction=Z,n.isWindow=_,n.isArray=A,n.isPlainObject=M,n.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},n.inArray=function(t,e,n){return r.indexOf.call(e,t,n)},n.camelCase=C,n.trim=function(t){return null==t?\"\":String.prototype.trim.call(t)},n.uuid=0,n.support={},n.expr={},n.map=function(t,e){var n,r,o,i=[];if(R(t))for(r=0;r=0?e:e+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return r.every.call(this,function(e,n){return t.call(e,n,e)!==!1}),this},filter:function(t){return Z(t)?this.not(this.not(t)):n(s.call(this,function(e){return T.matches(e,t)}))},add:function(t,e){return n(N(this.concat(n(t,e))))},is:function(t){return this.length>0&&T.matches(this[0],t)},not:function(e){var i=[];if(Z(e)&&e.call!==t)this.each(function(t){e.call(this,t)||i.push(this)});else{var r=\"string\"==typeof e?this.filter(e):R(e)&&Z(e.item)?o.call(e):n(e);this.forEach(function(t){r.indexOf(t)<0&&i.push(t)})}return n(i)},has:function(t){return this.filter(function(){return D(t)?n.contains(this,t):n(this).find(t).size()})},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!D(t)?t:n(t)},last:function(){var t=this[this.length-1];return t&&!D(t)?t:n(t)},find:function(t){var e,i=this;return e=t?\"object\"==typeof t?n(t).filter(function(){var t=this;return r.some.call(i,function(e){return n.contains(e,t)})}):1==this.length?n(T.qsa(this[0],t)):this.map(function(){return T.qsa(this,t)}):n()},closest:function(t,e){var i=this[0],r=!1;for(\"object\"==typeof t&&(r=n(t));i&&!(r?r.indexOf(i)>=0:T.matches(i,t));)i=i!==e&&!$(i)&&i.parentNode;return n(i)},parents:function(t){for(var e=[],i=this;i.length>0;)i=n.map(i,function(t){return(t=t.parentNode)&&!$(t)&&e.indexOf(t)<0?(e.push(t),t):void 0});return U(e,t)},parent:function(t){return U(N(this.pluck(\"parentNode\")),t)},children:function(t){return U(this.map(function(){return V(this)}),t)},contents:function(){return this.map(function(){return o.call(this.childNodes)})},siblings:function(t){return U(this.map(function(t,e){return s.call(V(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=\"\"})},pluck:function(t){return n.map(this,function(e){return e[t]})},show:function(){return this.each(function(){\"none\"==this.style.display&&(this.style.display=\"\"),\"none\"==getComputedStyle(this,\"\").getPropertyValue(\"display\")&&(this.style.display=I(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var e=Z(t);if(this[0]&&!e)var i=n(t).get(0),r=i.parentNode||this.length>1;return this.each(function(o){n(this).wrapAll(e?t.call(this,o):r?i.cloneNode(!0):i)})},wrapAll:function(t){if(this[0]){n(this[0]).before(t=n(t));for(var e;(e=t.children()).length;)t=e.first();n(t).append(this)}return this},wrapInner:function(t){var e=Z(t);return this.each(function(i){var r=n(this),o=r.contents(),s=e?t.call(this,i):t;o.length?o.wrapAll(s):r.append(s)})},unwrap:function(){return this.parent().each(function(){n(this).replaceWith(n(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css(\"display\",\"none\")},toggle:function(e){return this.each(function(){var i=n(this);(e===t?\"none\"==i.css(\"display\"):e)?i.show():i.hide()})},prev:function(t){return n(this.pluck(\"previousElementSibling\")).filter(t||\"*\")},next:function(t){return n(this.pluck(\"nextElementSibling\")).filter(t||\"*\")},html:function(t){return 0 in arguments?this.each(function(e){var i=this.innerHTML;n(this).empty().append(J(this,t,e,i))}):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each(function(e){var n=J(this,t,e,this.textContent);this.textContent=null==n?\"\":\"\"+n}):0 in this?this[0].textContent:null},attr:function(n,i){var r;return\"string\"!=typeof n||1 in arguments?this.each(function(t){if(1===this.nodeType)if(D(n))for(e in n)X(this,e,n[e]);else X(this,n,J(this,i,t,this.getAttribute(n)))}):this.length&&1===this[0].nodeType?!(r=this[0].getAttribute(n))&&n in this[0]?this[0][n]:r:t},removeAttr:function(t){return this.each(function(){1===this.nodeType&&t.split(\" \").forEach(function(t){X(this,t)},this)})},prop:function(t,e){return t=P[t]||t,1 in arguments?this.each(function(n){this[t]=J(this,e,n,this[t])}):this[0]&&this[0][t]},data:function(e,n){var i=\"data-\"+e.replace(m,\"-$1\").toLowerCase(),r=1 in arguments?this.attr(i,n):this.attr(i);return null!==r?Y(r):t},val:function(t){return 0 in arguments?this.each(function(e){this.value=J(this,t,e,this.value)}):this[0]&&(this[0].multiple?n(this[0]).find(\"option\").filter(function(){return this.selected}).pluck(\"value\"):this[0].value)},offset:function(t){if(t)return this.each(function(e){var i=n(this),r=J(this,t,e,i.offset()),o=i.offsetParent().offset(),s={top:r.top-o.top,left:r.left-o.left};\"static\"==i.css(\"position\")&&(s.position=\"relative\"),i.css(s)});if(!this.length)return null;var e=this[0].getBoundingClientRect();return{left:e.left+window.pageXOffset,top:e.top+window.pageYOffset,width:Math.round(e.width),height:Math.round(e.height)}},css:function(t,i){if(arguments.length<2){var r,o=this[0];if(!o)return;if(r=getComputedStyle(o,\"\"),\"string\"==typeof t)return o.style[C(t)]||r.getPropertyValue(t);if(A(t)){var s={};return n.each(t,function(t,e){s[e]=o.style[C(e)]||r.getPropertyValue(e)}),s}}var a=\"\";if(\"string\"==L(t))i||0===i?a=F(t)+\":\"+H(t,i):this.each(function(){this.style.removeProperty(F(t))});else for(e in t)t[e]||0===t[e]?a+=F(e)+\":\"+H(e,t[e])+\";\":this.each(function(){this.style.removeProperty(F(e))});return this.each(function(){this.style.cssText+=\";\"+a})},index:function(t){return t?this.indexOf(n(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return t?r.some.call(this,function(t){return this.test(W(t))},q(t)):!1},addClass:function(t){return t?this.each(function(e){if(\"className\"in this){i=[];var r=W(this),o=J(this,t,e,r);o.split(/\\s+/g).forEach(function(t){n(this).hasClass(t)||i.push(t)},this),i.length&&W(this,r+(r?\" \":\"\")+i.join(\" \"))}}):this},removeClass:function(e){return this.each(function(n){if(\"className\"in this){if(e===t)return W(this,\"\");i=W(this),J(this,e,n,i).split(/\\s+/g).forEach(function(t){i=i.replace(q(t),\" \")}),W(this,i.trim())}})},toggleClass:function(e,i){return e?this.each(function(r){var o=n(this),s=J(this,e,r,W(this));s.split(/\\s+/g).forEach(function(e){(i===t?!o.hasClass(e):i)?o.addClass(e):o.removeClass(e)})}):this},scrollTop:function(e){if(this.length){var n=\"scrollTop\"in this[0];return e===t?n?this[0].scrollTop:this[0].pageYOffset:this.each(n?function(){this.scrollTop=e}:function(){this.scrollTo(this.scrollX,e)})}},scrollLeft:function(e){if(this.length){var n=\"scrollLeft\"in this[0];return e===t?n?this[0].scrollLeft:this[0].pageXOffset:this.each(n?function(){this.scrollLeft=e}:function(){this.scrollTo(e,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),i=this.offset(),r=d.test(e[0].nodeName)?{top:0,left:0}:e.offset();return i.top-=parseFloat(n(t).css(\"margin-top\"))||0,i.left-=parseFloat(n(t).css(\"margin-left\"))||0,r.top+=parseFloat(n(e[0]).css(\"border-top-width\"))||0,r.left+=parseFloat(n(e[0]).css(\"border-left-width\"))||0,{top:i.top-r.top,left:i.left-r.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||a.body;t&&!d.test(t.nodeName)&&\"static\"==n(t).css(\"position\");)t=t.offsetParent;return t})}},n.fn.detach=n.fn.remove,[\"width\",\"height\"].forEach(function(e){var i=e.replace(/./,function(t){return t[0].toUpperCase()});n.fn[e]=function(r){var o,s=this[0];return r===t?_(s)?s[\"inner\"+i]:$(s)?s.documentElement[\"scroll\"+i]:(o=this.offset())&&o[e]:this.each(function(t){s=n(this),s.css(e,J(this,r,t,s[e]()))})}}),v.forEach(function(t,e){var i=e%2;n.fn[t]=function(){var t,o,r=n.map(arguments,function(e){return t=L(e),\"object\"==t||\"array\"==t||null==e?e:T.fragment(e)}),s=this.length>1;return r.length<1?this:this.each(function(t,u){o=i?u:u.parentNode,u=0==e?u.nextSibling:1==e?u.firstChild:2==e?u:null;var f=n.contains(a.documentElement,o);r.forEach(function(t){if(s)t=t.cloneNode(!0);else if(!o)return n(t).remove();o.insertBefore(t,u),f&&G(t,function(t){null==t.nodeName||\"SCRIPT\"!==t.nodeName.toUpperCase()||t.type&&\"text/javascript\"!==t.type||t.src||window.eval.call(window,t.innerHTML)})})})},n.fn[i?t+\"To\":\"insert\"+(e?\"Before\":\"After\")]=function(e){return n(e)[t](this),this}}),T.Z.prototype=n.fn,T.uniq=N,T.deserializeValue=Y,n.zepto=T,n}();window.Zepto=Zepto,void 0===window.$&&(window.$=Zepto),function(t){function l(t){return t._zid||(t._zid=e++)}function h(t,e,n,i){if(e=p(e),e.ns)var r=d(e.ns);return(s[l(t)]||[]).filter(function(t){return!(!t||e.e&&t.e!=e.e||e.ns&&!r.test(t.ns)||n&&l(t.fn)!==l(n)||i&&t.sel!=i)})}function p(t){var e=(\"\"+t).split(\".\");return{e:e[0],ns:e.slice(1).sort().join(\" \")}}function d(t){return new RegExp(\"(?:^| )\"+t.replace(\" \",\" .* ?\")+\"(?: |$)\")}function m(t,e){return t.del&&!u&&t.e in f||!!e}function g(t){return c[t]||u&&f[t]||t}function v(e,i,r,o,a,u,f){var h=l(e),d=s[h]||(s[h]=[]);i.split(/\\s/).forEach(function(i){if(\"ready\"==i)return t(document).ready(r);var s=p(i);s.fn=r,s.sel=a,s.e in c&&(r=function(e){var n=e.relatedTarget;return!n||n!==this&&!t.contains(this,n)?s.fn.apply(this,arguments):void 0}),s.del=u;var l=u||r;s.proxy=function(t){if(t=j(t),!t.isImmediatePropagationStopped()){t.data=o;var i=l.apply(e,t._args==n?[t]:[t].concat(t._args));return i===!1&&(t.preventDefault(),t.stopPropagation()),i}},s.i=d.length,d.push(s),\"addEventListener\"in e&&e.addEventListener(g(s.e),s.proxy,m(s,f))})}function y(t,e,n,i,r){var o=l(t);(e||\"\").split(/\\s/).forEach(function(e){h(t,e,n,i).forEach(function(e){delete s[o][e.i],\"removeEventListener\"in t&&t.removeEventListener(g(e.e),e.proxy,m(e,r))})})}function j(e,i){return(i||!e.isDefaultPrevented)&&(i||(i=e),t.each(E,function(t,n){var r=i[t];e[t]=function(){return this[n]=x,r&&r.apply(i,arguments)},e[n]=b}),(i.defaultPrevented!==n?i.defaultPrevented:\"returnValue\"in i?i.returnValue===!1:i.getPreventDefault&&i.getPreventDefault())&&(e.isDefaultPrevented=x)),e}function S(t){var e,i={originalEvent:t};for(e in t)w.test(e)||t[e]===n||(i[e]=t[e]);return j(i,t)}var n,e=1,i=Array.prototype.slice,r=t.isFunction,o=function(t){return\"string\"==typeof t},s={},a={},u=\"onfocusin\"in window,f={focus:\"focusin\",blur:\"focusout\"},c={mouseenter:\"mouseover\",mouseleave:\"mouseout\"};a.click=a.mousedown=a.mouseup=a.mousemove=\"MouseEvents\",t.event={add:v,remove:y},t.proxy=function(e,n){var s=2 in arguments&&i.call(arguments,2);if(r(e)){var a=function(){return e.apply(n,s?s.concat(i.call(arguments)):arguments)};return a._zid=l(e),a}if(o(n))return s?(s.unshift(e[n],e),t.proxy.apply(null,s)):t.proxy(e[n],e);throw new TypeError(\"expected function\")},t.fn.bind=function(t,e,n){return this.on(t,e,n)},t.fn.unbind=function(t,e){return this.off(t,e)},t.fn.one=function(t,e,n,i){return this.on(t,e,n,i,1)};var x=function(){return!0},b=function(){return!1},w=/^([A-Z]|returnValue$|layer[XY]$)/,E={preventDefault:\"isDefaultPrevented\",stopImmediatePropagation:\"isImmediatePropagationStopped\",stopPropagation:\"isPropagationStopped\"};t.fn.delegate=function(t,e,n){return this.on(e,t,n)},t.fn.undelegate=function(t,e,n){return this.off(e,t,n)},t.fn.live=function(e,n){return t(document.body).delegate(this.selector,e,n),this},t.fn.die=function(e,n){return t(document.body).undelegate(this.selector,e,n),this},t.fn.on=function(e,s,a,u,f){var c,l,h=this;return e&&!o(e)?(t.each(e,function(t,e){h.on(t,s,a,e,f)}),h):(o(s)||r(u)||u===!1||(u=a,a=s,s=n),(r(a)||a===!1)&&(u=a,a=n),u===!1&&(u=b),h.each(function(n,r){f&&(c=function(t){return y(r,t.type,u),u.apply(this,arguments)}),s&&(l=function(e){var n,o=t(e.target).closest(s,r).get(0);return o&&o!==r?(n=t.extend(S(e),{currentTarget:o,liveFired:r}),(c||u).apply(o,[n].concat(i.call(arguments,1)))):void 0}),v(r,e,u,a,s,l||c)}))},t.fn.off=function(e,i,s){var a=this;return e&&!o(e)?(t.each(e,function(t,e){a.off(t,i,e)}),a):(o(i)||r(s)||s===!1||(s=i,i=n),s===!1&&(s=b),a.each(function(){y(this,e,s,i)}))},t.fn.trigger=function(e,n){return e=o(e)||t.isPlainObject(e)?t.Event(e):j(e),e._args=n,this.each(function(){e.type in f&&\"function\"==typeof this[e.type]?this[e.type]():\"dispatchEvent\"in this?this.dispatchEvent(e):t(this).triggerHandler(e,n)})},t.fn.triggerHandler=function(e,n){var i,r;return this.each(function(s,a){i=S(o(e)?t.Event(e):e),i._args=n,i.target=a,t.each(h(a,e.type||e),function(t,e){return r=e.proxy(i),i.isImmediatePropagationStopped()?!1:void 0})}),r},\"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error\".split(\" \").forEach(function(e){t.fn[e]=function(t){return 0 in arguments?this.bind(e,t):this.trigger(e)}}),t.Event=function(t,e){o(t)||(e=t,t=e.type);var n=document.createEvent(a[t]||\"Events\"),i=!0;if(e)for(var r in e)\"bubbles\"==r?i=!!e[r]:n[r]=e[r];return n.initEvent(t,i,!0),j(n)}}(Zepto),function(t){function h(e,n,i){var r=t.Event(n);return t(e).trigger(r,i),!r.isDefaultPrevented()}function p(t,e,i,r){return t.global?h(e||n,i,r):void 0}function d(e){e.global&&0===t.active++&&p(e,null,\"ajaxStart\")}function m(e){e.global&&!--t.active&&p(e,null,\"ajaxStop\")}function g(t,e){var n=e.context;return e.beforeSend.call(n,t,e)===!1||p(e,n,\"ajaxBeforeSend\",[t,e])===!1?!1:void p(e,n,\"ajaxSend\",[t,e])}function v(t,e,n,i){var r=n.context,o=\"success\";n.success.call(r,t,o,e),i&&i.resolveWith(r,[t,o,e]),p(n,r,\"ajaxSuccess\",[e,n,t]),x(o,e,n)}function y(t,e,n,i,r){var o=i.context;i.error.call(o,n,e,t),r&&r.rejectWith(o,[n,e,t]),p(i,o,\"ajaxError\",[n,i,t||e]),x(e,n,i)}function x(t,e,n){var i=n.context;n.complete.call(i,e,t),p(n,i,\"ajaxComplete\",[e,n]),m(n)}function b(){}function w(t){return t&&(t=t.split(\";\",2)[0]),t&&(t==f?\"html\":t==u?\"json\":s.test(t)?\"script\":a.test(t)&&\"xml\")||\"text\"}function E(t,e){return\"\"==e?t:(t+\"&\"+e).replace(/[&?]{1,2}/,\"?\")}function j(e){e.processData&&e.data&&\"string\"!=t.type(e.data)&&(e.data=t.param(e.data,e.traditional)),!e.data||e.type&&\"GET\"!=e.type.toUpperCase()||(e.url=E(e.url,e.data),e.data=void 0)}function S(e,n,i,r){return t.isFunction(n)&&(r=i,i=n,n=void 0),t.isFunction(i)||(r=i,i=void 0),{url:e,data:n,success:i,dataType:r}}function C(e,n,i,r){var o,s=t.isArray(n),a=t.isPlainObject(n);t.each(n,function(n,u){o=t.type(u),r&&(n=i?r:r+\"[\"+(a||\"object\"==o||\"array\"==o?n:\"\")+\"]\"),!r&&s?e.add(u.name,u.value):\"array\"==o||!i&&\"object\"==o?C(e,u,i,n):e.add(n,u)})}var i,r,e=0,n=window.document,o=/)<[^<]*)*<\\/script>/gi,s=/^(?:text|application)\\/javascript/i,a=/^(?:text|application)\\/xml/i,u=\"application/json\",f=\"text/html\",c=/^\\s*$/,l=n.createElement(\"a\");l.href=window.location.href,t.active=0,t.ajaxJSONP=function(i,r){if(!(\"type\"in i))return t.ajax(i);var f,h,o=i.jsonpCallback,s=(t.isFunction(o)?o():o)||\"jsonp\"+ ++e,a=n.createElement(\"script\"),u=window[s],c=function(e){t(a).triggerHandler(\"error\",e||\"abort\")},l={abort:c};return r&&r.promise(l),t(a).on(\"load error\",function(e,n){clearTimeout(h),t(a).off().remove(),\"error\"!=e.type&&f?v(f[0],l,i,r):y(null,n||\"error\",l,i,r),window[s]=u,f&&t.isFunction(u)&&u(f[0]),u=f=void 0}),g(l,i)===!1?(c(\"abort\"),l):(window[s]=function(){f=arguments},a.src=i.url.replace(/\\?(.+)=\\?/,\"?$1=\"+s),n.head.appendChild(a),i.timeout>0&&(h=setTimeout(function(){c(\"timeout\")},i.timeout)),l)},t.ajaxSettings={type:\"GET\",beforeSend:b,success:b,error:b,complete:b,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:\"text/javascript, application/javascript, application/x-javascript\",json:u,xml:\"application/xml, text/xml\",html:f,text:\"text/plain\"},crossDomain:!1,timeout:0,processData:!0,cache:!0},t.ajax=function(e){var a,o=t.extend({},e||{}),s=t.Deferred&&t.Deferred();for(i in t.ajaxSettings)void 0===o[i]&&(o[i]=t.ajaxSettings[i]);d(o),o.crossDomain||(a=n.createElement(\"a\"),a.href=o.url,a.href=a.href,o.crossDomain=l.protocol+\"//\"+l.host!=a.protocol+\"//\"+a.host),o.url||(o.url=window.location.toString()),j(o);var u=o.dataType,f=/\\?.+=\\?/.test(o.url);if(f&&(u=\"jsonp\"),o.cache!==!1&&(e&&e.cache===!0||\"script\"!=u&&\"jsonp\"!=u)||(o.url=E(o.url,\"_=\"+Date.now())),\"jsonp\"==u)return f||(o.url=E(o.url,o.jsonp?o.jsonp+\"=?\":o.jsonp===!1?\"\":\"callback=?\")),t.ajaxJSONP(o,s);var C,h=o.accepts[u],p={},m=function(t,e){p[t.toLowerCase()]=[t,e]},x=/^([\\w-]+:)\\/\\//.test(o.url)?RegExp.$1:window.location.protocol,S=o.xhr(),T=S.setRequestHeader;if(s&&s.promise(S),o.crossDomain||m(\"X-Requested-With\",\"XMLHttpRequest\"),m(\"Accept\",h||\"*/*\"),(h=o.mimeType||h)&&(h.indexOf(\",\")>-1&&(h=h.split(\",\",2)[0]),S.overrideMimeType&&S.overrideMimeType(h)),(o.contentType||o.contentType!==!1&&o.data&&\"GET\"!=o.type.toUpperCase())&&m(\"Content-Type\",o.contentType||\"application/x-www-form-urlencoded\"),o.headers)for(r in o.headers)m(r,o.headers[r]);if(S.setRequestHeader=m,S.onreadystatechange=function(){if(4==S.readyState){S.onreadystatechange=b,clearTimeout(C);var e,n=!1;if(S.status>=200&&S.status<300||304==S.status||0==S.status&&\"file:\"==x){u=u||w(o.mimeType||S.getResponseHeader(\"content-type\")),e=S.responseText;try{\"script\"==u?(1,eval)(e):\"xml\"==u?e=S.responseXML:\"json\"==u&&(e=c.test(e)?null:t.parseJSON(e))}catch(i){n=i}n?y(n,\"parsererror\",S,o,s):v(e,S,o,s)}else y(S.statusText||null,S.status?\"error\":\"abort\",S,o,s)}},g(S,o)===!1)return S.abort(),y(null,\"abort\",S,o,s),S;if(o.xhrFields)for(r in o.xhrFields)S[r]=o.xhrFields[r];var N=\"async\"in o?o.async:!0;S.open(o.type,o.url,N,o.username,o.password);for(r in p)T.apply(S,p[r]);return o.timeout>0&&(C=setTimeout(function(){S.onreadystatechange=b,S.abort(),y(null,\"timeout\",S,o,s)},o.timeout)),S.send(o.data?o.data:null),S},t.get=function(){return t.ajax(S.apply(null,arguments))},t.post=function(){var e=S.apply(null,arguments);return e.type=\"POST\",t.ajax(e)},t.getJSON=function(){var e=S.apply(null,arguments);return e.dataType=\"json\",t.ajax(e)},t.fn.load=function(e,n,i){if(!this.length)return this;var a,r=this,s=e.split(/\\s/),u=S(e,n,i),f=u.success;return s.length>1&&(u.url=s[0],a=s[1]),u.success=function(e){r.html(a?t(\"
\").html(e.replace(o,\"\")).find(a):e),f&&f.apply(r,arguments)},t.ajax(u),this};var T=encodeURIComponent;t.param=function(e,n){var i=[];return i.add=function(e,n){t.isFunction(n)&&(n=n()),null==n&&(n=\"\"),this.push(T(e)+\"=\"+T(n))},C(i,e,n),i.join(\"&\").replace(/%20/g,\"+\")}}(Zepto),function(t){t.fn.serializeArray=function(){var e,n,i=[],r=function(t){return t.forEach?t.forEach(r):void i.push({name:e,value:t})};return this[0]&&t.each(this[0].elements,function(i,o){n=o.type,e=o.name,e&&\"fieldset\"!=o.nodeName.toLowerCase()&&!o.disabled&&\"submit\"!=n&&\"reset\"!=n&&\"button\"!=n&&\"file\"!=n&&(\"radio\"!=n&&\"checkbox\"!=n||o.checked)&&r(t(o).val())}),i},t.fn.serialize=function(){var t=[];return this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+\"=\"+encodeURIComponent(e.value))}),t.join(\"&\")},t.fn.submit=function(e){if(0 in arguments)this.bind(\"submit\",e);else if(this.length){var n=t.Event(\"submit\");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return this}}(Zepto),function(t){\"__proto__\"in{}||t.extend(t.zepto,{Z:function(e,n){return e=e||[],t.extend(e,t.fn),e.selector=n||\"\",e.__Z=!0,e},isZ:function(e){return\"array\"===t.type(e)&&\"__Z\"in e}});try{getComputedStyle(void 0)}catch(e){var n=getComputedStyle;window.getComputedStyle=function(t){try{return n(t)}catch(e){return null}}}}(Zepto);"}; 42 | const char index_html[] PROGMEM={"\n\n\n\n esp\n \n\n \n\n \n\n\n
\n \n \n \n \n\t\t\t\t\n\t\t\t\t\n \n \n \n \n\t\t\t\t\n\t\t\t\t\n \n \n \n \n\t\t\t\t\n\t\t\t\t\n \n \n \n \n \n\t\t\t\t\n\t\t\t\t\n \n \n \n \n\t\t\t\t\n\t\t\t\t\n \n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n \n \n \n\t\t\t\n
ParameterIncrementDecrementvalue
Target Angle \n \n \n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
Kp\n \n\t\t\t\t\n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
Ki\n \n\t\t\t\t\n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
Kd\n \n\t\t\t\t\n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
motor A\n \n\t\t\t\t\n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
motor B\n \n\t\t\t\t\n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
Save\n \n\t\t\t\t
\n
\n\n\n\n"}; 43 | /*********HTML Contents************/ 44 | const char get_root[]="/"; 45 | const char get_index[]="/index.html"; 46 | 47 | /**********JS ***********/ 48 | const char get_jquery_js[]= "/js/zepto.min.js"; 49 | 50 | void handlejQuery(){ 51 | httpServer.send_P ( 200, "application/js", jquery_js); 52 | } 53 | 54 | void handleRoot() { 55 | httpServer.send_P ( 200, "text/html", index_html); 56 | } 57 | void handleTuning(){ 58 | if(httpServer.argName(0).equals("angle")) 59 | { 60 | if(httpServer.arg(0).equals("H")) 61 | { 62 | targetAngle+=0.5; 63 | } 64 | else if(httpServer.arg(0).equals("L")){ 65 | targetAngle-=0.5; 66 | } 67 | else 68 | targetAngle=httpServer.arg(0).toFloat(); 69 | } 70 | else if(httpServer.argName(0).equals("i")) 71 | { 72 | if(httpServer.arg(0).equals("H")) 73 | { 74 | Ki+=0.5; 75 | } 76 | else if(httpServer.arg(0).equals("L")) 77 | { 78 | Ki+=0.5; 79 | } 80 | else 81 | { 82 | Ki=httpServer.arg(0).toFloat(); 83 | } 84 | } 85 | else if(httpServer.argName(0).equals("d")) 86 | { 87 | if(httpServer.arg(0).equals("H")) 88 | { 89 | Kd+=0.01; 90 | } 91 | else if(httpServer.arg(0).equals("L")) 92 | { 93 | Kd+=0.01; 94 | } 95 | else 96 | { 97 | Kd=httpServer.arg(0).toFloat(); 98 | } 99 | } 100 | else if(httpServer.argName(0).equals("p")) 101 | { 102 | if(httpServer.arg(0).equals("H")) 103 | { 104 | Kp+=0.5; 105 | } 106 | else if(httpServer.arg(0).equals("L")) 107 | { 108 | Kp+=0.5; 109 | } 110 | else 111 | { 112 | Kp=httpServer.arg(0).toFloat(); 113 | } 114 | } 115 | /* else if(httpServer.argName(0).equals("da")) 116 | { 117 | if(httpServer.arg(0).equals("H")) 118 | { 119 | motorADutyOffset+=0.1; 120 | } 121 | else if(httpServer.arg(0).equals("L")) 122 | { 123 | motorADutyOffset-=0.1; 124 | } 125 | else 126 | { 127 | motorADutyOffset=httpServer.arg(0).toFloat(); 128 | } 129 | } 130 | else if(httpServer.argName(0).equals("db")) 131 | { 132 | if(httpServer.arg(0).equals("H")) 133 | { 134 | motorBDutyOffset+=0.1; 135 | } 136 | else if(httpServer.arg(0).equals("L")) 137 | { 138 | motorBDutyOffset-=0.1; 139 | } 140 | else { 141 | motorBDutyOffset=httpServer.arg(0).toFloat(); 142 | } 143 | }*/ 144 | else if(httpServer.argName(0).equals("ok")) 145 | { 146 | String response=""; 147 | response+=(" Kp:"); 148 | response+=(Kp); 149 | response+=(" Ki:"); 150 | response+=(Ki); 151 | response+=(" Kd:"); 152 | response+=(Kd); 153 | response+=(" targetAngle:"); 154 | response+=(targetAngle); 155 | /* response+=(" A offset:"); 156 | response+=(motorADutyOffset); 157 | response+=(" B offset:"); 158 | response+=(motorBDutyOffset); 159 | */ httpServer.send ( 200, "text/plain",response); 160 | return; 161 | } 162 | httpServer.send ( 200, "text/plain",""); 163 | } 164 | void handleNotFound() { 165 | String message = "File Not Found\n\n"; 166 | httpServer.send ( 404, "text/plain", message ); 167 | } 168 | 169 | #define MotorPWMPin1 D3 170 | #define MotorPWMPin2 D4 171 | #define sampleTime 0.01 172 | MPU6050 mpu; 173 | int16_t accY, accZ, gyroX; 174 | volatile int motorPower, gyroRate; 175 | volatile float accAngle, gyroAngle, currentAngle, prevAngle=0, error, prevError=0, errorSum=0; 176 | volatile byte count=0; 177 | 178 | void setMotors(int MotorPWM ) { 179 | if(MotorPWM >= 0) { 180 | analogWrite(MotorPWMPin1 , MotorPWM); 181 | analogWrite(MotorPWMPin2 , 0); 182 | } 183 | else { 184 | analogWrite(MotorPWMPin2 , -MotorPWM); 185 | analogWrite(MotorPWMPin1 , 0); 186 | } 187 | } 188 | 189 | void setup() { 190 | pinMode(MotorPWMPin1 , OUTPUT); 191 | pinMode(MotorPWMPin2 , OUTPUT); 192 | setMotors(0); 193 | Serial.begin(115200); 194 | Wire.begin(); 195 | analogWriteRange(255); 196 | #ifdef STA_MODE 197 | WiFiManager wifiManager; 198 | wifiManager.autoConnect("RobotWifiConfig"); 199 | while(!mqtt.connected()) 200 | { 201 | MQTT_connect(); 202 | } 203 | delay(1000); 204 | espIp.publish(WiFi.localIP().toString().c_str() ); 205 | #endif 206 | mpu.initialize(); 207 | mpu.setXAccelOffset(-2816); 208 | mpu.setYAccelOffset(562); 209 | mpu.setZAccelOffset(1633); 210 | mpu.setXGyroOffset(-7); 211 | mpu.setYGyroOffset(33); 212 | mpu.setZGyroOffset(91); 213 | // initialize PID sampling loop 214 | httpUpdater.setup(&httpServer); 215 | httpServer.on (get_index, handleRoot ); 216 | httpServer.on (get_root, handleRoot ); 217 | httpServer.on ("/Tune",handleTuning); 218 | httpServer.on (get_jquery_js,handlejQuery); 219 | httpServer.onNotFound ( handleNotFound ); 220 | httpServer.begin(); 221 | } 222 | unsigned int lastTempUpdate=0; 223 | //sampleTime 224 | unsigned int counter=0; 225 | bool periodicFunc() { 226 | if ((millis() - lastTempUpdate) > (sampleTime*1000)) { 227 | lastTempUpdate=millis(); 228 | accAngle = atan2(accY, accZ)*RAD_TO_DEG; 229 | gyroRate = map(gyroX, -32768, 32767, -250, 250); 230 | gyroAngle = (float)gyroRate*sampleTime; 231 | currentAngle = 0.9934*(prevAngle + gyroAngle) + 0.0066*(accAngle); 232 | // Serial.print("currentAngle :");Serial.println(currentAngle ); 233 | error = currentAngle - targetAngle; 234 | // Serial.print("error:");Serial.println(error); 235 | errorSum = errorSum + error; 236 | errorSum = constrain(errorSum, -300, 300); 237 | // Serial.print("error sum:");Serial.println(errorSum); 238 | //calculate output from P, I and D values 239 | motorPower = Kp*(error) + Ki*(errorSum)*sampleTime - Kd*(currentAngle-prevAngle)/sampleTime; 240 | prevAngle = currentAngle; 241 | motorPower = constrain(motorPower, -255, 255); 242 | // Serial.print("motor power:");Serial.println(motorPower); 243 | setMotors(motorPower ); 244 | counter++; 245 | if(counter%200==0) 246 | { 247 | Serial.print("Angle: "); 248 | Serial.println(currentAngle); 249 | Serial.print("Output: "); 250 | Serial.println(motorPower); 251 | } 252 | } 253 | } 254 | void loop() { 255 | httpServer.handleClient(); 256 | // read acceleration and gyroscope values 257 | accY = mpu.getAccelerationY(); 258 | accZ = mpu.getAccelerationZ(); 259 | gyroX = mpu.getRotationX(); 260 | // set motor power after constraining it 261 | periodicFunc(); 262 | } 263 | 264 | -------------------------------------------------------------------------------- /esp8266Code/esp8266Code.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | const char style_css[] PROGMEM={"* {\n padding: 0;\n margin: 0;\n}\nheader {\n background-color: #27ace5;\n}\nbody {\n font-family: calibri;\n}\nheader h1 {\n text-align: center;\n font-size: 4em;\n color: white;\n padding: 10px;\n}\nheader img {\n width: 110px;\n margin-top: 10px;\n float: left;\n}\nul {\n list-style-type: none;\n margin: 0;\n padding: 0;\n overflow: hidden;\n background-color: #333;\n}\nli {\n float: left;\n}\nli a {\n display: block;\n color: white;\n text-align: center;\n padding: 14px 16px;\n text-decoration: none;\n}\nli a:hover:not(.active) {\n background-color: #111;\n}\n.active {\n background-color: #4CAF50;\n}\ntable {\n border-collapse: collapse;\n width: 100%;\n}\ntable#inputsTable {\n border-collapse: collapse;\n width: 70%;\n}\nth,\ntd {\n text-align: left;\n padding: 8px;\n}\ntr:nth-child(even) {\n background-color: #f2f2f2\n}\nth {\n background-color: #4CAF50;\n color: white;\n}\nsection {\n width: 60%;\n margin: 10px;\n}\n.button {\n display: inline-block;\n padding: 10px 15px;\n font-size: 15px;\n cursor: pointer;\n text-align: center;\n text-decoration: none;\n outline: none;\n color: #fff;\n background-color: #4CAF50;\n border: none;\n border-radius: 15px;\n box-shadow: 0 9px #999;\n}\n.button:hover {\n background-color: #3e8e41\n}\n.button:active {\n background-color: #3e8e41;\n box-shadow: 0 5px #666;\n transform: translateY(4px);\n}\ninput[type=text],\nselect {\n width: 25%;\n padding: 12px 20px;\n margin: 8px 0;\n display: inline-block;\n border: 1px solid #ccc;\n border-radius: 4px;\n box-sizing: border-box;\n}\n.container {\n width: 250px;\n margin: 0;\n text-align: center;\n}\n.gauge {\n width: 250px;\n height: 250px;\n}"}; 7 | const char jquery_js[] PROGMEM={"var Zepto=function(){function L(t){return null==t?String(t):j[S.call(t)]||\"object\"}function Z(t){return\"function\"==L(t)}function _(t){return null!=t&&t==t.window}function $(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function D(t){return\"object\"==L(t)}function M(t){return D(t)&&!_(t)&&Object.getPrototypeOf(t)==Object.prototype}function R(t){return\"number\"==typeof t.length}function k(t){return s.call(t,function(t){return null!=t})}function z(t){return t.length>0?n.fn.concat.apply([],t):t}function F(t){return t.replace(/::/g,\"/\").replace(/([A-Z]+)([A-Z][a-z])/g,\"$1_$2\").replace(/([a-z\\d])([A-Z])/g,\"$1_$2\").replace(/_/g,\"-\").toLowerCase()}function q(t){return t in f?f[t]:f[t]=new RegExp(\"(^|\\\\s)\"+t+\"(\\\\s|$)\")}function H(t,e){return\"number\"!=typeof e||c[F(t)]?e:e+\"px\"}function I(t){var e,n;return u[t]||(e=a.createElement(t),a.body.appendChild(e),n=getComputedStyle(e,\"\").getPropertyValue(\"display\"),e.parentNode.removeChild(e),\"none\"==n&&(n=\"block\"),u[t]=n),u[t]}function V(t){return\"children\"in t?o.call(t.children):n.map(t.childNodes,function(t){return 1==t.nodeType?t:void 0})}function B(n,i,r){for(e in i)r&&(M(i[e])||A(i[e]))?(M(i[e])&&!M(n[e])&&(n[e]={}),A(i[e])&&!A(n[e])&&(n[e]=[]),B(n[e],i[e],r)):i[e]!==t&&(n[e]=i[e])}function U(t,e){return null==e?n(t):n(t).filter(e)}function J(t,e,n,i){return Z(e)?e.call(t,n,i):e}function X(t,e,n){null==n?t.removeAttribute(e):t.setAttribute(e,n)}function W(e,n){var i=e.className||\"\",r=i&&i.baseVal!==t;return n===t?r?i.baseVal:i:void(r?i.baseVal=n:e.className=n)}function Y(t){try{return t?\"true\"==t||(\"false\"==t?!1:\"null\"==t?null:+t+\"\"==t?+t:/^[\\[\\{]/.test(t)?n.parseJSON(t):t):t}catch(e){return t}}function G(t,e){e(t);for(var n=0,i=t.childNodes.length;i>n;n++)G(t.childNodes[n],e)}var t,e,n,i,C,N,r=[],o=r.slice,s=r.filter,a=window.document,u={},f={},c={\"column-count\":1,columns:1,\"font-weight\":1,\"line-height\":1,opacity:1,\"z-index\":1,zoom:1},l=/^\\s*<(\\w+|!)[^>]*>/,h=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/,p=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,d=/^(?:body|html)$/i,m=/([A-Z])/g,g=[\"val\",\"css\",\"html\",\"text\",\"data\",\"width\",\"height\",\"offset\"],v=[\"after\",\"prepend\",\"before\",\"append\"],y=a.createElement(\"table\"),x=a.createElement(\"tr\"),b={tr:a.createElement(\"tbody\"),tbody:y,thead:y,tfoot:y,td:x,th:x,\"*\":a.createElement(\"div\")},w=/complete|loaded|interactive/,E=/^[\\w-]*$/,j={},S=j.toString,T={},O=a.createElement(\"div\"),P={tabindex:\"tabIndex\",readonly:\"readOnly\",\"for\":\"htmlFor\",\"class\":\"className\",maxlength:\"maxLength\",cellspacing:\"cellSpacing\",cellpadding:\"cellPadding\",rowspan:\"rowSpan\",colspan:\"colSpan\",usemap:\"useMap\",frameborder:\"frameBorder\",contenteditable:\"contentEditable\"},A=Array.isArray||function(t){return t instanceof Array};return T.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var i,r=t.parentNode,o=!r;return o&&(r=O).appendChild(t),i=~T.qsa(r,e).indexOf(t),o&&O.removeChild(t),i},C=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():\"\"})},N=function(t){return s.call(t,function(e,n){return t.indexOf(e)==n})},T.fragment=function(e,i,r){var s,u,f;return h.test(e)&&(s=n(a.createElement(RegExp.$1))),s||(e.replace&&(e=e.replace(p,\"<$1>\")),i===t&&(i=l.test(e)&&RegExp.$1),i in b||(i=\"*\"),f=b[i],f.innerHTML=\"\"+e,s=n.each(o.call(f.childNodes),function(){f.removeChild(this)})),M(r)&&(u=n(s),n.each(r,function(t,e){g.indexOf(t)>-1?u[t](e):u.attr(t,e)})),s},T.Z=function(t,e){return t=t||[],t.__proto__=n.fn,t.selector=e||\"\",t},T.isZ=function(t){return t instanceof T.Z},T.init=function(e,i){var r;if(!e)return T.Z();if(\"string\"==typeof e)if(e=e.trim(),\"<\"==e[0]&&l.test(e))r=T.fragment(e,RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=T.qsa(a,e)}else{if(Z(e))return n(a).ready(e);if(T.isZ(e))return e;if(A(e))r=k(e);else if(D(e))r=[e],e=null;else if(l.test(e))r=T.fragment(e.trim(),RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=T.qsa(a,e)}}return T.Z(r,e)},n=function(t,e){return T.init(t,e)},n.extend=function(t){var e,n=o.call(arguments,1);return\"boolean\"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){B(t,n,e)}),t},T.qsa=function(t,e){var n,i=\"#\"==e[0],r=!i&&\".\"==e[0],s=i||r?e.slice(1):e,a=E.test(s);return $(t)&&a&&i?(n=t.getElementById(s))?[n]:[]:1!==t.nodeType&&9!==t.nodeType?[]:o.call(a&&!i?r?t.getElementsByClassName(s):t.getElementsByTagName(e):t.querySelectorAll(e))},n.contains=a.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},n.type=L,n.isFunction=Z,n.isWindow=_,n.isArray=A,n.isPlainObject=M,n.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},n.inArray=function(t,e,n){return r.indexOf.call(e,t,n)},n.camelCase=C,n.trim=function(t){return null==t?\"\":String.prototype.trim.call(t)},n.uuid=0,n.support={},n.expr={},n.map=function(t,e){var n,r,o,i=[];if(R(t))for(r=0;r=0?e:e+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return r.every.call(this,function(e,n){return t.call(e,n,e)!==!1}),this},filter:function(t){return Z(t)?this.not(this.not(t)):n(s.call(this,function(e){return T.matches(e,t)}))},add:function(t,e){return n(N(this.concat(n(t,e))))},is:function(t){return this.length>0&&T.matches(this[0],t)},not:function(e){var i=[];if(Z(e)&&e.call!==t)this.each(function(t){e.call(this,t)||i.push(this)});else{var r=\"string\"==typeof e?this.filter(e):R(e)&&Z(e.item)?o.call(e):n(e);this.forEach(function(t){r.indexOf(t)<0&&i.push(t)})}return n(i)},has:function(t){return this.filter(function(){return D(t)?n.contains(this,t):n(this).find(t).size()})},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!D(t)?t:n(t)},last:function(){var t=this[this.length-1];return t&&!D(t)?t:n(t)},find:function(t){var e,i=this;return e=t?\"object\"==typeof t?n(t).filter(function(){var t=this;return r.some.call(i,function(e){return n.contains(e,t)})}):1==this.length?n(T.qsa(this[0],t)):this.map(function(){return T.qsa(this,t)}):n()},closest:function(t,e){var i=this[0],r=!1;for(\"object\"==typeof t&&(r=n(t));i&&!(r?r.indexOf(i)>=0:T.matches(i,t));)i=i!==e&&!$(i)&&i.parentNode;return n(i)},parents:function(t){for(var e=[],i=this;i.length>0;)i=n.map(i,function(t){return(t=t.parentNode)&&!$(t)&&e.indexOf(t)<0?(e.push(t),t):void 0});return U(e,t)},parent:function(t){return U(N(this.pluck(\"parentNode\")),t)},children:function(t){return U(this.map(function(){return V(this)}),t)},contents:function(){return this.map(function(){return o.call(this.childNodes)})},siblings:function(t){return U(this.map(function(t,e){return s.call(V(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=\"\"})},pluck:function(t){return n.map(this,function(e){return e[t]})},show:function(){return this.each(function(){\"none\"==this.style.display&&(this.style.display=\"\"),\"none\"==getComputedStyle(this,\"\").getPropertyValue(\"display\")&&(this.style.display=I(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var e=Z(t);if(this[0]&&!e)var i=n(t).get(0),r=i.parentNode||this.length>1;return this.each(function(o){n(this).wrapAll(e?t.call(this,o):r?i.cloneNode(!0):i)})},wrapAll:function(t){if(this[0]){n(this[0]).before(t=n(t));for(var e;(e=t.children()).length;)t=e.first();n(t).append(this)}return this},wrapInner:function(t){var e=Z(t);return this.each(function(i){var r=n(this),o=r.contents(),s=e?t.call(this,i):t;o.length?o.wrapAll(s):r.append(s)})},unwrap:function(){return this.parent().each(function(){n(this).replaceWith(n(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css(\"display\",\"none\")},toggle:function(e){return this.each(function(){var i=n(this);(e===t?\"none\"==i.css(\"display\"):e)?i.show():i.hide()})},prev:function(t){return n(this.pluck(\"previousElementSibling\")).filter(t||\"*\")},next:function(t){return n(this.pluck(\"nextElementSibling\")).filter(t||\"*\")},html:function(t){return 0 in arguments?this.each(function(e){var i=this.innerHTML;n(this).empty().append(J(this,t,e,i))}):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each(function(e){var n=J(this,t,e,this.textContent);this.textContent=null==n?\"\":\"\"+n}):0 in this?this[0].textContent:null},attr:function(n,i){var r;return\"string\"!=typeof n||1 in arguments?this.each(function(t){if(1===this.nodeType)if(D(n))for(e in n)X(this,e,n[e]);else X(this,n,J(this,i,t,this.getAttribute(n)))}):this.length&&1===this[0].nodeType?!(r=this[0].getAttribute(n))&&n in this[0]?this[0][n]:r:t},removeAttr:function(t){return this.each(function(){1===this.nodeType&&t.split(\" \").forEach(function(t){X(this,t)},this)})},prop:function(t,e){return t=P[t]||t,1 in arguments?this.each(function(n){this[t]=J(this,e,n,this[t])}):this[0]&&this[0][t]},data:function(e,n){var i=\"data-\"+e.replace(m,\"-$1\").toLowerCase(),r=1 in arguments?this.attr(i,n):this.attr(i);return null!==r?Y(r):t},val:function(t){return 0 in arguments?this.each(function(e){this.value=J(this,t,e,this.value)}):this[0]&&(this[0].multiple?n(this[0]).find(\"option\").filter(function(){return this.selected}).pluck(\"value\"):this[0].value)},offset:function(t){if(t)return this.each(function(e){var i=n(this),r=J(this,t,e,i.offset()),o=i.offsetParent().offset(),s={top:r.top-o.top,left:r.left-o.left};\"static\"==i.css(\"position\")&&(s.position=\"relative\"),i.css(s)});if(!this.length)return null;var e=this[0].getBoundingClientRect();return{left:e.left+window.pageXOffset,top:e.top+window.pageYOffset,width:Math.round(e.width),height:Math.round(e.height)}},css:function(t,i){if(arguments.length<2){var r,o=this[0];if(!o)return;if(r=getComputedStyle(o,\"\"),\"string\"==typeof t)return o.style[C(t)]||r.getPropertyValue(t);if(A(t)){var s={};return n.each(t,function(t,e){s[e]=o.style[C(e)]||r.getPropertyValue(e)}),s}}var a=\"\";if(\"string\"==L(t))i||0===i?a=F(t)+\":\"+H(t,i):this.each(function(){this.style.removeProperty(F(t))});else for(e in t)t[e]||0===t[e]?a+=F(e)+\":\"+H(e,t[e])+\";\":this.each(function(){this.style.removeProperty(F(e))});return this.each(function(){this.style.cssText+=\";\"+a})},index:function(t){return t?this.indexOf(n(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return t?r.some.call(this,function(t){return this.test(W(t))},q(t)):!1},addClass:function(t){return t?this.each(function(e){if(\"className\"in this){i=[];var r=W(this),o=J(this,t,e,r);o.split(/\\s+/g).forEach(function(t){n(this).hasClass(t)||i.push(t)},this),i.length&&W(this,r+(r?\" \":\"\")+i.join(\" \"))}}):this},removeClass:function(e){return this.each(function(n){if(\"className\"in this){if(e===t)return W(this,\"\");i=W(this),J(this,e,n,i).split(/\\s+/g).forEach(function(t){i=i.replace(q(t),\" \")}),W(this,i.trim())}})},toggleClass:function(e,i){return e?this.each(function(r){var o=n(this),s=J(this,e,r,W(this));s.split(/\\s+/g).forEach(function(e){(i===t?!o.hasClass(e):i)?o.addClass(e):o.removeClass(e)})}):this},scrollTop:function(e){if(this.length){var n=\"scrollTop\"in this[0];return e===t?n?this[0].scrollTop:this[0].pageYOffset:this.each(n?function(){this.scrollTop=e}:function(){this.scrollTo(this.scrollX,e)})}},scrollLeft:function(e){if(this.length){var n=\"scrollLeft\"in this[0];return e===t?n?this[0].scrollLeft:this[0].pageXOffset:this.each(n?function(){this.scrollLeft=e}:function(){this.scrollTo(e,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),i=this.offset(),r=d.test(e[0].nodeName)?{top:0,left:0}:e.offset();return i.top-=parseFloat(n(t).css(\"margin-top\"))||0,i.left-=parseFloat(n(t).css(\"margin-left\"))||0,r.top+=parseFloat(n(e[0]).css(\"border-top-width\"))||0,r.left+=parseFloat(n(e[0]).css(\"border-left-width\"))||0,{top:i.top-r.top,left:i.left-r.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||a.body;t&&!d.test(t.nodeName)&&\"static\"==n(t).css(\"position\");)t=t.offsetParent;return t})}},n.fn.detach=n.fn.remove,[\"width\",\"height\"].forEach(function(e){var i=e.replace(/./,function(t){return t[0].toUpperCase()});n.fn[e]=function(r){var o,s=this[0];return r===t?_(s)?s[\"inner\"+i]:$(s)?s.documentElement[\"scroll\"+i]:(o=this.offset())&&o[e]:this.each(function(t){s=n(this),s.css(e,J(this,r,t,s[e]()))})}}),v.forEach(function(t,e){var i=e%2;n.fn[t]=function(){var t,o,r=n.map(arguments,function(e){return t=L(e),\"object\"==t||\"array\"==t||null==e?e:T.fragment(e)}),s=this.length>1;return r.length<1?this:this.each(function(t,u){o=i?u:u.parentNode,u=0==e?u.nextSibling:1==e?u.firstChild:2==e?u:null;var f=n.contains(a.documentElement,o);r.forEach(function(t){if(s)t=t.cloneNode(!0);else if(!o)return n(t).remove();o.insertBefore(t,u),f&&G(t,function(t){null==t.nodeName||\"SCRIPT\"!==t.nodeName.toUpperCase()||t.type&&\"text/javascript\"!==t.type||t.src||window.eval.call(window,t.innerHTML)})})})},n.fn[i?t+\"To\":\"insert\"+(e?\"Before\":\"After\")]=function(e){return n(e)[t](this),this}}),T.Z.prototype=n.fn,T.uniq=N,T.deserializeValue=Y,n.zepto=T,n}();window.Zepto=Zepto,void 0===window.$&&(window.$=Zepto),function(t){function l(t){return t._zid||(t._zid=e++)}function h(t,e,n,i){if(e=p(e),e.ns)var r=d(e.ns);return(s[l(t)]||[]).filter(function(t){return!(!t||e.e&&t.e!=e.e||e.ns&&!r.test(t.ns)||n&&l(t.fn)!==l(n)||i&&t.sel!=i)})}function p(t){var e=(\"\"+t).split(\".\");return{e:e[0],ns:e.slice(1).sort().join(\" \")}}function d(t){return new RegExp(\"(?:^| )\"+t.replace(\" \",\" .* ?\")+\"(?: |$)\")}function m(t,e){return t.del&&!u&&t.e in f||!!e}function g(t){return c[t]||u&&f[t]||t}function v(e,i,r,o,a,u,f){var h=l(e),d=s[h]||(s[h]=[]);i.split(/\\s/).forEach(function(i){if(\"ready\"==i)return t(document).ready(r);var s=p(i);s.fn=r,s.sel=a,s.e in c&&(r=function(e){var n=e.relatedTarget;return!n||n!==this&&!t.contains(this,n)?s.fn.apply(this,arguments):void 0}),s.del=u;var l=u||r;s.proxy=function(t){if(t=j(t),!t.isImmediatePropagationStopped()){t.data=o;var i=l.apply(e,t._args==n?[t]:[t].concat(t._args));return i===!1&&(t.preventDefault(),t.stopPropagation()),i}},s.i=d.length,d.push(s),\"addEventListener\"in e&&e.addEventListener(g(s.e),s.proxy,m(s,f))})}function y(t,e,n,i,r){var o=l(t);(e||\"\").split(/\\s/).forEach(function(e){h(t,e,n,i).forEach(function(e){delete s[o][e.i],\"removeEventListener\"in t&&t.removeEventListener(g(e.e),e.proxy,m(e,r))})})}function j(e,i){return(i||!e.isDefaultPrevented)&&(i||(i=e),t.each(E,function(t,n){var r=i[t];e[t]=function(){return this[n]=x,r&&r.apply(i,arguments)},e[n]=b}),(i.defaultPrevented!==n?i.defaultPrevented:\"returnValue\"in i?i.returnValue===!1:i.getPreventDefault&&i.getPreventDefault())&&(e.isDefaultPrevented=x)),e}function S(t){var e,i={originalEvent:t};for(e in t)w.test(e)||t[e]===n||(i[e]=t[e]);return j(i,t)}var n,e=1,i=Array.prototype.slice,r=t.isFunction,o=function(t){return\"string\"==typeof t},s={},a={},u=\"onfocusin\"in window,f={focus:\"focusin\",blur:\"focusout\"},c={mouseenter:\"mouseover\",mouseleave:\"mouseout\"};a.click=a.mousedown=a.mouseup=a.mousemove=\"MouseEvents\",t.event={add:v,remove:y},t.proxy=function(e,n){var s=2 in arguments&&i.call(arguments,2);if(r(e)){var a=function(){return e.apply(n,s?s.concat(i.call(arguments)):arguments)};return a._zid=l(e),a}if(o(n))return s?(s.unshift(e[n],e),t.proxy.apply(null,s)):t.proxy(e[n],e);throw new TypeError(\"expected function\")},t.fn.bind=function(t,e,n){return this.on(t,e,n)},t.fn.unbind=function(t,e){return this.off(t,e)},t.fn.one=function(t,e,n,i){return this.on(t,e,n,i,1)};var x=function(){return!0},b=function(){return!1},w=/^([A-Z]|returnValue$|layer[XY]$)/,E={preventDefault:\"isDefaultPrevented\",stopImmediatePropagation:\"isImmediatePropagationStopped\",stopPropagation:\"isPropagationStopped\"};t.fn.delegate=function(t,e,n){return this.on(e,t,n)},t.fn.undelegate=function(t,e,n){return this.off(e,t,n)},t.fn.live=function(e,n){return t(document.body).delegate(this.selector,e,n),this},t.fn.die=function(e,n){return t(document.body).undelegate(this.selector,e,n),this},t.fn.on=function(e,s,a,u,f){var c,l,h=this;return e&&!o(e)?(t.each(e,function(t,e){h.on(t,s,a,e,f)}),h):(o(s)||r(u)||u===!1||(u=a,a=s,s=n),(r(a)||a===!1)&&(u=a,a=n),u===!1&&(u=b),h.each(function(n,r){f&&(c=function(t){return y(r,t.type,u),u.apply(this,arguments)}),s&&(l=function(e){var n,o=t(e.target).closest(s,r).get(0);return o&&o!==r?(n=t.extend(S(e),{currentTarget:o,liveFired:r}),(c||u).apply(o,[n].concat(i.call(arguments,1)))):void 0}),v(r,e,u,a,s,l||c)}))},t.fn.off=function(e,i,s){var a=this;return e&&!o(e)?(t.each(e,function(t,e){a.off(t,i,e)}),a):(o(i)||r(s)||s===!1||(s=i,i=n),s===!1&&(s=b),a.each(function(){y(this,e,s,i)}))},t.fn.trigger=function(e,n){return e=o(e)||t.isPlainObject(e)?t.Event(e):j(e),e._args=n,this.each(function(){e.type in f&&\"function\"==typeof this[e.type]?this[e.type]():\"dispatchEvent\"in this?this.dispatchEvent(e):t(this).triggerHandler(e,n)})},t.fn.triggerHandler=function(e,n){var i,r;return this.each(function(s,a){i=S(o(e)?t.Event(e):e),i._args=n,i.target=a,t.each(h(a,e.type||e),function(t,e){return r=e.proxy(i),i.isImmediatePropagationStopped()?!1:void 0})}),r},\"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error\".split(\" \").forEach(function(e){t.fn[e]=function(t){return 0 in arguments?this.bind(e,t):this.trigger(e)}}),t.Event=function(t,e){o(t)||(e=t,t=e.type);var n=document.createEvent(a[t]||\"Events\"),i=!0;if(e)for(var r in e)\"bubbles\"==r?i=!!e[r]:n[r]=e[r];return n.initEvent(t,i,!0),j(n)}}(Zepto),function(t){function h(e,n,i){var r=t.Event(n);return t(e).trigger(r,i),!r.isDefaultPrevented()}function p(t,e,i,r){return t.global?h(e||n,i,r):void 0}function d(e){e.global&&0===t.active++&&p(e,null,\"ajaxStart\")}function m(e){e.global&&!--t.active&&p(e,null,\"ajaxStop\")}function g(t,e){var n=e.context;return e.beforeSend.call(n,t,e)===!1||p(e,n,\"ajaxBeforeSend\",[t,e])===!1?!1:void p(e,n,\"ajaxSend\",[t,e])}function v(t,e,n,i){var r=n.context,o=\"success\";n.success.call(r,t,o,e),i&&i.resolveWith(r,[t,o,e]),p(n,r,\"ajaxSuccess\",[e,n,t]),x(o,e,n)}function y(t,e,n,i,r){var o=i.context;i.error.call(o,n,e,t),r&&r.rejectWith(o,[n,e,t]),p(i,o,\"ajaxError\",[n,i,t||e]),x(e,n,i)}function x(t,e,n){var i=n.context;n.complete.call(i,e,t),p(n,i,\"ajaxComplete\",[e,n]),m(n)}function b(){}function w(t){return t&&(t=t.split(\";\",2)[0]),t&&(t==f?\"html\":t==u?\"json\":s.test(t)?\"script\":a.test(t)&&\"xml\")||\"text\"}function E(t,e){return\"\"==e?t:(t+\"&\"+e).replace(/[&?]{1,2}/,\"?\")}function j(e){e.processData&&e.data&&\"string\"!=t.type(e.data)&&(e.data=t.param(e.data,e.traditional)),!e.data||e.type&&\"GET\"!=e.type.toUpperCase()||(e.url=E(e.url,e.data),e.data=void 0)}function S(e,n,i,r){return t.isFunction(n)&&(r=i,i=n,n=void 0),t.isFunction(i)||(r=i,i=void 0),{url:e,data:n,success:i,dataType:r}}function C(e,n,i,r){var o,s=t.isArray(n),a=t.isPlainObject(n);t.each(n,function(n,u){o=t.type(u),r&&(n=i?r:r+\"[\"+(a||\"object\"==o||\"array\"==o?n:\"\")+\"]\"),!r&&s?e.add(u.name,u.value):\"array\"==o||!i&&\"object\"==o?C(e,u,i,n):e.add(n,u)})}var i,r,e=0,n=window.document,o=/)<[^<]*)*<\\/script>/gi,s=/^(?:text|application)\\/javascript/i,a=/^(?:text|application)\\/xml/i,u=\"application/json\",f=\"text/html\",c=/^\\s*$/,l=n.createElement(\"a\");l.href=window.location.href,t.active=0,t.ajaxJSONP=function(i,r){if(!(\"type\"in i))return t.ajax(i);var f,h,o=i.jsonpCallback,s=(t.isFunction(o)?o():o)||\"jsonp\"+ ++e,a=n.createElement(\"script\"),u=window[s],c=function(e){t(a).triggerHandler(\"error\",e||\"abort\")},l={abort:c};return r&&r.promise(l),t(a).on(\"load error\",function(e,n){clearTimeout(h),t(a).off().remove(),\"error\"!=e.type&&f?v(f[0],l,i,r):y(null,n||\"error\",l,i,r),window[s]=u,f&&t.isFunction(u)&&u(f[0]),u=f=void 0}),g(l,i)===!1?(c(\"abort\"),l):(window[s]=function(){f=arguments},a.src=i.url.replace(/\\?(.+)=\\?/,\"?$1=\"+s),n.head.appendChild(a),i.timeout>0&&(h=setTimeout(function(){c(\"timeout\")},i.timeout)),l)},t.ajaxSettings={type:\"GET\",beforeSend:b,success:b,error:b,complete:b,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:\"text/javascript, application/javascript, application/x-javascript\",json:u,xml:\"application/xml, text/xml\",html:f,text:\"text/plain\"},crossDomain:!1,timeout:0,processData:!0,cache:!0},t.ajax=function(e){var a,o=t.extend({},e||{}),s=t.Deferred&&t.Deferred();for(i in t.ajaxSettings)void 0===o[i]&&(o[i]=t.ajaxSettings[i]);d(o),o.crossDomain||(a=n.createElement(\"a\"),a.href=o.url,a.href=a.href,o.crossDomain=l.protocol+\"//\"+l.host!=a.protocol+\"//\"+a.host),o.url||(o.url=window.location.toString()),j(o);var u=o.dataType,f=/\\?.+=\\?/.test(o.url);if(f&&(u=\"jsonp\"),o.cache!==!1&&(e&&e.cache===!0||\"script\"!=u&&\"jsonp\"!=u)||(o.url=E(o.url,\"_=\"+Date.now())),\"jsonp\"==u)return f||(o.url=E(o.url,o.jsonp?o.jsonp+\"=?\":o.jsonp===!1?\"\":\"callback=?\")),t.ajaxJSONP(o,s);var C,h=o.accepts[u],p={},m=function(t,e){p[t.toLowerCase()]=[t,e]},x=/^([\\w-]+:)\\/\\//.test(o.url)?RegExp.$1:window.location.protocol,S=o.xhr(),T=S.setRequestHeader;if(s&&s.promise(S),o.crossDomain||m(\"X-Requested-With\",\"XMLHttpRequest\"),m(\"Accept\",h||\"*/*\"),(h=o.mimeType||h)&&(h.indexOf(\",\")>-1&&(h=h.split(\",\",2)[0]),S.overrideMimeType&&S.overrideMimeType(h)),(o.contentType||o.contentType!==!1&&o.data&&\"GET\"!=o.type.toUpperCase())&&m(\"Content-Type\",o.contentType||\"application/x-www-form-urlencoded\"),o.headers)for(r in o.headers)m(r,o.headers[r]);if(S.setRequestHeader=m,S.onreadystatechange=function(){if(4==S.readyState){S.onreadystatechange=b,clearTimeout(C);var e,n=!1;if(S.status>=200&&S.status<300||304==S.status||0==S.status&&\"file:\"==x){u=u||w(o.mimeType||S.getResponseHeader(\"content-type\")),e=S.responseText;try{\"script\"==u?(1,eval)(e):\"xml\"==u?e=S.responseXML:\"json\"==u&&(e=c.test(e)?null:t.parseJSON(e))}catch(i){n=i}n?y(n,\"parsererror\",S,o,s):v(e,S,o,s)}else y(S.statusText||null,S.status?\"error\":\"abort\",S,o,s)}},g(S,o)===!1)return S.abort(),y(null,\"abort\",S,o,s),S;if(o.xhrFields)for(r in o.xhrFields)S[r]=o.xhrFields[r];var N=\"async\"in o?o.async:!0;S.open(o.type,o.url,N,o.username,o.password);for(r in p)T.apply(S,p[r]);return o.timeout>0&&(C=setTimeout(function(){S.onreadystatechange=b,S.abort(),y(null,\"timeout\",S,o,s)},o.timeout)),S.send(o.data?o.data:null),S},t.get=function(){return t.ajax(S.apply(null,arguments))},t.post=function(){var e=S.apply(null,arguments);return e.type=\"POST\",t.ajax(e)},t.getJSON=function(){var e=S.apply(null,arguments);return e.dataType=\"json\",t.ajax(e)},t.fn.load=function(e,n,i){if(!this.length)return this;var a,r=this,s=e.split(/\\s/),u=S(e,n,i),f=u.success;return s.length>1&&(u.url=s[0],a=s[1]),u.success=function(e){r.html(a?t(\"
\").html(e.replace(o,\"\")).find(a):e),f&&f.apply(r,arguments)},t.ajax(u),this};var T=encodeURIComponent;t.param=function(e,n){var i=[];return i.add=function(e,n){t.isFunction(n)&&(n=n()),null==n&&(n=\"\"),this.push(T(e)+\"=\"+T(n))},C(i,e,n),i.join(\"&\").replace(/%20/g,\"+\")}}(Zepto),function(t){t.fn.serializeArray=function(){var e,n,i=[],r=function(t){return t.forEach?t.forEach(r):void i.push({name:e,value:t})};return this[0]&&t.each(this[0].elements,function(i,o){n=o.type,e=o.name,e&&\"fieldset\"!=o.nodeName.toLowerCase()&&!o.disabled&&\"submit\"!=n&&\"reset\"!=n&&\"button\"!=n&&\"file\"!=n&&(\"radio\"!=n&&\"checkbox\"!=n||o.checked)&&r(t(o).val())}),i},t.fn.serialize=function(){var t=[];return this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+\"=\"+encodeURIComponent(e.value))}),t.join(\"&\")},t.fn.submit=function(e){if(0 in arguments)this.bind(\"submit\",e);else if(this.length){var n=t.Event(\"submit\");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return this}}(Zepto),function(t){\"__proto__\"in{}||t.extend(t.zepto,{Z:function(e,n){return e=e||[],t.extend(e,t.fn),e.selector=n||\"\",e.__Z=!0,e},isZ:function(e){return\"array\"===t.type(e)&&\"__Z\"in e}});try{getComputedStyle(void 0)}catch(e){var n=getComputedStyle;window.getComputedStyle=function(t){try{return n(t)}catch(e){return null}}}}(Zepto);"}; 8 | const char index_html[] PROGMEM={"\n\n\n\n esp\n \n\n \n\n \n\n\n
\n \n \n \n \n\t\t\t\t\n\t\t\t\t\n \n \n \n \n\t\t\t\t\n\t\t\t\t\n \n \n \n \n\t\t\t\t\n\t\t\t\t\n \n \n \n \n \n\t\t\t\t\n\t\t\t\t\n \n \n \n \n\t\t\t\t\n\t\t\t\t\n \n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n \n \n \n\t\t\t\n
ParameterIncrementDecrementvalue
Target Angle \n \n \n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
Kp\n \n\t\t\t\t\n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
Ki\n \n\t\t\t\t\n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
Kd\n \n\t\t\t\t\n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
motor A\n \n\t\t\t\t\n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
motor B\n \n\t\t\t\t\n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
Save\n \n\t\t\t\t
\n
\n\n\n\n"}; 9 | 10 | const char* ssid = "wifi-robot"; 11 | const char* password = ""; 12 | const char* host = "robot"; 13 | 14 | ESP8266WebServer server(80); 15 | ESP8266HTTPUpdateServer httpUpdater; 16 | 17 | /*********HTML Contents************/ 18 | const char get_root[]="/"; 19 | const char get_index[]="/index.html"; 20 | /********* CSS ************/ 21 | const char get_style[]="/css/style.css"; 22 | 23 | /**********JS ***********/ 24 | const char get_jquery_js[]= "/js/zepto.min.js"; 25 | 26 | int status = WL_IDLE_STATUS; 27 | void handlejQuery(){ 28 | server.send_P ( 200, "application/js", jquery_js); 29 | } 30 | 31 | void handleRoot() { 32 | server.send_P ( 200, "text/html", index_html); 33 | } 34 | 35 | void handleCss() { 36 | server.send_P ( 200, "text/css", style_css); 37 | } 38 | 39 | String pidData=""; 40 | String inputString = ""; // a String to hold incoming data 41 | boolean stringComplete = false; // whether the string is complete 42 | void serialEvent() { 43 | while (Serial.available()) { 44 | // get the new byte: 45 | char inChar = (char)Serial.read(); 46 | // add it to the inputString: 47 | inputString += inChar; 48 | if (inChar == 0x0A) { 49 | stringComplete = true; 50 | pidData=""; 51 | pidData+=inputString; 52 | inputString=""; 53 | } 54 | } 55 | } 56 | 57 | void handleTuning(){ 58 | String someBuffer=""; 59 | Serial.print(server.argName(0)); 60 | Serial.print(":"); 61 | Serial.println(server.arg(0)); 62 | if(stringComplete) 63 | { 64 | stringComplete=false; 65 | server.send ( 200, "text/plain",pidData); 66 | } 67 | else 68 | server.send ( 200, "text/plain",""); 69 | } 70 | void handleNotFound() { 71 | String message = "File Not Found\n\n"; 72 | server.send ( 404, "text/plain", message ); 73 | } 74 | 75 | 76 | void setup ( void ) { 77 | delay(1000); 78 | Serial.begin(115200); 79 | WiFi.softAP(ssid, password); 80 | IPAddress myIP = WiFi.softAPIP(); 81 | server.on (get_index, handleRoot ); 82 | server.on (get_root, handleRoot ); 83 | server.on (get_style, handleCss); 84 | server.on ("/Tune",handleTuning); 85 | server.on (get_jquery_js,handlejQuery); 86 | server.onNotFound ( handleNotFound ); 87 | MDNS.begin(host); 88 | httpUpdater.setup(&server); 89 | server.begin(); 90 | MDNS.addService("http", "tcp", 80); 91 | } 92 | 93 | void loop ( void ) { 94 | server.handleClient(); 95 | serialEvent(); 96 | } 97 | 98 | 99 | -------------------------------------------------------------------------------- /gyroTest/gyroTest.ino: -------------------------------------------------------------------------------- 1 | #include "Wire.h" 2 | #include "I2Cdev.h" 3 | #include "MPU6050.h" 4 | 5 | MPU6050 mpu; 6 | 7 | int16_t gyroX, gyroRate; 8 | float gyroAngle=0; 9 | unsigned long currTime, prevTime=0, loopTime; 10 | 11 | void setup() { 12 | mpu.initialize(); 13 | mpu.setXAccelOffset(-2757); 14 | mpu.setYAccelOffset(588); 15 | mpu.setZAccelOffset(1645); 16 | mpu.setXGyroOffset(-12); 17 | mpu.setYGyroOffset(42); 18 | mpu.setZGyroOffset(93); 19 | Serial.begin(115200); 20 | } 21 | 22 | void loop() { 23 | currTime = millis(); 24 | loopTime = currTime - prevTime; 25 | prevTime = currTime; 26 | 27 | gyroX = mpu.getRotationX(); 28 | gyroRate = map(gyroX, -32768, 32767, -250, 250); 29 | gyroAngle = gyroAngle + (float)gyroRate*loopTime/1000; 30 | 31 | Serial.println(gyroAngle); 32 | } 33 | -------------------------------------------------------------------------------- /nanoCode/nanoCode.ino: -------------------------------------------------------------------------------- 1 | #include "Wire.h" 2 | #include "I2Cdev.h" 3 | #include "MPU6050.h" 4 | #include "math.h" 5 | 6 | #define leftMotorPWMPin 6 7 | #define leftMotorDirPin 11 8 | #define rightMotorPWMPin 5 9 | #define rightMotorDirPin 3 10 | 11 | String inputString = ""; // a String to hold incoming data 12 | boolean stringComplete = false; // whether the string is complete 13 | /* 14 | #define Kp 15 15 | #define Kd 0.13 16 | #define Ki 20 17 | */ 18 | 19 | /* 20 | float Kp= 17.0; 21 | float Kd= 0.05; 22 | float Ki= 22.5; 23 | float targetAngle = 6.0; 24 | */ 25 | /* 26 | float Kp= 32.0; 27 | float Kd= -0.05; 28 | float Ki= 30.5; 29 | float targetAngle = 6.0; 30 | */ 31 | 32 | /* 33 | float Kp= 36.50; 34 | float Kd= -0.15; 35 | float Ki= 30.5; 36 | float targetAngle = 3.0; 37 | */ 38 | /* 39 | float Kp= 25.0; 40 | float Kd= 0; 41 | float Ki= 0; 42 | float targetAngle = 3.0; 43 | */ 44 | 45 | /* 46 | float Kp= 47.50; 47 | float Kd= -0.53; 48 | float Ki= 62.50; 49 | float targetAngle = 0.50; 50 | */ 51 | 52 | 53 | float Kp= 45.0; 54 | float Kd=-0.2 ; 55 | float Ki= 135; 56 | float targetAngle = 1.50; 57 | 58 | float motorADutyOffset=1; 59 | float motorBDutyOffset=1; 60 | 61 | #define sampleTime 0.005 62 | 63 | MPU6050 mpu; 64 | 65 | int16_t accY, accZ, gyroX; 66 | volatile int motorPower, gyroRate; 67 | volatile float accAngle, gyroAngle, currentAngle, prevAngle=0, error, prevError=0, errorSum=0; 68 | volatile byte count=0; 69 | 70 | void setMotors(int leftMotorSpeed, int rightMotorSpeed) { 71 | /* Serial.print(leftMotorSpeed); 72 | Serial.print(":");Serial.print(-leftMotorSpeed); 73 | Serial.print(":"); 74 | Serial.print(rightMotorSpeed); 75 | Serial.print(":"); 76 | Serial.println(-rightMotorSpeed); 77 | */ 78 | if(leftMotorSpeed >= 0) { 79 | analogWrite(leftMotorPWMPin, leftMotorSpeed*motorADutyOffset); 80 | analogWrite(leftMotorDirPin, 0); 81 | } 82 | else { 83 | analogWrite(leftMotorPWMPin,0); 84 | analogWrite(leftMotorDirPin, -leftMotorSpeed*motorADutyOffset); 85 | } 86 | if(rightMotorSpeed >= 0) { 87 | analogWrite(rightMotorPWMPin, rightMotorSpeed*motorBDutyOffset); 88 | analogWrite(rightMotorDirPin, 0); 89 | } 90 | else { 91 | analogWrite(rightMotorPWMPin,0); 92 | analogWrite(rightMotorDirPin, -rightMotorSpeed*motorBDutyOffset); 93 | } 94 | } 95 | 96 | void init_PID() { 97 | // initialize Timer1 98 | cli(); // disable global interrupts 99 | TCCR1A = 0; // set entire TCCR1A register to 0 100 | TCCR1B = 0; // same for TCCR1B 101 | // set compare match register to set sample time 5ms 102 | OCR1A = 9999; 103 | // turn on CTC mode 104 | TCCR1B |= (1 << WGM12); 105 | // Set CS11 bit for prescaling by 8 106 | TCCR1B |= (1 << CS11); 107 | // enable timer compare interrupt 108 | TIMSK1 |= (1 << OCIE1A); 109 | sei(); // enable global interrupts 110 | } 111 | 112 | void setup() { 113 | Serial.begin(115200); 114 | delay(2000); 115 | inputString.reserve(200); 116 | // set the motor control and PWM pins to output mode 117 | pinMode(leftMotorPWMPin, OUTPUT); 118 | pinMode(leftMotorDirPin, OUTPUT); 119 | pinMode(rightMotorPWMPin, OUTPUT); 120 | pinMode(rightMotorDirPin, OUTPUT); 121 | // set the status LED to output mode 122 | pinMode(13, OUTPUT); 123 | // initialize the MPU6050 and set offset values 124 | mpu.initialize(); 125 | mpu.setXAccelOffset(-2816); 126 | mpu.setYAccelOffset(562); 127 | mpu.setZAccelOffset(1633); 128 | mpu.setXGyroOffset(-7); 129 | mpu.setYGyroOffset(33); 130 | mpu.setZGyroOffset(91); 131 | // initialize PID sampling loop 132 | init_PID(); 133 | } 134 | void loop() { 135 | // read acceleration and gyroscope values 136 | accY = mpu.getAccelerationY(); 137 | accZ = mpu.getAccelerationZ(); 138 | gyroX = mpu.getRotationX(); 139 | // set motor power after constraining it 140 | motorPower = constrain(motorPower, -255, 255); 141 | setMotors(motorPower, motorPower); 142 | if (stringComplete) { 143 | if(inputString.equals("angle:H\r\n")) 144 | { 145 | targetAngle+=0.5; 146 | } 147 | else if(inputString.equals("angle:L\r\n")) 148 | { 149 | targetAngle-=0.5; 150 | } 151 | else if(inputString.equals("i:H\r\n")) 152 | { 153 | Ki+=0.5; 154 | } 155 | else if(inputString.equals("i:L\r\n")) 156 | { 157 | Ki-=0.5; 158 | } 159 | else if(inputString.equals("d:H\r\n")) 160 | { 161 | Kd+=0.01; 162 | } 163 | else if(inputString.equals("d:L\r\n")) 164 | { 165 | Kd-=0.01; 166 | } 167 | else if(inputString.equals("p:H\r\n")) 168 | { 169 | Kp+=0.5; 170 | } 171 | else if(inputString.equals("p:L\r\n")) 172 | { 173 | Kp-=0.5; 174 | } 175 | else if(inputString.equals("da:H\r\n")) 176 | { 177 | motorADutyOffset+=1; 178 | } 179 | else if(inputString.equals("da:L\r\n")) 180 | { 181 | motorADutyOffset-=1; 182 | } 183 | else if(inputString.equals("db:H\r\n")) 184 | { 185 | motorBDutyOffset+=1; 186 | } 187 | else if(inputString.equals("db:L\r\n")) 188 | { 189 | motorBDutyOffset-=1; 190 | } 191 | 192 | else if(inputString.indexOf("angle:")!=-1) 193 | { 194 | targetAngle=(inputString.substring(6)).toFloat(); 195 | } 196 | else if(inputString.indexOf("p:")!=-1) 197 | { 198 | Kp=(inputString.substring(2)).toFloat(); 199 | } 200 | else if(inputString.indexOf("d:")!=-1) 201 | { 202 | Kd=(inputString.substring(2)).toFloat(); 203 | } 204 | else if(inputString.indexOf("i:")!=-1) 205 | { 206 | Ki=(inputString.substring(2)).toFloat(); 207 | } 208 | else if(inputString.indexOf("dutyA:")!=-1) 209 | { 210 | motorADutyOffset=(inputString.substring(6)).toFloat(); 211 | } 212 | else if(inputString.indexOf("dutyB:")!=-1) 213 | { 214 | motorBDutyOffset=(inputString.substring(6)).toFloat(); 215 | } 216 | else if(inputString.equals("ok:1\r\n")) 217 | { 218 | Serial.print(" Kp:"); 219 | Serial.print(Kp); 220 | Serial.print(" Ki:"); 221 | Serial.print(Ki); 222 | Serial.print(" Kd:"); 223 | Serial.print(Kd); 224 | Serial.print(" targetAngle:"); 225 | Serial.print(targetAngle); 226 | Serial.print(" A offset:"); 227 | Serial.print(motorADutyOffset); 228 | Serial.print(" B offset:"); 229 | Serial.println(motorBDutyOffset); 230 | } 231 | inputString = ""; 232 | stringComplete = false; 233 | } 234 | } 235 | void serialEvent() { 236 | while (Serial.available()) { 237 | // get the new byte: 238 | char inChar = (char)Serial.read(); 239 | // add it to the inputString: 240 | inputString += inChar; 241 | // if the incoming character is a newline, set a flag so the main loop can 242 | // do something about it: 243 | if (inChar == '\n') { 244 | stringComplete = true; 245 | } 246 | } 247 | } 248 | // The ISR will be called every 5 milliseconds 249 | ISR(TIMER1_COMPA_vect) 250 | { 251 | // calculate the angle of inclination 252 | accAngle = atan2(accY, accZ)*RAD_TO_DEG; 253 | gyroRate = map(gyroX, -32768, 32767, -250, 250); 254 | gyroAngle = (float)gyroRate*sampleTime; 255 | currentAngle = 0.9934*(prevAngle + gyroAngle) + 0.0066*(accAngle); 256 | 257 | error = currentAngle - targetAngle; 258 | errorSum = errorSum + error; 259 | errorSum = constrain(errorSum, -300, 300); 260 | //Serial.print("error sum:");Serial.println(errorSum); 261 | //calculate output from P, I and D values 262 | motorPower = Kp*(error) + Ki*(errorSum)*sampleTime - Kd*(currentAngle-prevAngle)/sampleTime; 263 | //Serial.print("motor power:");Serial.println(motorPower); 264 | prevAngle = currentAngle; 265 | // toggle the led on pin13 every second 266 | count++; 267 | if(count == 200) { 268 | count = 0; 269 | digitalWrite(13, !digitalRead(13)); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /web-interface/css/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; 4 | } 5 | header { 6 | background-color: #27ace5; 7 | } 8 | body { 9 | font-family: calibri; 10 | } 11 | header h1 { 12 | text-align: center; 13 | font-size: 4em; 14 | color: white; 15 | padding: 10px; 16 | } 17 | header img { 18 | width: 110px; 19 | margin-top: 10px; 20 | float: left; 21 | } 22 | ul { 23 | list-style-type: none; 24 | margin: 0; 25 | padding: 0; 26 | overflow: hidden; 27 | background-color: #333; 28 | } 29 | li { 30 | float: left; 31 | } 32 | li a { 33 | display: block; 34 | color: white; 35 | text-align: center; 36 | padding: 14px 16px; 37 | text-decoration: none; 38 | } 39 | li a:hover:not(.active) { 40 | background-color: #111; 41 | } 42 | .active { 43 | background-color: #4CAF50; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | width: 100%; 48 | } 49 | table#inputsTable { 50 | border-collapse: collapse; 51 | width: 70%; 52 | } 53 | th, 54 | td { 55 | text-align: left; 56 | padding: 8px; 57 | } 58 | tr:nth-child(even) { 59 | background-color: #f2f2f2 60 | } 61 | th { 62 | background-color: #4CAF50; 63 | color: white; 64 | } 65 | section { 66 | width: 60%; 67 | margin: 10px; 68 | } 69 | .button { 70 | display: inline-block; 71 | padding: 10px 15px; 72 | font-size: 15px; 73 | cursor: pointer; 74 | text-align: center; 75 | text-decoration: none; 76 | outline: none; 77 | color: #fff; 78 | background-color: #4CAF50; 79 | border: none; 80 | border-radius: 15px; 81 | box-shadow: 0 9px #999; 82 | } 83 | .button:hover { 84 | background-color: #3e8e41 85 | } 86 | .button:active { 87 | background-color: #3e8e41; 88 | box-shadow: 0 5px #666; 89 | transform: translateY(4px); 90 | } 91 | input[type=text], 92 | select { 93 | width: 25%; 94 | padding: 12px 20px; 95 | margin: 8px 0; 96 | display: inline-block; 97 | border: 1px solid #ccc; 98 | border-radius: 4px; 99 | box-sizing: border-box; 100 | } 101 | .container { 102 | width: 250px; 103 | margin: 0; 104 | text-align: center; 105 | } 106 | .gauge { 107 | width: 250px; 108 | height: 250px; 109 | } -------------------------------------------------------------------------------- /web-interface/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | esp 6 | 7 | 8 | 9 | 10 | 35 | 36 | 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 50 | 53 | 57 | 58 | 59 | 60 | 63 | 66 | 70 | 71 | 72 | 73 | 74 | 77 | 80 | 84 | 85 | 86 | 87 | 90 | 93 | 97 | 98 | 99 | 100 | 103 | 106 | 110 | 111 | 112 | 113 | 116 | 119 | 123 | 124 | 125 | 126 | 129 | 130 | 131 |
ParameterIncrementDecrementvalue
Target Angle 48 | 49 | 51 | 52 | 54 | 55 | 56 |
Kp 61 | 62 | 64 | 65 | 67 | 68 | 69 |
Ki 75 | 76 | 78 | 79 | 81 | 82 | 83 |
Kd 88 | 89 | 91 | 92 | 94 | 95 | 96 |
motor A 101 | 102 | 104 | 105 | 107 | 108 | 109 |
motor B 114 | 115 | 117 | 118 | 120 | 121 | 122 |
Save 127 | 128 |
132 |
133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /web-interface/js/zepto.min.js: -------------------------------------------------------------------------------- 1 | var Zepto=function(){function L(t){return null==t?String(t):j[S.call(t)]||"object"}function Z(t){return"function"==L(t)}function _(t){return null!=t&&t==t.window}function $(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function D(t){return"object"==L(t)}function M(t){return D(t)&&!_(t)&&Object.getPrototypeOf(t)==Object.prototype}function R(t){return"number"==typeof t.length}function k(t){return s.call(t,function(t){return null!=t})}function z(t){return t.length>0?n.fn.concat.apply([],t):t}function F(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function q(t){return t in f?f[t]:f[t]=new RegExp("(^|\\s)"+t+"(\\s|$)")}function H(t,e){return"number"!=typeof e||c[F(t)]?e:e+"px"}function I(t){var e,n;return u[t]||(e=a.createElement(t),a.body.appendChild(e),n=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==n&&(n="block"),u[t]=n),u[t]}function V(t){return"children"in t?o.call(t.children):n.map(t.childNodes,function(t){return 1==t.nodeType?t:void 0})}function B(n,i,r){for(e in i)r&&(M(i[e])||A(i[e]))?(M(i[e])&&!M(n[e])&&(n[e]={}),A(i[e])&&!A(n[e])&&(n[e]=[]),B(n[e],i[e],r)):i[e]!==t&&(n[e]=i[e])}function U(t,e){return null==e?n(t):n(t).filter(e)}function J(t,e,n,i){return Z(e)?e.call(t,n,i):e}function X(t,e,n){null==n?t.removeAttribute(e):t.setAttribute(e,n)}function W(e,n){var i=e.className||"",r=i&&i.baseVal!==t;return n===t?r?i.baseVal:i:void(r?i.baseVal=n:e.className=n)}function Y(t){try{return t?"true"==t||("false"==t?!1:"null"==t?null:+t+""==t?+t:/^[\[\{]/.test(t)?n.parseJSON(t):t):t}catch(e){return t}}function G(t,e){e(t);for(var n=0,i=t.childNodes.length;i>n;n++)G(t.childNodes[n],e)}var t,e,n,i,C,N,r=[],o=r.slice,s=r.filter,a=window.document,u={},f={},c={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},l=/^\s*<(\w+|!)[^>]*>/,h=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,p=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,d=/^(?:body|html)$/i,m=/([A-Z])/g,g=["val","css","html","text","data","width","height","offset"],v=["after","prepend","before","append"],y=a.createElement("table"),x=a.createElement("tr"),b={tr:a.createElement("tbody"),tbody:y,thead:y,tfoot:y,td:x,th:x,"*":a.createElement("div")},w=/complete|loaded|interactive/,E=/^[\w-]*$/,j={},S=j.toString,T={},O=a.createElement("div"),P={tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},A=Array.isArray||function(t){return t instanceof Array};return T.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var i,r=t.parentNode,o=!r;return o&&(r=O).appendChild(t),i=~T.qsa(r,e).indexOf(t),o&&O.removeChild(t),i},C=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},N=function(t){return s.call(t,function(e,n){return t.indexOf(e)==n})},T.fragment=function(e,i,r){var s,u,f;return h.test(e)&&(s=n(a.createElement(RegExp.$1))),s||(e.replace&&(e=e.replace(p,"<$1>")),i===t&&(i=l.test(e)&&RegExp.$1),i in b||(i="*"),f=b[i],f.innerHTML=""+e,s=n.each(o.call(f.childNodes),function(){f.removeChild(this)})),M(r)&&(u=n(s),n.each(r,function(t,e){g.indexOf(t)>-1?u[t](e):u.attr(t,e)})),s},T.Z=function(t,e){return t=t||[],t.__proto__=n.fn,t.selector=e||"",t},T.isZ=function(t){return t instanceof T.Z},T.init=function(e,i){var r;if(!e)return T.Z();if("string"==typeof e)if(e=e.trim(),"<"==e[0]&&l.test(e))r=T.fragment(e,RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=T.qsa(a,e)}else{if(Z(e))return n(a).ready(e);if(T.isZ(e))return e;if(A(e))r=k(e);else if(D(e))r=[e],e=null;else if(l.test(e))r=T.fragment(e.trim(),RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=T.qsa(a,e)}}return T.Z(r,e)},n=function(t,e){return T.init(t,e)},n.extend=function(t){var e,n=o.call(arguments,1);return"boolean"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){B(t,n,e)}),t},T.qsa=function(t,e){var n,i="#"==e[0],r=!i&&"."==e[0],s=i||r?e.slice(1):e,a=E.test(s);return $(t)&&a&&i?(n=t.getElementById(s))?[n]:[]:1!==t.nodeType&&9!==t.nodeType?[]:o.call(a&&!i?r?t.getElementsByClassName(s):t.getElementsByTagName(e):t.querySelectorAll(e))},n.contains=a.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},n.type=L,n.isFunction=Z,n.isWindow=_,n.isArray=A,n.isPlainObject=M,n.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},n.inArray=function(t,e,n){return r.indexOf.call(e,t,n)},n.camelCase=C,n.trim=function(t){return null==t?"":String.prototype.trim.call(t)},n.uuid=0,n.support={},n.expr={},n.map=function(t,e){var n,r,o,i=[];if(R(t))for(r=0;r=0?e:e+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return r.every.call(this,function(e,n){return t.call(e,n,e)!==!1}),this},filter:function(t){return Z(t)?this.not(this.not(t)):n(s.call(this,function(e){return T.matches(e,t)}))},add:function(t,e){return n(N(this.concat(n(t,e))))},is:function(t){return this.length>0&&T.matches(this[0],t)},not:function(e){var i=[];if(Z(e)&&e.call!==t)this.each(function(t){e.call(this,t)||i.push(this)});else{var r="string"==typeof e?this.filter(e):R(e)&&Z(e.item)?o.call(e):n(e);this.forEach(function(t){r.indexOf(t)<0&&i.push(t)})}return n(i)},has:function(t){return this.filter(function(){return D(t)?n.contains(this,t):n(this).find(t).size()})},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!D(t)?t:n(t)},last:function(){var t=this[this.length-1];return t&&!D(t)?t:n(t)},find:function(t){var e,i=this;return e=t?"object"==typeof t?n(t).filter(function(){var t=this;return r.some.call(i,function(e){return n.contains(e,t)})}):1==this.length?n(T.qsa(this[0],t)):this.map(function(){return T.qsa(this,t)}):n()},closest:function(t,e){var i=this[0],r=!1;for("object"==typeof t&&(r=n(t));i&&!(r?r.indexOf(i)>=0:T.matches(i,t));)i=i!==e&&!$(i)&&i.parentNode;return n(i)},parents:function(t){for(var e=[],i=this;i.length>0;)i=n.map(i,function(t){return(t=t.parentNode)&&!$(t)&&e.indexOf(t)<0?(e.push(t),t):void 0});return U(e,t)},parent:function(t){return U(N(this.pluck("parentNode")),t)},children:function(t){return U(this.map(function(){return V(this)}),t)},contents:function(){return this.map(function(){return o.call(this.childNodes)})},siblings:function(t){return U(this.map(function(t,e){return s.call(V(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(t){return n.map(this,function(e){return e[t]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=I(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var e=Z(t);if(this[0]&&!e)var i=n(t).get(0),r=i.parentNode||this.length>1;return this.each(function(o){n(this).wrapAll(e?t.call(this,o):r?i.cloneNode(!0):i)})},wrapAll:function(t){if(this[0]){n(this[0]).before(t=n(t));for(var e;(e=t.children()).length;)t=e.first();n(t).append(this)}return this},wrapInner:function(t){var e=Z(t);return this.each(function(i){var r=n(this),o=r.contents(),s=e?t.call(this,i):t;o.length?o.wrapAll(s):r.append(s)})},unwrap:function(){return this.parent().each(function(){n(this).replaceWith(n(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(e){return this.each(function(){var i=n(this);(e===t?"none"==i.css("display"):e)?i.show():i.hide()})},prev:function(t){return n(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return n(this.pluck("nextElementSibling")).filter(t||"*")},html:function(t){return 0 in arguments?this.each(function(e){var i=this.innerHTML;n(this).empty().append(J(this,t,e,i))}):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each(function(e){var n=J(this,t,e,this.textContent);this.textContent=null==n?"":""+n}):0 in this?this[0].textContent:null},attr:function(n,i){var r;return"string"!=typeof n||1 in arguments?this.each(function(t){if(1===this.nodeType)if(D(n))for(e in n)X(this,e,n[e]);else X(this,n,J(this,i,t,this.getAttribute(n)))}):this.length&&1===this[0].nodeType?!(r=this[0].getAttribute(n))&&n in this[0]?this[0][n]:r:t},removeAttr:function(t){return this.each(function(){1===this.nodeType&&t.split(" ").forEach(function(t){X(this,t)},this)})},prop:function(t,e){return t=P[t]||t,1 in arguments?this.each(function(n){this[t]=J(this,e,n,this[t])}):this[0]&&this[0][t]},data:function(e,n){var i="data-"+e.replace(m,"-$1").toLowerCase(),r=1 in arguments?this.attr(i,n):this.attr(i);return null!==r?Y(r):t},val:function(t){return 0 in arguments?this.each(function(e){this.value=J(this,t,e,this.value)}):this[0]&&(this[0].multiple?n(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value)},offset:function(t){if(t)return this.each(function(e){var i=n(this),r=J(this,t,e,i.offset()),o=i.offsetParent().offset(),s={top:r.top-o.top,left:r.left-o.left};"static"==i.css("position")&&(s.position="relative"),i.css(s)});if(!this.length)return null;var e=this[0].getBoundingClientRect();return{left:e.left+window.pageXOffset,top:e.top+window.pageYOffset,width:Math.round(e.width),height:Math.round(e.height)}},css:function(t,i){if(arguments.length<2){var r,o=this[0];if(!o)return;if(r=getComputedStyle(o,""),"string"==typeof t)return o.style[C(t)]||r.getPropertyValue(t);if(A(t)){var s={};return n.each(t,function(t,e){s[e]=o.style[C(e)]||r.getPropertyValue(e)}),s}}var a="";if("string"==L(t))i||0===i?a=F(t)+":"+H(t,i):this.each(function(){this.style.removeProperty(F(t))});else for(e in t)t[e]||0===t[e]?a+=F(e)+":"+H(e,t[e])+";":this.each(function(){this.style.removeProperty(F(e))});return this.each(function(){this.style.cssText+=";"+a})},index:function(t){return t?this.indexOf(n(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return t?r.some.call(this,function(t){return this.test(W(t))},q(t)):!1},addClass:function(t){return t?this.each(function(e){if("className"in this){i=[];var r=W(this),o=J(this,t,e,r);o.split(/\s+/g).forEach(function(t){n(this).hasClass(t)||i.push(t)},this),i.length&&W(this,r+(r?" ":"")+i.join(" "))}}):this},removeClass:function(e){return this.each(function(n){if("className"in this){if(e===t)return W(this,"");i=W(this),J(this,e,n,i).split(/\s+/g).forEach(function(t){i=i.replace(q(t)," ")}),W(this,i.trim())}})},toggleClass:function(e,i){return e?this.each(function(r){var o=n(this),s=J(this,e,r,W(this));s.split(/\s+/g).forEach(function(e){(i===t?!o.hasClass(e):i)?o.addClass(e):o.removeClass(e)})}):this},scrollTop:function(e){if(this.length){var n="scrollTop"in this[0];return e===t?n?this[0].scrollTop:this[0].pageYOffset:this.each(n?function(){this.scrollTop=e}:function(){this.scrollTo(this.scrollX,e)})}},scrollLeft:function(e){if(this.length){var n="scrollLeft"in this[0];return e===t?n?this[0].scrollLeft:this[0].pageXOffset:this.each(n?function(){this.scrollLeft=e}:function(){this.scrollTo(e,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),i=this.offset(),r=d.test(e[0].nodeName)?{top:0,left:0}:e.offset();return i.top-=parseFloat(n(t).css("margin-top"))||0,i.left-=parseFloat(n(t).css("margin-left"))||0,r.top+=parseFloat(n(e[0]).css("border-top-width"))||0,r.left+=parseFloat(n(e[0]).css("border-left-width"))||0,{top:i.top-r.top,left:i.left-r.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||a.body;t&&!d.test(t.nodeName)&&"static"==n(t).css("position");)t=t.offsetParent;return t})}},n.fn.detach=n.fn.remove,["width","height"].forEach(function(e){var i=e.replace(/./,function(t){return t[0].toUpperCase()});n.fn[e]=function(r){var o,s=this[0];return r===t?_(s)?s["inner"+i]:$(s)?s.documentElement["scroll"+i]:(o=this.offset())&&o[e]:this.each(function(t){s=n(this),s.css(e,J(this,r,t,s[e]()))})}}),v.forEach(function(t,e){var i=e%2;n.fn[t]=function(){var t,o,r=n.map(arguments,function(e){return t=L(e),"object"==t||"array"==t||null==e?e:T.fragment(e)}),s=this.length>1;return r.length<1?this:this.each(function(t,u){o=i?u:u.parentNode,u=0==e?u.nextSibling:1==e?u.firstChild:2==e?u:null;var f=n.contains(a.documentElement,o);r.forEach(function(t){if(s)t=t.cloneNode(!0);else if(!o)return n(t).remove();o.insertBefore(t,u),f&&G(t,function(t){null==t.nodeName||"SCRIPT"!==t.nodeName.toUpperCase()||t.type&&"text/javascript"!==t.type||t.src||window.eval.call(window,t.innerHTML)})})})},n.fn[i?t+"To":"insert"+(e?"Before":"After")]=function(e){return n(e)[t](this),this}}),T.Z.prototype=n.fn,T.uniq=N,T.deserializeValue=Y,n.zepto=T,n}();window.Zepto=Zepto,void 0===window.$&&(window.$=Zepto),function(t){function l(t){return t._zid||(t._zid=e++)}function h(t,e,n,i){if(e=p(e),e.ns)var r=d(e.ns);return(s[l(t)]||[]).filter(function(t){return!(!t||e.e&&t.e!=e.e||e.ns&&!r.test(t.ns)||n&&l(t.fn)!==l(n)||i&&t.sel!=i)})}function p(t){var e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join(" ")}}function d(t){return new RegExp("(?:^| )"+t.replace(" "," .* ?")+"(?: |$)")}function m(t,e){return t.del&&!u&&t.e in f||!!e}function g(t){return c[t]||u&&f[t]||t}function v(e,i,r,o,a,u,f){var h=l(e),d=s[h]||(s[h]=[]);i.split(/\s/).forEach(function(i){if("ready"==i)return t(document).ready(r);var s=p(i);s.fn=r,s.sel=a,s.e in c&&(r=function(e){var n=e.relatedTarget;return!n||n!==this&&!t.contains(this,n)?s.fn.apply(this,arguments):void 0}),s.del=u;var l=u||r;s.proxy=function(t){if(t=j(t),!t.isImmediatePropagationStopped()){t.data=o;var i=l.apply(e,t._args==n?[t]:[t].concat(t._args));return i===!1&&(t.preventDefault(),t.stopPropagation()),i}},s.i=d.length,d.push(s),"addEventListener"in e&&e.addEventListener(g(s.e),s.proxy,m(s,f))})}function y(t,e,n,i,r){var o=l(t);(e||"").split(/\s/).forEach(function(e){h(t,e,n,i).forEach(function(e){delete s[o][e.i],"removeEventListener"in t&&t.removeEventListener(g(e.e),e.proxy,m(e,r))})})}function j(e,i){return(i||!e.isDefaultPrevented)&&(i||(i=e),t.each(E,function(t,n){var r=i[t];e[t]=function(){return this[n]=x,r&&r.apply(i,arguments)},e[n]=b}),(i.defaultPrevented!==n?i.defaultPrevented:"returnValue"in i?i.returnValue===!1:i.getPreventDefault&&i.getPreventDefault())&&(e.isDefaultPrevented=x)),e}function S(t){var e,i={originalEvent:t};for(e in t)w.test(e)||t[e]===n||(i[e]=t[e]);return j(i,t)}var n,e=1,i=Array.prototype.slice,r=t.isFunction,o=function(t){return"string"==typeof t},s={},a={},u="onfocusin"in window,f={focus:"focusin",blur:"focusout"},c={mouseenter:"mouseover",mouseleave:"mouseout"};a.click=a.mousedown=a.mouseup=a.mousemove="MouseEvents",t.event={add:v,remove:y},t.proxy=function(e,n){var s=2 in arguments&&i.call(arguments,2);if(r(e)){var a=function(){return e.apply(n,s?s.concat(i.call(arguments)):arguments)};return a._zid=l(e),a}if(o(n))return s?(s.unshift(e[n],e),t.proxy.apply(null,s)):t.proxy(e[n],e);throw new TypeError("expected function")},t.fn.bind=function(t,e,n){return this.on(t,e,n)},t.fn.unbind=function(t,e){return this.off(t,e)},t.fn.one=function(t,e,n,i){return this.on(t,e,n,i,1)};var x=function(){return!0},b=function(){return!1},w=/^([A-Z]|returnValue$|layer[XY]$)/,E={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};t.fn.delegate=function(t,e,n){return this.on(e,t,n)},t.fn.undelegate=function(t,e,n){return this.off(e,t,n)},t.fn.live=function(e,n){return t(document.body).delegate(this.selector,e,n),this},t.fn.die=function(e,n){return t(document.body).undelegate(this.selector,e,n),this},t.fn.on=function(e,s,a,u,f){var c,l,h=this;return e&&!o(e)?(t.each(e,function(t,e){h.on(t,s,a,e,f)}),h):(o(s)||r(u)||u===!1||(u=a,a=s,s=n),(r(a)||a===!1)&&(u=a,a=n),u===!1&&(u=b),h.each(function(n,r){f&&(c=function(t){return y(r,t.type,u),u.apply(this,arguments)}),s&&(l=function(e){var n,o=t(e.target).closest(s,r).get(0);return o&&o!==r?(n=t.extend(S(e),{currentTarget:o,liveFired:r}),(c||u).apply(o,[n].concat(i.call(arguments,1)))):void 0}),v(r,e,u,a,s,l||c)}))},t.fn.off=function(e,i,s){var a=this;return e&&!o(e)?(t.each(e,function(t,e){a.off(t,i,e)}),a):(o(i)||r(s)||s===!1||(s=i,i=n),s===!1&&(s=b),a.each(function(){y(this,e,s,i)}))},t.fn.trigger=function(e,n){return e=o(e)||t.isPlainObject(e)?t.Event(e):j(e),e._args=n,this.each(function(){e.type in f&&"function"==typeof this[e.type]?this[e.type]():"dispatchEvent"in this?this.dispatchEvent(e):t(this).triggerHandler(e,n)})},t.fn.triggerHandler=function(e,n){var i,r;return this.each(function(s,a){i=S(o(e)?t.Event(e):e),i._args=n,i.target=a,t.each(h(a,e.type||e),function(t,e){return r=e.proxy(i),i.isImmediatePropagationStopped()?!1:void 0})}),r},"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(e){t.fn[e]=function(t){return 0 in arguments?this.bind(e,t):this.trigger(e)}}),t.Event=function(t,e){o(t)||(e=t,t=e.type);var n=document.createEvent(a[t]||"Events"),i=!0;if(e)for(var r in e)"bubbles"==r?i=!!e[r]:n[r]=e[r];return n.initEvent(t,i,!0),j(n)}}(Zepto),function(t){function h(e,n,i){var r=t.Event(n);return t(e).trigger(r,i),!r.isDefaultPrevented()}function p(t,e,i,r){return t.global?h(e||n,i,r):void 0}function d(e){e.global&&0===t.active++&&p(e,null,"ajaxStart")}function m(e){e.global&&!--t.active&&p(e,null,"ajaxStop")}function g(t,e){var n=e.context;return e.beforeSend.call(n,t,e)===!1||p(e,n,"ajaxBeforeSend",[t,e])===!1?!1:void p(e,n,"ajaxSend",[t,e])}function v(t,e,n,i){var r=n.context,o="success";n.success.call(r,t,o,e),i&&i.resolveWith(r,[t,o,e]),p(n,r,"ajaxSuccess",[e,n,t]),x(o,e,n)}function y(t,e,n,i,r){var o=i.context;i.error.call(o,n,e,t),r&&r.rejectWith(o,[n,e,t]),p(i,o,"ajaxError",[n,i,t||e]),x(e,n,i)}function x(t,e,n){var i=n.context;n.complete.call(i,e,t),p(n,i,"ajaxComplete",[e,n]),m(n)}function b(){}function w(t){return t&&(t=t.split(";",2)[0]),t&&(t==f?"html":t==u?"json":s.test(t)?"script":a.test(t)&&"xml")||"text"}function E(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}function j(e){e.processData&&e.data&&"string"!=t.type(e.data)&&(e.data=t.param(e.data,e.traditional)),!e.data||e.type&&"GET"!=e.type.toUpperCase()||(e.url=E(e.url,e.data),e.data=void 0)}function S(e,n,i,r){return t.isFunction(n)&&(r=i,i=n,n=void 0),t.isFunction(i)||(r=i,i=void 0),{url:e,data:n,success:i,dataType:r}}function C(e,n,i,r){var o,s=t.isArray(n),a=t.isPlainObject(n);t.each(n,function(n,u){o=t.type(u),r&&(n=i?r:r+"["+(a||"object"==o||"array"==o?n:"")+"]"),!r&&s?e.add(u.name,u.value):"array"==o||!i&&"object"==o?C(e,u,i,n):e.add(n,u)})}var i,r,e=0,n=window.document,o=/)<[^<]*)*<\/script>/gi,s=/^(?:text|application)\/javascript/i,a=/^(?:text|application)\/xml/i,u="application/json",f="text/html",c=/^\s*$/,l=n.createElement("a");l.href=window.location.href,t.active=0,t.ajaxJSONP=function(i,r){if(!("type"in i))return t.ajax(i);var f,h,o=i.jsonpCallback,s=(t.isFunction(o)?o():o)||"jsonp"+ ++e,a=n.createElement("script"),u=window[s],c=function(e){t(a).triggerHandler("error",e||"abort")},l={abort:c};return r&&r.promise(l),t(a).on("load error",function(e,n){clearTimeout(h),t(a).off().remove(),"error"!=e.type&&f?v(f[0],l,i,r):y(null,n||"error",l,i,r),window[s]=u,f&&t.isFunction(u)&&u(f[0]),u=f=void 0}),g(l,i)===!1?(c("abort"),l):(window[s]=function(){f=arguments},a.src=i.url.replace(/\?(.+)=\?/,"?$1="+s),n.head.appendChild(a),i.timeout>0&&(h=setTimeout(function(){c("timeout")},i.timeout)),l)},t.ajaxSettings={type:"GET",beforeSend:b,success:b,error:b,complete:b,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript, application/x-javascript",json:u,xml:"application/xml, text/xml",html:f,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0},t.ajax=function(e){var a,o=t.extend({},e||{}),s=t.Deferred&&t.Deferred();for(i in t.ajaxSettings)void 0===o[i]&&(o[i]=t.ajaxSettings[i]);d(o),o.crossDomain||(a=n.createElement("a"),a.href=o.url,a.href=a.href,o.crossDomain=l.protocol+"//"+l.host!=a.protocol+"//"+a.host),o.url||(o.url=window.location.toString()),j(o);var u=o.dataType,f=/\?.+=\?/.test(o.url);if(f&&(u="jsonp"),o.cache!==!1&&(e&&e.cache===!0||"script"!=u&&"jsonp"!=u)||(o.url=E(o.url,"_="+Date.now())),"jsonp"==u)return f||(o.url=E(o.url,o.jsonp?o.jsonp+"=?":o.jsonp===!1?"":"callback=?")),t.ajaxJSONP(o,s);var C,h=o.accepts[u],p={},m=function(t,e){p[t.toLowerCase()]=[t,e]},x=/^([\w-]+:)\/\//.test(o.url)?RegExp.$1:window.location.protocol,S=o.xhr(),T=S.setRequestHeader;if(s&&s.promise(S),o.crossDomain||m("X-Requested-With","XMLHttpRequest"),m("Accept",h||"*/*"),(h=o.mimeType||h)&&(h.indexOf(",")>-1&&(h=h.split(",",2)[0]),S.overrideMimeType&&S.overrideMimeType(h)),(o.contentType||o.contentType!==!1&&o.data&&"GET"!=o.type.toUpperCase())&&m("Content-Type",o.contentType||"application/x-www-form-urlencoded"),o.headers)for(r in o.headers)m(r,o.headers[r]);if(S.setRequestHeader=m,S.onreadystatechange=function(){if(4==S.readyState){S.onreadystatechange=b,clearTimeout(C);var e,n=!1;if(S.status>=200&&S.status<300||304==S.status||0==S.status&&"file:"==x){u=u||w(o.mimeType||S.getResponseHeader("content-type")),e=S.responseText;try{"script"==u?(1,eval)(e):"xml"==u?e=S.responseXML:"json"==u&&(e=c.test(e)?null:t.parseJSON(e))}catch(i){n=i}n?y(n,"parsererror",S,o,s):v(e,S,o,s)}else y(S.statusText||null,S.status?"error":"abort",S,o,s)}},g(S,o)===!1)return S.abort(),y(null,"abort",S,o,s),S;if(o.xhrFields)for(r in o.xhrFields)S[r]=o.xhrFields[r];var N="async"in o?o.async:!0;S.open(o.type,o.url,N,o.username,o.password);for(r in p)T.apply(S,p[r]);return o.timeout>0&&(C=setTimeout(function(){S.onreadystatechange=b,S.abort(),y(null,"timeout",S,o,s)},o.timeout)),S.send(o.data?o.data:null),S},t.get=function(){return t.ajax(S.apply(null,arguments))},t.post=function(){var e=S.apply(null,arguments);return e.type="POST",t.ajax(e)},t.getJSON=function(){var e=S.apply(null,arguments);return e.dataType="json",t.ajax(e)},t.fn.load=function(e,n,i){if(!this.length)return this;var a,r=this,s=e.split(/\s/),u=S(e,n,i),f=u.success;return s.length>1&&(u.url=s[0],a=s[1]),u.success=function(e){r.html(a?t("
").html(e.replace(o,"")).find(a):e),f&&f.apply(r,arguments)},t.ajax(u),this};var T=encodeURIComponent;t.param=function(e,n){var i=[];return i.add=function(e,n){t.isFunction(n)&&(n=n()),null==n&&(n=""),this.push(T(e)+"="+T(n))},C(i,e,n),i.join("&").replace(/%20/g,"+")}}(Zepto),function(t){t.fn.serializeArray=function(){var e,n,i=[],r=function(t){return t.forEach?t.forEach(r):void i.push({name:e,value:t})};return this[0]&&t.each(this[0].elements,function(i,o){n=o.type,e=o.name,e&&"fieldset"!=o.nodeName.toLowerCase()&&!o.disabled&&"submit"!=n&&"reset"!=n&&"button"!=n&&"file"!=n&&("radio"!=n&&"checkbox"!=n||o.checked)&&r(t(o).val())}),i},t.fn.serialize=function(){var t=[];return this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+"="+encodeURIComponent(e.value))}),t.join("&")},t.fn.submit=function(e){if(0 in arguments)this.bind("submit",e);else if(this.length){var n=t.Event("submit");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return this}}(Zepto),function(t){"__proto__"in{}||t.extend(t.zepto,{Z:function(e,n){return e=e||[],t.extend(e,t.fn),e.selector=n||"",e.__Z=!0,e},isZ:function(e){return"array"===t.type(e)&&"__Z"in e}});try{getComputedStyle(void 0)}catch(e){var n=getComputedStyle;window.getComputedStyle=function(t){try{return n(t)}catch(e){return null}}}}(Zepto); --------------------------------------------------------------------------------