How to create a graphical interface for the Tinkerkit! Gyro module

Introduction / Objectives: 

In this tutorial we realize a graphical user interface with Processing to display data received from the Tinkerkit! Gyro module.

Part list: 

1 Arduino Uno
1 Tinkerkit gyroscope module T00064
1 Tinkerkit Shield
2 Tinkerkit connection wires

Instructions: 

General description of the gyroscope module

The MEMS gyroscope is a sensor that can measure the angular velocity, especially this one that is mounted on this module is manufactured by ST and is called LPR5150AL. The outputs are analog values ​​and the maximum angular velocities that can be read are ± 6000 ° / s for non-amplified outputs and ± 1500 ° / s for 4x amplified outputs.
Because the sensor works with 3.3V logic, the tinker module is also concerned to provide the proper supply and to adapt the outputs to be optimally read from Arduino.



 

This sensor is sensitive to rotations that can occur on two axes: X (pitch) and Y (roll), interface it is very simple because its outputs are analog, so you just connect each output to an analog input of Arduino.
In a situation where the sensor is stationary, its outputs will measure a voltage of 2.46V, while for positive rotation this value will grow up to 4.47V (@ 1500 deg / s) on the contrary, the value will fall negative for rotations up to arrive at 0.45V (@ -1500 ° / s). Positive rotation, by convention, means counterclockwise rotation (as shown in the figure) and negative for clockwise rotations.

What to do on the Arduino side

This module is available in two versions, with pins for breadboard connection and with standard tinkerkit connectors, in this case we use the tinkerkit because it makes very simple connections. Mount on top of the Arduino the Tinker! Sensor shield and connect the X-axis of the gyroscope to I0, then the Y-axis to I1, using the appropriate cables.



 

The sample sketch that you can be find on the product page on the store, is a basic example of how to read, interpret and transform data from the gyro properly.
As this sketch  also provide to write on serial all the results, rather than read through the serial port monitor, we can make them more readable by displaying them in graphical processing.

Processing: build the interface

One way to show the angular velocity in order to make reading more immediate and readable is to place the instantaneous values​​ into a graph, and slide them on the horizontal axis as time passes. To display the angular position, obtained from the integration of angular velocity, it is natural to think to a pointer, with one end attached to a center and the other end that can rotate around, just like a clock.

step 1: interpret what comes from the serial

Arduino on serial, send strings like this one:

Roll_speed: 467     Roll_Angle: 69     Pitch_speed: -795     Pitch_Angle: 230     Servo: 159

where each reading is separated from the next by a special character "\ t", called horizontal tab and each number is separated by a space from his own label, so you can identify where the data is contained in the string and build a parser for capture information from graphs.

void serialEvent(Serial p) {
 myString = p.readStringUntil(lf);
  if (myString != null) {
    temp = myString.split(" |\t");
    rollSpeed = parseInt(temp[1]);
    rollAngle = parseInt(temp[3]);
    pitchSpeed = parseInt(temp[5]);
    pitchAngle = parseInt(temp[7]);

    println(rollSpeed+"  "+rollAngle+"  "+pitchSpeed+"  "+pitchAngle);
  }
}

This function is activated every time something is written on the serial port and the instruction split () takes care of dividing the string received in a number of different substrings, each time encounter a character described above.



 

step 2: angular position indicators

Each indicator of the angular position is composed by a circle and a straight line, with one end fixed in the center of the circle, which rotates respect to this point by an amount given by the angular position data received from Arduino. To rotate the line we must first convert the string containing the angle in a number, and instructions to do this are:

rollAngle = parseInt(temp[3]);
pitchAngle = parseInt(temp[7]);

while the rotation is made by the breakdown in the two Cartesian components of the angle. To use the trigonometric functions must express the angle in radians:

float gyroY_radians = radians(-rollAngle)-HALF_PI;
  line( (width-70), (height-300), (width-70)+(60*cos(gyroY_radians)), (height-300)+(60*sin(gyroY_radians)) );

step 3: Angular velocity graph

To obtain an oscilloscope-style graphics, that what is plotted is a function of time, is sufficient to draw the last data received in the same position and move of one position the previously read data. To do this you need to keep in memory a part of the previous readings, enough to fill the screen.

void graphMeThis(float inData, int[] graphBuffer, int xPos, int yPos, int ySpan)
{  
// For each frame the buffer that contains the older samples are shifted by one position
  for (int i=0; i<(width-xPos)-1; i++)  
    graphBuffer[i] = graphBuffer[i+1];
  // Store the new entry data
  graphBuffer[(width-xPos)-1] = (int)map(inData, -3000, 3000, -ySpan/2, ySpan/2);  //salvo il nuovo dato...che plotto alla fine del grafico
  stroke(#E2F520, 150);
  strokeWeight(2);
  // plot the graph that goes from right to left
  for (int x=(width-xPos); x>1; x--)
    line( x, (height-yPos)-graphBuffer[x-1], x+1, (height-yPos)-graphBuffer[x]);
  noStroke();
  strokeWeight(1);
}

This function takes care of that described above and in addition allows you to place the chart in a specified region of the window and decide how many pixels you want it to be the height of the graph.
Note that the speed with which the graph will scroll on the screen can be adjusted by setting the frame rate refresh of the application. Considering that the Arduino sends data every 48 milliseconds, you can calculate the minimum frame rate required to display all the values​​, simply counting how many of these events happen in a second, about 21. More the frame rate will be greater than the value found, more two subsequent readings will be spaced on the screen; for a  pleasant visualization I chose 30. In processing, you can set the frame rate, placing the function frameRate() in setup ().

Complete code

 

/* -------+ TinkerKit! Gyroscope Module T000062 Dashboard +-------
 
 This processing sketch grab data from an analog 2-axis Gyroscope
 connected to Arduino, plot the angular rate readings into a graph;
 then transform them into an angular position (inclination) trought
 integration over time, dislpaying them into gauges.
 
 Look on the product page for the Gyroscope specifiations:
 http://tinkerkit.com/en/Modules/T000062
 
 Connect the gyroscope with two Toolkit wires to the Tinkerkit!
 sensor shield into I0 and I1.
 
 The values displayed on this GUI comes from a specific sketch that must be 
 uploaded on the Arduino board.
 
 created 17 Sept 2011
 by Federico Vanzati
 
 This example code is in the public domain.
 -----------------------------------------------------------------
*/

import processing.serial.*;  // Enable processing to use the serial port

Serial myPort;  // Create object from Serial class
String myString = null;
String[] temp;
int lf = 10; 

// Timing variables
int refreshScreen = 0;

// Variables to transform data into physical measurement
int rollSpeed, rollAngle, pitchSpeed, pitchAngle;
String y_speed_string, x_speed_string, y_angle_string, x_angle_string;
int offsetX, offsetY;

// Variables for displayng data
int[] y_rateVideoBuffer, x_rateVideoBuffer;
String str_yAngle, str_yGyroRate, str_xAngle, str_xGyroRate;


void setup()
{
  size(700, 440);  

  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 115200);
  // wait a little to give time to Arduino to be initialized
  delay(500);

  frameRate(60);

  y_rateVideoBuffer = new int[width]; 
  x_rateVideoBuffer = new int[width];

  PFont font;
  font = loadFont("Monospaced.bold-26.vlw");
  textFont(font);

  smooth(); // smoothed shapes looks better!
}


void draw() {
  background(0);
  fill(#088D9D);  // little blue
  stroke(255);

  //NOTE: measure taken from the centre
  ellipse(width-70, height-300, 120, 120);  // the circles
  ellipse(width-70, height-100, 120, 120);  // -> our gauges!

  // Strings composition
  textSize(26);
  text("[Y] GYRO_Y speed: "+y_speed_string+"°/s", 10, 70);
  text("[X] GYRO_X speed: "+x_speed_string+"°/s", 10, 270);
  text("Angle", (width-120), 70);
  text("Angle", (width-120), 270);
  text(y_angle_string+"°", (width-120), (height-210));
  text(x_angle_string+"°", (width-120), (height-10) );
  textSize(28);
  fill(#C63906);  // orange
  text("TinkerKit!  2-Axis Gyroscope [T000062]", 28, 28);
  textSize(15);
  text("Reset Arduino to re-calibrate the Gyro", 10, (height -5));

  // Draw the gauges indicator. Will display the inclination
  strokeWeight(3);
  float gyroY_radians = radians(-rollAngle)-HALF_PI;
  line( (width-70), (height-300), (width-70)+(60*cos(gyroY_radians)), (height-300)+(60*sin(gyroY_radians)) );

  float gyroX_radians = radians(-pitchAngle)-PI;
  line( (width-70), (height-100), (width-70)+(60*cos(gyroX_radians)), (height-100)+(60*sin(gyroX_radians)) );
  strokeWeight(1);

  // call the function that plot the angular velocities, with few screen settings
  graphMeThis(rollSpeed, y_rateVideoBuffer, 140, 300, 140);
  graphMeThis(pitchSpeed, x_rateVideoBuffer, 140, 100, 140);
}


void serialEvent(Serial p) {
  myString = p.readStringUntil(lf);  // Receive one reading from Arduino
  if (myString != null) {
    temp = myString.split(" |\t");  // Split the informations that are separated by space and tab ASCII characters

    if (temp[0].equals("Roll_Rate:")) {
      rollSpeed = parseInt(temp[1]);
      y_speed_string = temp[1];

      rollAngle = parseInt(temp[3]);
      y_angle_string = temp[3];
     
      pitchSpeed = parseInt(temp[5]);
      x_speed_string = temp[5];

      pitchAngle = parseInt(temp[7]);
      x_angle_string = temp[7];
    }
    println(rollSpeed+"  "+rollAngle+"  "+pitchSpeed+"  "+pitchAngle);
  }
}

/*
This function plot data over screen in a xPos and yPos given position.
 [ySpan] is expressed in pixel and indicates the heigth that you give to the graph
 */
void graphMeThis(float inData, int[] graphBuffer, int xPos, int yPos, int ySpan)
{
  // For each frame the buffer that contains the older samples are shifted by one position
  for (int i=0; i<(width-xPos)-1; i++)  
    graphBuffer[i] = graphBuffer[i+1];
  // Store the new entry data
  graphBuffer[(width-xPos)-1] = (int)map(inData, -1500, 1500, -ySpan/2, ySpan/2);  //save the new data...and plot it at the end of the graph
  stroke(#E2F520, 150);  //yellow with transparency
  strokeWeight(2);
  // plot the graph that goes from right to left
  for (int x=(width-xPos); x>1; x--)
    line( x, (height-yPos)-graphBuffer[x-1], x+1, (height-yPos)-graphBuffer[x]);
  noStroke();
  strokeWeight(1);
}

For the Y axis starting position of the pointer is 90 °, while the X axis is 180, respecting the axes directions drawn on the sensor.
Each time you press the Reset button on the Arduino, this restarts the calibration of the sensor, so it is still necessary to maintain the gyro in a horizontal position for a couple of seconds.
Since the gyroscopes are not made to measure absolute angular position over time they are subject to a drift angle phenomenon, so to have correspondence between the gyro and tilt angle of the pointer, you must occasionally recalibrate the gyro. To do this you must close and re-open the Processing application each time you reset the Arduino.

Images: 
AttachmentSize
gyroguifromarduino.zip25.13 KB

Comments

 
Loading...