1

I need to find the angle of rotation (please see the picture) when the round plate is turning. I actually need only one angle of rotation, but with data obtained through Sensors2OSC from Samsung Galaxy S4. This app enables me to receive Accelerometer and Gyroscope float data to processing over OSC. The phone is mounted on the back of plate..

https://github.com/SensorApps/Sensors2OSC

Which method provides the most accurate result, which sensors I have to use for sensor fusion??

image


import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myRemoteLocation;

LowPass lp;
float number1 = 0.0;

void setup() {
  size(1200, 600, P3D);
  oscP5 = new OscP5(this, 9000);
  lp = new LowPass(10);  //The argument is the FIFO queue length
}

void draw() {
  background(0);
  lights();

  pushMatrix(); 
  translate(300, height/2, -100); 
  rotateZ(-number1);
  box(330, 200, 40);
  popMatrix();

  pushMatrix(); 
  translate(900, height/2, -100);
  lp.input(number1);
  rotateZ(lp.output);
  box(330, 200, 40);
  popMatrix();
}

/* incoming osc message are forwarded to the oscEvent method. */
void oscEvent(OscMessage theOscMessage) {

  if ( theOscMessage.addrPattern().equals("/rotationvector/z") );
  number1 = theOscMessage.get(0).floatValue();
}

class LowPass {
  ArrayList buffer;
  int len;
  float output;

  LowPass(int len) {
    this.len = len;
    buffer = new ArrayList(len);
    for (int i = 0; i < len; i++) {
      buffer.add(new Float(0.0));
    }
  }

  void input(float v) {
    buffer.add(new Float(v));
    buffer.remove(0);

    float sum = 0;
    for (int i=0; i<buffer.size (); i++) {
      Float fv = (Float)buffer.get(i);
      sum += fv.floatValue();
    }
    output = sum / buffer.size();
  }
}
Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997
potter3366
  • 31
  • 4

4 Answers4

1

It sounds like you're not asking how to get the sensor values from the phone itself. You're already getting the sensor value from Sensors2OSC, which is sending them to Processing over OSC. You're probably using something like oscP5.

I think you're asking how to parse the messages coming into your Processing sketch so you have access to the sensor values in your Processing code, and then how to translate those sensor values into an angle.

Step 1 is to get the messages coming over OSC. You can find an example here, and the function you care about is the oscEvent(OscMessage theOscMessage) function.

Once you have that working, step 2 is to parse the data coming over the messages. You can check out the OscMessage documentation for a list of functions that might come in handy. Your end goal is to have something like this:

void oscEvent(OscMessage theOscMessage) {
   float xAccel = //parse theOscMessage to get X accelerometer reading
   float yAccel = //parse theOscMessage to get Y accelerometer reading
   float zAccel = //parse theOscMessage to get Z accelerometer reading

   println(xAccel + ", " + yAccel + ", " + zAccel);
}

Step 3 is to then translate those raw accelerometer values into an angle. Googling "android accelerometer to angle" returns a ton of results, including:

Your goal is to have something like this:

void oscEvent(OscMessage theOscMessage) {
   float xAccel = //parse theOscMessage to get X accelerometer reading
   float yAccel = //parse theOscMessage to get Y accelerometer reading
   float zAccel = //parse theOscMessage to get Z accelerometer reading

   float angle = //calculate angle
   println(angle);
}

From there you can do whatever you want with the angle value. Note that it might be slightly more complicated than that, since I'm not sure if your Android app is going to send all of the accelerometer values in one message, or if it'll be split up into multiple messages. You're going to have to play around until you really understand what the messages contain.

Community
  • 1
  • 1
Kevin Workman
  • 39,413
  • 8
  • 61
  • 94
  • My problem is to choose the appropriate sensor fusion on processing side. What would be the best way to manipulate the data to accurately measure angles? Accelerometer sensor not providing very accurate data when it used alone.. – potter3366 Mar 19 '16 at 13:31
  • @potter3366 I understand that. Check out the google search and the four links I gave you. – Kevin Workman Mar 19 '16 at 13:34
  • It seems that virtual sensor ROTATION VECTOR gives the best results. Now these values must be converted into the corresponding angle.. – potter3366 Mar 19 '16 at 14:28
1
import oscP5.*;
import netP5.*;
import toxi.geom.*;

OscP5 oscP5;
NetAddress myRemoteLocation;

float number0 = 0.0;
float number1 = 0.0;
float number2 = 0.0;
float number3 = 0.0;

float[] axis = new float[3];
Quaternion quat = new Quaternion(1, 0, 0, 0);

void setup() {
  size(1200, 600, P3D);
  oscP5 = new OscP5(this, 9000);
}

void draw() {
  background(0);
  lights();

  quat.set(number0, number1, number2, number3);
  axis = quat.toAxisAngle();

  pushMatrix(); 
  translate(width/2, height/2, -100);
  rotate(axis[0], axis[1], axis[2], axis[3]);
  box(330, 200, 40);
  popMatrix();
}

/* incoming osc message are forwarded to the oscEvent method. */
void oscEvent(OscMessage theOscMessage) {

  if ( theOscMessage.addrPattern().equals("/rotationvector/X") )
    number1 = theOscMessage.get(0).floatValue();
  if ( theOscMessage.addrPattern().equals("/rotationvector/Y") )
    number2 = theOscMessage.get(0).floatValue();
  if ( theOscMessage.addrPattern().equals("/rotationvector/Z") )
    number3 = theOscMessage.get(0).floatValue();
  if ( theOscMessage.addrPattern().equals("/rotationvector/cos") )
    number0 = theOscMessage.get(0).floatValue();
}
potter3366
  • 31
  • 4
  • I have used toxiclibs to converts the quaternion (ROTATION VECTOR) into a float array consisting of: rotation angle in radians, rotation axis x,y,z...but still need improvement... – potter3366 Mar 19 '16 at 15:55
1

Here is the solution with only one sensor - accelerometer + low pass filter

TODO: combine the accelerometer and gyroscope data + Kalman or Complementary Filter

It is necessary to know gyroscope offset value and gyro sensitivity to implement Complementary filter. Where I can find this values for Samsung Galaxy?

Processing these data offline in processing and get accurate orientation is hard, because some functions should be implemented in processing which are already implemented in android (such as SensorManager.getRotationMatrix)..

http://plaw.info/2012/03/android-sensor-fusion-tutorial/

import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myRemoteLocation;

float number1, number1a;
float number2, number2a;
float number3, number3a;
float r, b;
float x1, y1, x2, y2, cx, cy, a1, b1;
int rec1x = 150, rec1y = 150;

LowPass lp;

void setup() {
  size(550, 550);
  lp = new LowPass(10);
  oscP5 = new OscP5(this, 9000);
}

void draw() {
  background(50);

  b = number2 / sqrt(number1 * number1 + number3 * number3);
  r = atan(b); 

  //accelerometer
  noStroke();
  fill(50, 20, 200, 80);
  rect(rec1x, rec1y, 250, 250);
  fill(0);
  ellipse(rec1x + (250/2), rec1y + (250/2), 240, 240);

  //acc_line
  cx = rec1x + (250/2);
  cy = rec1y + (250/2);
  lp.input(r);
  a1 = 120 * cos(lp.output);
  b1 = 120 * sin(lp.output);
  x1 = cx - a1;
  y1 = cy - b1;
  x2 = cx + a1;
  y2 = cy + b1;
  stroke(2, 2, 255);
  strokeWeight(3);
  line(x1, y1, x2, y2);
}

/* incoming osc message are forwarded to the oscEvent method. */
void oscEvent(OscMessage theOscMessage) {

  if ( theOscMessage.addrPattern().equals("/accelerometer/X") )
    //if ( theOscMessage.addrPattern().equals("/linearacceleration/X") )
    number1 = theOscMessage.get(0).floatValue();
  if ( theOscMessage.addrPattern().equals("/accelerometer/Y") )
    //if ( theOscMessage.addrPattern().equals("/linearacceleration/Y") )
    number2 = theOscMessage.get(0).floatValue();
  if ( theOscMessage.addrPattern().equals("/accelerometer/Z") )
    //if ( theOscMessage.addrPattern().equals("/linearacceleration/Z") )
    number3= theOscMessage.get(0).floatValue();
  if ( theOscMessage.addrPattern().equals("/gyroscope/X") )
    number1a = theOscMessage.get(0).floatValue();
  if ( theOscMessage.addrPattern().equals("/gyroscope/Y") )
    number2a = theOscMessage.get(0).floatValue();
  if ( theOscMessage.addrPattern().equals("/gyroscope/Z") )
    number3a = theOscMessage.get(0).floatValue();
}

class LowPass {
  ArrayList buffer;
  int len;
  float output;

  LowPass(int len) {
    this.len = len;
    buffer = new ArrayList(len);
    for (int i = 0; i < len; i++) {
      buffer.add(new Float(0.0));
    }
  }

  void input(float v) {
    buffer.add(new Float(v));
    buffer.remove(0);

    float sum = 0;
    for (int i=0; i<buffer.size (); i++) {
      Float fv = (Float)buffer.get(i);
      sum += fv.floatValue();
    }
    output = sum / buffer.size();
  }
}
potter3366
  • 31
  • 4
-1

Just instantiate an OrientationEventListener object. The onOrientationChanged method will give you the angle of rotation.

Hoan Nguyen
  • 17,479
  • 3
  • 47
  • 51