{"id":216,"date":"2008-09-20T09:40:03","date_gmt":"2008-09-20T14:40:03","guid":{"rendered":"http:\/\/www.tigoe.net\/pcomp\/code\/?p=216"},"modified":"2010-11-22T06:16:05","modified_gmt":"2010-11-22T11:16:05","slug":"using-an-accelerometer-to-sense-which-way-is-up","status":"publish","type":"post","link":"https:\/\/www.tigoe.com\/pcomp\/code\/arduinowiring\/216\/","title":{"rendered":"Using an Accelerometer to Sense Which Way Is Up"},"content":{"rendered":"<p><a href=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/rotating_screen.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-thumbnail wp-image-221\" style=\"border: 0pt none; margin: 3px;\" title=\"rotating_screen\" src=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/rotating_screen-150x150.jpg\" alt=\"\" width=\"150\" height=\"150\" \/><\/a>ITP just got some nifty flat panel mounts that can rotate 360 degrees. They&#8217;re very easy to move, it takes only one hand.  When I saw them, I thought, &#8220;what good is a rotating mount if the content on the screen can&#8217;t rotate too?&#8221;  So I came up with a little system to sense the screen&#8217;s rotation.  Here&#8217;s how to turn those screens into a very big iPhone.  Thanks to Michael Dory for his help in coding this and Dan O&#8217;Sullivan for the final clue.<\/p>\n<p>The screens have a mac mini mounted on the back to display digital content. I added an Arduino with an accelerometer mounted on it to sense the angle of the screen&#8217;s rotation, then sent that data into Processing.\u00a0 This example doesn&#8217;t do much, but the code can be re-used for any Processing application that needs to know the screen&#8217;s rotation.<\/p>\n<p>Rory Nugent modified my existing code and made it much better.\u00a0 I&#8217;ve incorporated <a href=\"http:\/\/prize-pony.com\/wiki\/index.php?title=Rotating_Screens\">his changes<\/a> here, thanks Rory.<\/p>\n<p><!--more--><\/p>\n<h2>Part 1: The Hardware<\/h2>\n<dl id=\"attachment_219\" class=\"wp-caption alignleft\" style=\"width: 310px;\">\n<dt class=\"wp-caption-dt\"><a href=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/arduino_accelerometer.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-219 alignleft\" style=\"border: 0pt none;\" title=\"arduino_accelerometer\" src=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/arduino_accelerometer-300x225.jpg\" alt=\"Arduino and ADXL330 accelerometer\" width=\"300\" height=\"225\" srcset=\"https:\/\/www.tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/arduino_accelerometer-300x225.jpg 300w, https:\/\/www.tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/arduino_accelerometer.jpg 600w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/dt>\n<\/dl>\n<p>To do this quickly, I used an <a href=\"http:\/\/www.arduino.cc\">Arduino Diecimila<\/a> and an <a href=\"http:\/\/www.sparkfun.com\/commerce\/product_info.php?products_id=847\">ADXL330 accelerometer module<\/a> that I had on my desk.\u00a0 Rather than set up a separate breadboard, I plugged the accelerometer directly into the analog pins of the Arduino.<\/p>\n<p><em>But wait!\u00a0 How is the accelerometer powered by analog pins?<\/em><\/p>\n<p>The analog pins of an Arduino can also act as digital I\/O.\u00a0 Analog pins 0 through 5 correspond to digital I\/O 14 through 19.\u00a0 The accelerometer draws very little current, less than the I\/O pins can output.\u00a0 So I just used analog pins 0, 4, and 5 as digital outputs.\u00a0 They are digital outputs 14, 18, and 19.\u00a0 Digital output 18 acts as ground and 19 acts as voltage in for the accelerometer.\u00a0 digital output 14 keeps the self-test pin high.<\/p>\n<p>Analog pins 1 through 3 are connected to the analog outputs of the accelerometer.\u00a0 This is a handy way to make a motion sensor with a minimum of parts.\u00a0 Now the whole board can be attached to the back of the plasma mount.<\/p>\n<p>(Tip of the hat to Tod Kurt, who taught me this trick.\u00a0 This is how he wires <a href=\"http:\/\/thingm.com\/products\/blinkm\">BlinkMs<\/a> to the Arduino)<\/p>\n<h2>Part 2: The Firmware<\/h2>\n<p>The Arduino firmware is pretty simple.\u00a0 It reads the accelerometer&#8217;s outputs and sends them to Processing using a call-and-response serial methodology.\u00a0 It also calculates the running maxima and minima of the X and Y channels, because Processing will need to know those in order to calculate the angle from the accelerometer values.<\/p>\n<p><em>How does the call and response work?<\/em><\/p>\n<p>Every time the Processing application that this Arduino is speaking to opens the serial port, it will reset the Arduino. In order to initialize serial communications, the Arduino starts out by sending a serial byte until it gets something back from Processing.\u00a0 Processing is buffering serial data until it sees a newline character, so\u00a0 <code>serialEvent()<\/code> is going to get triggered by a newline. So Arduino sends newlines intially.\u00a0 Processing will read those, and at the end of the first <code>serialEvent()<\/code>, send a newline back.\u00a0 Arduino, once it receives any character, will go into the main <code>loop()<\/code>. Here&#8217;s how that works in the <code>setup()<\/code>:<\/p>\n<pre>void setup() {\r\n  \/\/ initialize serial:\r\n  Serial.begin(9600);\r\n\r\n  \/\/ send a byte out the serial port until\r\n  \/\/ you get one back in to initialize\r\n  \/\/ call-and-response serial communication:\r\n  while (Serial.available() &lt;=0) {\r\n    \/\/ take readings of the accelerometer while you wait for a call-and-response\r\n    \/\/ doing this seems to clear out any initial garbage and settle down the ADC\r\n    for (int channel = 1; channel &lt; 4; channel++) {\r\n      analogRead(channel);\r\n      delay(10);\r\n   }\r\n    Serial.print(\"\\n\");\r\n  }\r\n}<\/pre>\n<p>In the main loop, Arduino listens for incoming serial data.\u00a0 When it gets a byte, it reads it.\u00a0 Doesn&#8217;t matter what the byte is, since it doesn&#8217;t do anything but read it to clear the serial buffer.\u00a0 When it&#8217;s finished sending all its data, it sends a <code>Serial.println()<\/code>. The newline in the println() triggers Processing&#8217;s <code>serialEvent()<\/code>, and Bob&#8217;s your uncle. Here&#8217;s how that works in the main loop:<\/p>\n<pre>void loop() {\r\n\r\n  \/\/ only send if you have an incoming serial byte:\r\n  if (Serial.available()) {\r\n    \/\/ read the incoming byte to clear the serial buffer:\r\n    int inByte = Serial.read();\r\n\r\n    \/\/ do everything else here...\r\n\r\n    \/\/ then send a newline:\r\n    Serial.println();\r\n   }\r\n}<\/pre>\n<p>In my original version, I calculated maxima and minima on the fly and sent them to Processing, but Rory found it was more stable to do that on the Processing side.\u00a0 So the main loop in Arduino is actually quite simple.\u00a0 Here it is in its entirety:<\/p>\n<pre>void loop() {\r\n  \/\/ only send if you have an incoming serial byte:\r\n  if (Serial.available()) {\r\n    \/\/ read and print the x-axis value from the accelerometer\r\n    Serial.print(analogRead(3));\r\n\r\n    \/\/ print a delimiter\r\n    Serial.print(\",\");\r\n\r\n    \/\/read and print the y-axis from the accelerometer\r\n    Serial.print(analogRead(2));\r\n\r\n    \/\/ print carriage return and newline:\r\n    Serial.println();\r\n\r\n    Serial.flush();\r\n  }\r\n}<\/pre>\n<p>Here&#8217;s the Arduino code in full:<\/p>\n<pre>\/*\r\n  Accelerometer Reader\r\n\r\n Reads the X and Y of a 3-axis accelerometer\r\n\r\n The accelerometer, an ADXL330 from Sparkfun, is attached\r\n to analogs 1 through 3.  Analog pins 0, 4, and 5\r\n are used as digital I\/O pins in this case, as follows:\r\n Analog  0 = Digital  14 = HIGH (accelerometer self test)\r\n Analog 4 = Digital 18 = LOW (accelerometer ground)\r\n Analog 5 = Digital 19 = HIGH (accelerometer Vin)\r\n\r\n Sends serial readings in this format:\r\n  X, Y\\r\\n\r\n\r\n created 19 Sep 2008\r\n by Tom Igoe\r\n\r\n last modified 28 Oct 2008\r\n by Rory Nugent\r\n\r\n Recent Changes:\r\n Removed calculation of the max and min, sends only X-axis and Y-axis values, and\r\n configured a basic wait period after boot to wait for Processing and to throw out\r\n all readings during this period.\r\n *\/\r\n\r\nint accelReading = 0;\r\n\r\nvoid setup() {\r\n  \/\/ initialize serial:\r\n  Serial.begin(9600);\r\n\r\n  pinMode(13,OUTPUT);\r\n\r\n  \/\/ set up Analog 0, 4, and 5 to be\r\n  \/\/ digital I\/O (14, 18, and 19, respectively):\r\n  pinMode(14, OUTPUT);\r\n  pinMode(18, OUTPUT);\r\n  pinMode(19, OUTPUT);\r\n\r\n  \/\/ set pins appropriately for accelerometer's needs:\r\n  digitalWrite(14, HIGH);    \/\/ acc. self test\r\n  digitalWrite(18, LOW);     \/\/ acc. ground\r\n  digitalWrite(19, HIGH);    \/\/ acc. power\r\n\r\n  digitalWrite(13,HIGH);\r\n\r\n  \/\/ send a byte out the serial port until\r\n  \/\/ you get one back in to initialize\r\n  \/\/ call-and-response serial communication:\r\n  while (Serial.available() &lt;=0) {\r\n    \/\/ take readings of the accelerometer while you wait for a call-and-response\r\n    \/\/ doing this seems to clear out any initial garbage and settle down the ADC\r\n    for (int channel = 1; channel &lt; 4; channel++) {\r\n      analogRead(channel);\r\n      delay(10);\r\n   }\r\n    Serial.print(\"\\n\");\r\n  }\r\n\r\n  digitalWrite(13,LOW);\r\n}\r\n\r\nvoid loop() {\r\n  \/\/ only send if you have an incoming serial byte:\r\n  if (Serial.available()) {\r\n    \/\/ read and print the x-axis value from the accelerometer\r\n    Serial.print(analogRead(3));\r\n\r\n    \/\/ print a delimiter\r\n    Serial.print(\",\");\r\n\r\n    \/\/read and print the y-axis from the accelerometer\r\n    Serial.print(analogRead(2));\r\n\r\n    \/\/ print carriage return and newline:\r\n    Serial.println();\r\n\r\n    Serial.flush();\r\n  }\r\n}<\/pre>\n<h2>Part 3: The Software<\/h2>\n<p>In order to derive angle from the accelerometer values, you need to know how the values are changing as you move the sensor.\u00a0 I tested by holding the accelerometer and Arduino vertically and watching the output of the axes.\u00a0 The output is like this:<\/p>\n<p style=\"text-align: center;\"><a href=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/rotation1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-245 aligncenter\" style=\"border: 0pt none; margin-top: 3px; margin-bottom: 3px;\" title=\"rotation\" src=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/rotation1-300x227.png\" alt=\"\" width=\"180\" height=\"136\" srcset=\"https:\/\/www.tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/rotation1-300x227.png 300w, https:\/\/www.tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/rotation1.png 349w\" sizes=\"auto, (max-width: 180px) 100vw, 180px\" \/><\/a><\/p>\n<p>Knowing that, you can calculate the angle using a little trigonometry.\u00a0 Imagine the X and Y values as sides of a right triangle.\u00a0 The angle you want is the arctangent of the opposite divided by the adjacent side.<\/p>\n<p style=\"text-align: center;\"><a href=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/angle1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-247 aligncenter\" style=\"border: 0pt none; margin-top: 3px; margin-bottom: 3px;\" title=\"angle\" src=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/angle1-300x244.png\" alt=\"\" width=\"300\" height=\"244\" srcset=\"https:\/\/www.tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/angle1-300x244.png 300w, https:\/\/www.tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/angle1.png 608w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Here&#8217;s the Processing routine to calculate the angle.\u00a0 Note that it uses the arctan(x, y) function, which compensates for the fact that you have negative x and y values in some quadrants of the circle.<\/p>\n<pre>\/*\r\n  This method calculates the angle using the X and Y\r\n values of the accelerometer, and the midpoints\r\n of the X and Y ranges\r\n *\/\r\n\r\nfloat calculateRotation(float thisX, float thisY, float midX, float midY) {\r\n  float angle = 0.0;\r\n  \/\/ the opposite side of the triangle is the distance\r\n  \/\/ of the Y point from the middle of the Y range:\r\n\r\n  float opposite = midY-thisY;\r\n  \/\/ the adjacent side of the triangle is the distance\r\n  \/\/ of the X point from the middle of the X range:\r\n  float adjacent = midX-thisX;\r\n  \/\/ you want to avoid a divide by zero error:\r\n  if (adjacent\u00a0!= 0) {\r\n    angle = atan2(opposite, adjacent);\r\n  }\r\n  \/\/ return the angle:\r\n  return angle;\r\n}<\/pre>\n<p>Here&#8217;s the Processing code in full:<\/p>\n<pre>\/**\r\n * Accelerometer rotator\r\n *\r\n * Takes in accelerometer readings serially and uses them to rotate a circle and\r\n * arrow.\r\n *\r\n * Uses a call-and-response serial approach.  Sends newline (\\n) to call\r\n * for more data\r\n * Serial readings are in this format:\r\n * X, Y\r\n *\r\n * created 19 Sep 2008\r\n * by Tom Igoe and Michael Dory\r\n *\r\n * last modified 28 Oct 2008\r\n * by Rory Nugent\r\n *\r\n * Recent Changes: Changed the code to handle raw X-axis and Y-axis values, Processing now calculates the max and min,\r\n * added a rough calibration feature, and added a simple smoothing algorithm to the X-axis and Y-axis values to cut\r\n * down on jitter.\r\n *\r\n *\/\r\n\r\nimport processing.serial.*;\r\n\r\nSerial myPort;        \/\/ instance of the serial library\r\nfloat myX, myY;       \/\/ X and Y readings\r\nfloat myXmax = 0;  \/\/ calculated min and max X value\r\nfloat myXmin = 1023;\r\nfloat myYmax = 0;  \/\/ calculated min and max Y value\r\nfloat myYmin = 1023;\r\nfloat angle;          \/\/ angle to turn arrow to\r\n\r\nfloat lastX = 0;\r\nfloat lastY = 0;\r\n\r\nboolean calibrationComplete = false;\r\n\r\nint numSamplingVals = 5;\r\n\r\nfloat[] recentX = new float[numSamplingVals];\r\nint recentXlength = 0;\r\nint recentXcurrent = 0;\r\n\r\nfloat[] recentY = new float[numSamplingVals];\r\nint recentYlength = 0;\r\nint recentYcurrent = 0;\r\n\r\nvoid setup()\r\n{\r\n  size(600,600);     \/\/ set the window size\r\n  noStroke();        \/\/ no borders on objects you draw\r\n  fill(255);         \/\/ fill with white\r\n  frameRate(30);     \/\/ 30 frames per second\r\n  smooth();          \/\/ smooth the edges\r\n\r\n  \/\/ initialize the serial port:\r\n  println(Serial.list());\r\n  myPort = new Serial(this, Serial.list()[0], 9600);\r\n  \/\/ only generate a serial event if you get a newline:\r\n  myPort.bufferUntil('\\n');\r\n  \/\/ until there's data available, send a\r\n  \/\/ newline character to prompt for data:\r\n  while(myPort.available() &lt; 1) {\r\n    myPort.write(\"\\n\");\r\n  }\r\n\r\n  print(\" *** To calibrate the screen, rotate it all the way to the left, rotate it all the way to the right, and then press ENTER or RETURN ***\\n\");\r\n}\r\n\r\nvoid draw()\r\n{\r\n  \/\/ make the background grey:\r\n  background(102);\r\n  \/\/ draw and rotate the arrow:\r\n  drawArrow(angle);\r\n}\r\n\r\nvoid keyPressed()\r\n{\r\n  if(key == ENTER || key == RETURN){\r\n    if(!calibrationComplete){\r\n        calibrationComplete = true;\r\n        print(\"*** CALIBRATION COMPLETE ***\\n\");\r\n    }\r\n  }\r\n}\r\n\r\nvoid serialEvent(Serial myPort) {\r\n  \/\/ read the serial buffer:\r\n  String myString = myPort.readStringUntil('\\n');\r\n  \/\/ if you got any bytes other than the linefeed:\r\n  if (myString\u00a0!= null) {\r\n    \/\/ trim off excess whitespace (such as the carriage return):\r\n    myString = trim(myString);\r\n\r\n    \/\/ split the string at the commas\r\n    \/\/ and convert the sections into integers:\r\n    int sensors[] = int(split(myString, ','));\r\n    \/\/ if you got all seven numbers:\r\n    if (sensors.length == 2) {\r\n      myX = sensors[0];\r\n      myY = sensors[1];\r\n\r\n      if(!calibrationComplete){\r\n        if(myX &gt; myXmax) myXmax = myX;\r\n        if(myX &lt; myXmin) myXmin = myX;\r\n\r\n        if(myY &gt; myYmax) myYmax = myY;\r\n        if(myY &lt; myYmin) myYmin = myY;\r\n      }\r\n\r\n      \/\/print(myX + \",\" + myXmin + \",\" + myXmax + \",\" + myY + \",\" + myYmin + \",\" + myYmax + \"\\n\");\r\n\r\n      \/\/ store the current X-axis and Y-axis value into an array for smoothing purposes\r\n      recentX[recentXcurrent] = myX;\r\n      recentXcurrent++;\r\n      if(recentXcurrent &gt;= numSamplingVals)\r\n        recentXcurrent = 0;\r\n\r\n      recentY[recentYcurrent] = myY;\r\n      recentYcurrent++;\r\n      if(recentYcurrent &gt;= numSamplingVals)\r\n        recentYcurrent = 0;\r\n\r\n      \/\/ calculate the average of the current samples in the smooth array\r\n      float recentXaverage = 0;\r\n      for(int i=0; i &lt; numSamplingVals; i++)\r\n        recentXaverage = recentXaverage + recentX[i];\r\n      recentXaverage \/= numSamplingVals;\r\n\r\n      float recentYaverage = 0;\r\n      for(int i=0; i &lt; numSamplingVals; i++)\r\n        recentYaverage = recentYaverage + recentY[i];\r\n      recentYaverage \/= numSamplingVals;\r\n\r\n      \/\/ save the smoothing average into the current X-axis and Y-axis for use\r\n      myX = recentXaverage;\r\n      myY = recentYaverage;\r\n\r\n      \/\/ get X and Y, mapped to the window size:\r\n      myX = map(myX, myXmin,myXmax,0,width);\r\n      myY = map(myY, myYmin,myYmax,0,height);\r\n      \/\/ calculate the midpoint of the X range:\r\n      float thisMidX = width\/2;\r\n      \/\/ calculate the midpoint of the Y range:\r\n      float thisMidY = height\/2; \r\n\r\n      \/\/ calculate the angle:\r\n      angle = calculateRotation(myX, myY, thisMidX, thisMidY);\r\n    }\r\n  }\r\n  \/\/ send a newline character to ask for more:\r\n  myPort.write(\"\\n\");\r\n}\r\n\r\n\/*\r\n  This method calculates the angle using the X and Y\r\n values of the accelerometer, and the midpoints\r\n of the X and Y ranges\r\n *\/\r\n\r\nfloat calculateRotation(float thisX, float thisY, float midX, float midY) {\r\n  float angle = 0.0;\r\n  \/\/ the opposite side of the triangle is the distance\r\n  \/\/ of the Y point from the middle of the Y range:\r\n\r\n  float opposite = midY-thisY;\r\n  \/\/ the adjacent side of the triangle is the distance\r\n  \/\/ of the X point from the middle of the X range:\r\n  float adjacent = midX-thisX;\r\n  \/\/ you want to avoid a divide by zero error:\r\n  if (adjacent\u00a0!= 0) {\r\n    angle = atan2(opposite, adjacent);\r\n  }\r\n  \/\/ return the angle:\r\n  return angle;\r\n}\r\n\r\n\/*\r\n  This method draws and rotates the arrow\r\n *\/\r\nvoid drawArrow(float thisAngle) {\r\n  \/\/ move whatever you draw next so that (0,0) is centered on the screen:\r\n  translate(width\/2, height\/2);\r\n\r\n  \/\/ draw a circle in light blue:\r\n  fill(80,200,230);\r\n  ellipse(0,0,50,50);\r\n  \/\/ make the arrow black:\r\n  fill(0);\r\n  \/\/ rotate using the heading:\r\n  rotate((thisAngle));\r\n\r\n  \/\/ draw the arrow.  center of the arrow is at (0,0):\r\n  triangle(-10, 0, 0, -20, 10, 0);\r\n  rect(-2,0, 4,20);\r\n}<\/pre>\n<h2>Part 4: The Installation<\/h2>\n<p>Once the code&#8217;s working, it&#8217;s simply a matter of installing the hardware on the back of the plasma.\u00a0 You need to align it with the screen&#8217;s edges, but a little gaffer&#8217;s tape holds it in nicely:<\/p>\n<p style=\"text-align: center;\"><a href=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/accelerometer_mounted.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-230 aligncenter\" title=\"accelerometer_mounted\" src=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/accelerometer_mounted-300x225.jpg\" alt=\"\" width=\"300\" height=\"225\" srcset=\"https:\/\/www.tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/accelerometer_mounted-300x225.jpg 300w, https:\/\/www.tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/accelerometer_mounted.jpg 600w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Once you&#8217;re all mounted, run the processing sketch, and your screen should know which way is up.<\/p>\n<p style=\"text-align: center;\"><a href=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/rotated_screen_21.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-233\" title=\"rotated_screen_21\" src=\"https:\/\/tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/rotated_screen_21-300x225.jpg\" alt=\"\" width=\"300\" height=\"225\" srcset=\"https:\/\/www.tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/rotated_screen_21-300x225.jpg 300w, https:\/\/www.tigoe.com\/pcomp\/code\/wp-content\/uploads\/2008\/09\/rotated_screen_21.jpg 600w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p style=\"text-align: left;\"><em>Thanks to Mike Dory for the pix and code encouragement, and Rory Nugent for the code improvements!<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>ITP just got some nifty flat panel mounts that can rotate 360 degrees. They&#8217;re very easy to move, it takes only one hand. When I saw them, I thought, &#8220;what good is a rotating mount if the content on the screen can&#8217;t rotate too?&#8221; So I came up with a little system to sense the &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.tigoe.com\/pcomp\/code\/arduinowiring\/216\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Using an Accelerometer to Sense Which Way Is Up&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,24],"tags":[36,37,31,30,38],"class_list":["post-216","post","type-post","status-publish","format-standard","hentry","category-arduinowiring","category-circuits","tag-accelerometer","tag-arduino","tag-pcomp","tag-physical-computing","tag-rotation-sensing"],"_links":{"self":[{"href":"https:\/\/www.tigoe.com\/pcomp\/code\/wp-json\/wp\/v2\/posts\/216","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tigoe.com\/pcomp\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tigoe.com\/pcomp\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tigoe.com\/pcomp\/code\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tigoe.com\/pcomp\/code\/wp-json\/wp\/v2\/comments?post=216"}],"version-history":[{"count":25,"href":"https:\/\/www.tigoe.com\/pcomp\/code\/wp-json\/wp\/v2\/posts\/216\/revisions"}],"predecessor-version":[{"id":243,"href":"https:\/\/www.tigoe.com\/pcomp\/code\/wp-json\/wp\/v2\/posts\/216\/revisions\/243"}],"wp:attachment":[{"href":"https:\/\/www.tigoe.com\/pcomp\/code\/wp-json\/wp\/v2\/media?parent=216"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tigoe.com\/pcomp\/code\/wp-json\/wp\/v2\/categories?post=216"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tigoe.com\/pcomp\/code\/wp-json\/wp\/v2\/tags?post=216"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}