MPUTeapot.pde 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // I2C device class (I2Cdev) demonstration Processing sketch for MPU6050 DMP output
  2. // 6/20/2012 by Jeff Rowberg <jeff@rowberg.net>
  3. // Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
  4. //
  5. // Changelog:
  6. // 2012-06-20 - initial release
  7. /* ============================================
  8. I2Cdev device library code is placed under the MIT license
  9. Copyright (c) 2012 Jeff Rowberg
  10. Permission is hereby granted, free of charge, to any person obtaining a copy
  11. of this software and associated documentation files (the "Software"), to deal
  12. in the Software without restriction, including without limitation the rights
  13. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14. copies of the Software, and to permit persons to whom the Software is
  15. furnished to do so, subject to the following conditions:
  16. The above copyright notice and this permission notice shall be included in
  17. all copies or substantial portions of the Software.
  18. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. THE SOFTWARE.
  25. ===============================================
  26. */
  27. import processing.serial.*;
  28. import processing.opengl.*;
  29. import toxi.geom.*;
  30. import toxi.processing.*;
  31. // NOTE: requires ToxicLibs to be installed in order to run properly.
  32. // 1. Download from http://toxiclibs.org/downloads
  33. // 2. Extract into [userdir]/Processing/libraries
  34. // (location may be different on Mac/Linux)
  35. // 3. Run and bask in awesomeness
  36. ToxiclibsSupport gfx;
  37. Serial port; // The serial port
  38. char[] teapotPacket = new char[14]; // InvenSense Teapot packet
  39. int serialCount = 0; // current packet byte position
  40. int aligned = 0;
  41. int interval = 0;
  42. float[] q = new float[4];
  43. Quaternion quat = new Quaternion(1, 0, 0, 0);
  44. float[] gravity = new float[3];
  45. float[] euler = new float[3];
  46. float[] ypr = new float[3];
  47. void setup() {
  48. // 300px square viewport using OpenGL rendering
  49. size(300, 300, OPENGL);
  50. gfx = new ToxiclibsSupport(this);
  51. // setup lights and antialiasing
  52. lights();
  53. smooth();
  54. // display serial port list for debugging/clarity
  55. println(Serial.list());
  56. // get the first available port (use EITHER this OR the specific port code below)
  57. String portName = "/dev/ttyUSB1";
  58. // get a specific serial port (use EITHER this OR the first-available code above)
  59. //String portName = "COM4";
  60. // open the serial port
  61. port = new Serial(this, portName, 115200);
  62. // send single character to trigger DMP init/start
  63. // (expected by MPU6050_DMP6 example Arduino sketch)
  64. port.write('r');
  65. }
  66. void draw() {
  67. if (millis() - interval > 1000) {
  68. // resend single character to trigger DMP init/start
  69. // in case the MPU is halted/reset while applet is running
  70. port.write('r');
  71. interval = millis();
  72. }
  73. // black background
  74. background(0);
  75. // translate everything to the middle of the viewport
  76. pushMatrix();
  77. translate(width / 2, height / 2);
  78. // 3-step rotation from yaw/pitch/roll angles (gimbal lock!)
  79. // ...and other weirdness I haven't figured out yet
  80. //rotateY(-ypr[0]);
  81. //rotateZ(-ypr[1]);
  82. //rotateX(-ypr[2]);
  83. // toxiclibs direct angle/axis rotation from quaternion (NO gimbal lock!)
  84. // (axis order [1, 3, 2] and inversion [-1, +1, +1] is a consequence of
  85. // different coordinate system orientation assumptions between Processing
  86. // and InvenSense DMP)
  87. float[] axis = quat.toAxisAngle();
  88. rotate(axis[0], -axis[1], axis[3], axis[2]);
  89. // draw main body in red
  90. fill(255, 0, 0, 200);
  91. box(10, 10, 200);
  92. // draw front-facing tip in blue
  93. fill(0, 0, 255, 200);
  94. pushMatrix();
  95. translate(0, 0, -120);
  96. rotateX(PI/2);
  97. drawCylinder(0, 20, 20, 8);
  98. popMatrix();
  99. // draw wings and tail fin in green
  100. fill(0, 255, 0, 200);
  101. beginShape(TRIANGLES);
  102. vertex(-100, 2, 30); vertex(0, 2, -80); vertex(100, 2, 30); // wing top layer
  103. vertex(-100, -2, 30); vertex(0, -2, -80); vertex(100, -2, 30); // wing bottom layer
  104. vertex(-2, 0, 98); vertex(-2, -30, 98); vertex(-2, 0, 70); // tail left layer
  105. vertex( 2, 0, 98); vertex( 2, -30, 98); vertex( 2, 0, 70); // tail right layer
  106. endShape();
  107. beginShape(QUADS);
  108. vertex(-100, 2, 30); vertex(-100, -2, 30); vertex( 0, -2, -80); vertex( 0, 2, -80);
  109. vertex( 100, 2, 30); vertex( 100, -2, 30); vertex( 0, -2, -80); vertex( 0, 2, -80);
  110. vertex(-100, 2, 30); vertex(-100, -2, 30); vertex(100, -2, 30); vertex(100, 2, 30);
  111. vertex(-2, 0, 98); vertex(2, 0, 98); vertex(2, -30, 98); vertex(-2, -30, 98);
  112. vertex(-2, 0, 98); vertex(2, 0, 98); vertex(2, 0, 70); vertex(-2, 0, 70);
  113. vertex(-2, -30, 98); vertex(2, -30, 98); vertex(2, 0, 70); vertex(-2, 0, 70);
  114. endShape();
  115. popMatrix();
  116. }
  117. void serialEvent(Serial port) {
  118. interval = millis();
  119. while (port.available() > 0) {
  120. int ch = port.read();
  121. print((char)ch);
  122. if (ch == '$') {serialCount = 0;} // this will help with alignment
  123. if (aligned < 4) {
  124. // make sure we are properly aligned on a 14-byte packet
  125. if (serialCount == 0) {
  126. if (ch == '$') aligned++; else aligned = 0;
  127. } else if (serialCount == 1) {
  128. if (ch == 2) aligned++; else aligned = 0;
  129. } else if (serialCount == 12) {
  130. if (ch == '\r') aligned++; else aligned = 0;
  131. } else if (serialCount == 13) {
  132. if (ch == '\n') aligned++; else aligned = 0;
  133. }
  134. //println(ch + " " + aligned + " " + serialCount);
  135. serialCount++;
  136. if (serialCount == 14) serialCount = 0;
  137. } else {
  138. if (serialCount > 0 || ch == '$') {
  139. teapotPacket[serialCount++] = (char)ch;
  140. if (serialCount == 14) {
  141. serialCount = 0; // restart packet byte position
  142. // get quaternion from data packet
  143. q[0] = ((teapotPacket[2] << 8) | teapotPacket[3]) / 16384.0f;
  144. q[1] = ((teapotPacket[4] << 8) | teapotPacket[5]) / 16384.0f;
  145. q[2] = ((teapotPacket[6] << 8) | teapotPacket[7]) / 16384.0f;
  146. q[3] = ((teapotPacket[8] << 8) | teapotPacket[9]) / 16384.0f;
  147. for (int i = 0; i < 4; i++) if (q[i] >= 2) q[i] = -4 + q[i];
  148. // set our toxilibs quaternion to new data
  149. quat.set(q[0], q[1], q[2], q[3]);
  150. /*
  151. // below calculations unnecessary for orientation only using toxilibs
  152. // calculate gravity vector
  153. gravity[0] = 2 * (q[1]*q[3] - q[0]*q[2]);
  154. gravity[1] = 2 * (q[0]*q[1] + q[2]*q[3]);
  155. gravity[2] = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3];
  156. // calculate Euler angles
  157. euler[0] = atan2(2*q[1]*q[2] - 2*q[0]*q[3], 2*q[0]*q[0] + 2*q[1]*q[1] - 1);
  158. euler[1] = -asin(2*q[1]*q[3] + 2*q[0]*q[2]);
  159. euler[2] = atan2(2*q[2]*q[3] - 2*q[0]*q[1], 2*q[0]*q[0] + 2*q[3]*q[3] - 1);
  160. // calculate yaw/pitch/roll angles
  161. ypr[0] = atan2(2*q[1]*q[2] - 2*q[0]*q[3], 2*q[0]*q[0] + 2*q[1]*q[1] - 1);
  162. ypr[1] = atan(gravity[0] / sqrt(gravity[1]*gravity[1] + gravity[2]*gravity[2]));
  163. ypr[2] = atan(gravity[1] / sqrt(gravity[0]*gravity[0] + gravity[2]*gravity[2]));
  164. // output various components for debugging
  165. //println("q:\t" + round(q[0]*100.0f)/100.0f + "\t" + round(q[1]*100.0f)/100.0f + "\t" + round(q[2]*100.0f)/100.0f + "\t" + round(q[3]*100.0f)/100.0f);
  166. //println("euler:\t" + euler[0]*180.0f/PI + "\t" + euler[1]*180.0f/PI + "\t" + euler[2]*180.0f/PI);
  167. //println("ypr:\t" + ypr[0]*180.0f/PI + "\t" + ypr[1]*180.0f/PI + "\t" + ypr[2]*180.0f/PI);
  168. */
  169. }
  170. }
  171. }
  172. }
  173. }
  174. void drawCylinder(float topRadius, float bottomRadius, float tall, int sides) {
  175. float angle = 0;
  176. float angleIncrement = TWO_PI / sides;
  177. beginShape(QUAD_STRIP);
  178. for (int i = 0; i < sides + 1; ++i) {
  179. vertex(topRadius*cos(angle), 0, topRadius*sin(angle));
  180. vertex(bottomRadius*cos(angle), tall, bottomRadius*sin(angle));
  181. angle += angleIncrement;
  182. }
  183. endShape();
  184. // If it is not a cone, draw the circular top cap
  185. if (topRadius != 0) {
  186. angle = 0;
  187. beginShape(TRIANGLE_FAN);
  188. // Center point
  189. vertex(0, 0, 0);
  190. for (int i = 0; i < sides + 1; i++) {
  191. vertex(topRadius * cos(angle), 0, topRadius * sin(angle));
  192. angle += angleIncrement;
  193. }
  194. endShape();
  195. }
  196. // If it is not a cone, draw the circular bottom cap
  197. if (bottomRadius != 0) {
  198. angle = 0;
  199. beginShape(TRIANGLE_FAN);
  200. // Center point
  201. vertex(0, tall, 0);
  202. for (int i = 0; i < sides + 1; i++) {
  203. vertex(bottomRadius * cos(angle), tall, bottomRadius * sin(angle));
  204. angle += angleIncrement;
  205. }
  206. endShape();
  207. }
  208. }