Android accelerometer angle calculation - android

Can anyone give any idea to calculate the angle by which a compass needle should be rotated to point in the direction of gravity from accelerometer x, y, z values?

I think X should be 0 and y should be positive while z is near 0 for the compass to point down towards earth.
(Which means the phone is held vertical).
In general, from the 0 angle, the compass' angle should be something like
float accelerometerMaxRange = 10; // This is NOT right, but it's a good value to work with
float newAngle = 0;
if (z > 9) {
// Phone is horizontally flat, can't point towards gravity, really. Do whatever you think is right
} else {
newAngle = (float)(x * 90 / accelerometerMaxRange);
if (y < 0) {
newAngle = 180 - newAngle;
}
}

Related

Drawing stripes in a flag math formula

I have a rectangle with known size and position. (flag)
I have to fill this rectangle with 4 other rectangles. (stripes)
Each stripe must have 1/4 of the total width of the flag and his position is near the previous.
I have to draw this stripes with a random angle that goes from 0° to 90°.
0° = Vertical stripes (stripe width = flag width / 4)
90° = Horizontal stripes (stripe width = flag height / 4)
How can I calculate the width of each stripe for other angles?
int stripes = 4;
RectF rect = new RectF(0, 0, 100f, 75f);
float angle = new Random.nextInt(90);
float stripeSize;
if (angle == 0) {
stripeSize = rect.width() / stripes;
} else if (angle == 90) {
stripeSize = rect.height() / stripes;
} else {
stripeSize = ?
}
canvas.save();
canvas.rotate(angle, rect.centerX(), rect.centerY());
float offset = 0;
for (int i = 0; i < stripes; i++) {
if (angle == 0) {
reusableRect.set(offset, rect.top, offset + stripeSize, rect.bottom);
} else if (angle == 90) {
reusableRect.set(rect.left, offset, rect.right, offset + stripeSize);
} else {
reusableRect.set(?, ?, ?, ?);
}
canvas.drawRect(reusableRect, paint);
offset += stripeSize;
}
canvas.restore();
Let's pretend you have one stripe. Depending on the angle, the stripe width is going to be a value between the shorter dimension (the height in your case) and the longer dimension (the width in your case). The formula for the stripe width calculation should look something like this:
height + ((width - height) * ?)
where ? varies between 0 and 1 based on the angle of rotation. To me that sounds like the sine function might be a good candidate: sine(0) = 0 and sine(90) = 1. You can use Math.sin(), but be aware that the argument it takes is in radians, not degrees, so you need to use Math.toRadians() on your angle first. Then just divide by the number of stripes:
double radians = Math.toRadians(angle);
float stripeTotal = height + ((width - height) * Math.sin(radians));
float stripeWidth = stripeTotal / 4; // or however many stripes you have
If it's not perfect, you can adjust the formula. One last point, since these values only need to be calculated once, I would do that separately every time the angle changes (if it ever changes), not inside of onDraw().

pitch value is -90 degree to 90 degree when reading orientation from android

I am reading the orientation values of the phone, the azimuth and roll data are quite OK as they are -180 to 180, but I have problem on pitch as it is -90 to 90 only when I rotate the phone from 0 degree to 360 degree.
SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
SensorManager.getOrientation(mRotationMatrix, orientationVals);
float azimuth = (float)Math.toDegrees(orientationVals[0]);
float pitch = (float)Math.toDegrees(orientationVals[1]);
float roll = (float)Math.toDegrees(orientationVals[2]);
float deltaX = Math.abs(mLastOrientation[0] - azimuth);
float deltaY = Math.abs(mLastOrientation[1] - pitch);
float deltaZ = Math.abs(mLastOrientation[2] - roll);
if (deltaX < ORIENTATIONNOISE) azimuth = mLastOrientation[0];
if (deltaY < ORIENTATIONNOISE) pitch = mLastOrientation[1];
if (deltaZ < ORIENTATIONNOISE) roll = mLastOrientation[2];
mLastOrientation[0] = azimuth;
mLastOrientation[1] = pitch;
mLastOrientation[2] = roll;
Could anyone help. Thanks
That strikes me as normal. If you think about it, pitch is essentially latitude in device coordinates, and latitude can't have a magnitude greater than 90 degrees - at that point (aka the north & south poles), it wraps around and begins to decrease again.

Drawing an arrow head in android

I am trying to draw an arrow to point to objects in am image. I have been able to write code to draw the line but cant seem to be able to find a way to draw the arrowhead.The code I wrote to draw a dragabble line is as follows.I need to draw an arrowhead on ACTION_UP event to the direction in which the line is pointing
if(event.getAction() ==MotionEvent.ACTION_DOWN) {
if (count==1){
x1 = event.getX();
y1 = event.getY();
System.out.println(count+"count of value a;skd");
Toast.makeText(getApplicationContext(), ""+(radius+count), Toast.LENGTH_LONG).show();
Log.i(TAG, "coordinate x1 : "+String.valueOf(x1)+" y1 : "+String.valueOf(y1));
}
}
else if(event.getAction() ==MotionEvent.ACTION_MOVE){
imageView.setImageBitmap(bmp2);
x2 = event.getX();
y2 = event.getY();
posX=(float)(x1+x2)/2;
posY=(float)(y1+y2)/2;
radius=(float) Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))/2;
onDraw();
Toast.makeText(getApplicationContext(), ""+radius, Toast.LENGTH_LONG).show();
}
Hi, for anyone still needing help .This is how I did it in the end
float h=(float) 30.0;
float phi = (float) Math.atan2(y2 - y1, x2 - x1);
float angle1 = (float) (phi - Math.PI / 6);
float angle2 = (float) (phi + Math.PI / 6);
float x3 = (float) (x2 - h * Math.cos(angle1));
float x4 = (float) (x2 - h * Math.cos(angle2));
float y3 = (float) (y2 - h * Math.sin(angle1));
float y4 = (float) (y2 - h * Math.sin(angle2));
c.drawLine(x1, y1,x2,y2 ,pnt);
c.drawLine(x2, y2,x3,y3 ,pnt);
c.drawLine(x2, y2,x4,y4 ,pnt);
I got help from the accepted answer and ios section in stackoverflow
How I would do this is to find the slope of the line, which is drawn between two points(start and end). The slope would be (dy/dx), and that would be a good start point for your arrow. Assuming you want the base of the arrowhead to be perpendicular to the line of the arrow, to find the slope of the base you would find the opposite reciprocal of the slope of the line. for example, lets say that your line has a slope of 2. The slope for the base of your triangle would be (-1/2), because you do (1/(oldslope)) and multiply by -1. I don't know android very well, but if I remember correctly, in Java, you would use a drawPolygon method, and you would have to specify 4 points(3 unique and 1 the same as the first to close it). Given the slope of the base of the tip, we can get our first two points and our final point. You should know before you start the dimensions of the arrowhead you wish to draw, so in this case b will be the length of your baseline. If you take ϴ=arctan(dy/dx), that will give you an angle between the x axis and your baseline. With that ϴ value, you can do ydif = b*sin(ϴ) to get the difference in y value between the two base corners of your arrow. Doing the same thing but with xdif = b*cos(ϴ) gives you the difference in the x value between the two base points. If the location of the final point of the line that the user drew is, say, (x1, y1), then the locations of the basepoints of the triangle would be (x1-(xdif/2), y1-(ydif/2)) and (x1+(xdif/2), y1+(ydif/2)). These two points, p1 and p2, are the first, second, and fourth points in the draw polygon method. To find the third point, we need to find the angle of the original line, by doing ϴ=arctan(dy/dx), this time using your original dy/dx. with that angle. Before we finish the actual calculation of the point, you first have to know how far from the end of your line the tip of the arrow should actually be, in my case, I will use the var h and h = 10. To get the cordinate, (x,y), assuming the cordinate for the line tip is (x1, y1)you would do (x1+hcosϴ, y1+hsinϴ). Use that for the third value in drawPolygon(), and you should be done. sorry if I kind of rushed at the end, I got kind of tired of typing, comment if you need help.
If you managed to draw a line from the input event, you might additionally draw a triangle on its end indicating the direction.
On another project I drew a square everytime a magnetic point on a grid was touched (as you can see here) Sorry I can not provide you any sample code right now. But if that's a suitable approach for you, I might post it later.
Here is a good code, its not mine, It was a Java Graphics2D code that I converted to Canvas. All credit go to the original guy/lady who wrote it
private void drawArrowHead(Canvas canvas, Point tip, Point tail)
{
double dy = tip.y - tail.y;
double dx = tip.x - tail.x;
double theta = Math.atan2(dy, dx);
int tempX = tip.x ,tempY = tip.y;
//make arrow touch the circle
if(tip.x>tail.x && tip.y==tail.y)
{
tempX = (tip.x-10);
}
else if(tip.x<tail.x && tip.y==tail.y)
{
tempX = (tip.x+10);
}
else if(tip.y>tail.y && tip.x==tail.x)
{
tempY = (tip.y-10);
}
else if(tip.y<tail.y && tip.x==tail.x)
{
tempY = (tip.y+10);
}
else if(tip.x>tail.x || tip.x<tail.x)
{
int rCosTheta = (int) ((10)*Math.cos(theta)) ;
int xx = tip.x - rCosTheta;
int yy = (int) ((xx-tip.x)*(dy/dx) + tip.y);
tempX = xx;
tempY = yy;
}
double x, y, rho = theta + phi;
for(int j = 0; j < 2; j++)
{
x = tempX - arrowLength * Math.cos(rho);
y = tempY - arrowLength * Math.sin(rho);
canvas.drawLine(tempX,tempY,(int)x,(int)y,this.paint);
rho = theta - phi;
}
}
Just call this for both sides of your line and it will draw an arrow at each side!

Rotating an ImageView like a compass (with the "north pole" set elsewhere)

I'm stumped regarding how to implement a "personal compass", ie a compass that points to a specific bearing instead of the standard "north pole"... unfortunatly, my current attempt has come out wrong (doesn't point at the given bearing). It's also hooked up with the accelerator to be able to dynamically adjust itself based on which way the user is turning.
Here's my current attempt at it (the onSensorChanged()-method that updates the arrow):
public void onSensorChanged( SensorEvent event ) {
// If we don't have a Location, we break out
if ( LocationObj == null ) return;
float azimuth = event.values[0];
float baseAzimuth = azimuth;
GeomagneticField geoField = new GeomagneticField( Double
.valueOf( LocationObj.getLatitude() ).floatValue(), Double
.valueOf( LocationObj.getLongitude() ).floatValue(),
Double.valueOf( LocationObj.getAltitude() ).floatValue(),
System.currentTimeMillis() );
azimuth += geoField.getDeclination(); // converts magnetic north into true north
//Correct the azimuth
azimuth = azimuth % 360;
//This is where we choose to point it
float direction = azimuth + LocationObj.bearingTo( destinationObj );
rotateImageView( arrow, R.drawable.arrow, direction );
//Set the field
if( baseAzimuth > 0 && baseAzimuth < 45 ) fieldBearing.setText("S");
else if( baseAzimuth >= 45 && baseAzimuth < 90 ) fieldBearing.setText("SW");
else if( baseAzimuth > 0 && baseAzimuth < 135 ) fieldBearing.setText("W");
else if( baseAzimuth > 0 && baseAzimuth < 180 ) fieldBearing.setText("NW");
else if( baseAzimuth > 0 && baseAzimuth < 225 ) fieldBearing.setText("N");
else if( baseAzimuth > 0 && baseAzimuth < 270 ) fieldBearing.setText("NE");
else if( baseAzimuth > 0 && baseAzimuth < 315 ) fieldBearing.setText("E");
else if( baseAzimuth > 0 && baseAzimuth < 360 ) fieldBearing.setText("SE");
else fieldBearing.setText("?");
}
And here's the method that rotates the ImageView (rotateImageView()):
private void rotateImageView( ImageView imageView, int drawable, float rotate ) {
// Decode the drawable into a bitmap
Bitmap bitmapOrg = BitmapFactory.decodeResource( getResources(),
drawable );
// Get the width/height of the drawable
DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = bitmapOrg.getWidth(), height = bitmapOrg.getHeight();
// Initialize a new Matrix
Matrix matrix = new Matrix();
// Decide on how much to rotate
rotate = rotate % 360;
// Actually rotate the image
matrix.postRotate( rotate, width, height );
// recreate the new Bitmap via a couple conditions
Bitmap rotatedBitmap = Bitmap.createBitmap( bitmapOrg, 0, 0, width, height, matrix, true );
//BitmapDrawable bmd = new BitmapDrawable( rotatedBitmap );
//imageView.setImageBitmap( rotatedBitmap );
imageView.setImageDrawable(new BitmapDrawable(getResources(), rotatedBitmap));
imageView.setScaleType( ScaleType.CENTER );
}
Any help would be much appreciated, as I don't quite know how to proceed. The "readings" I'm getting while trying it out is somewhat inaccurate and points in the wrong direction. Am I doing something really off, or did I just have a really bad test-run?
Your rotateImageView function should work just fine, however there are some things that needs to be changed in your rotation calculations.
//This is where we choose to point it
float direction = azimuth + LocationObj.bearingTo( destinationObj );
rotateImageView( arrow, R.drawable.arrow, direction );
The problem is that bearingTo will give you a range from -180 to 180, which will confuse things a bit. We will need to convert this value into a range from 0 to 360 to get the correct rotation.
This is a table of what we really want, comparing to what bearingTo gives us
+-----------+--------------+
| bearingTo | Real bearing |
+-----------+--------------+
| 0 | 0 |
+-----------+--------------+
| 90 | 90 |
+-----------+--------------+
| 180 | 180 |
+-----------+--------------+
| -90 | 270 |
+-----------+--------------+
| -135 | 225 |
+-----------+--------------+
| -180 | 180 |
+-----------+--------------+
Even though the bearingTo is in the range -180 to 180, 0 is still true north which will leave us to this calculation:
// Store the bearingTo in the bearTo variable
float bearTo = LocationObj.bearingTo( destinationObj );
// If the bearTo is smaller than 0, add 360 to get the rotation clockwise.
if (bearTo < 0) {
bearTo = bearTo + 360;
}
If we add some dummy values to test our new formula:
float bearTo = -100;
// This will now equal to true
if (-100 < 0) {
bearTo = -100 + 360 = 360 - 100 = 260;
}
We've now sorted out the bearingTo, lets head on to the azimuth!
You need to substract the declination instead of adding it, as we want azimuth to be 0 when we point the phone directly at true north instead of having the declination added to the azimuth, which will then give us double the declination when we point the phone to true north. Correct this by subtracting the declination instead of adding it.
azimuth -= geoField.getDeclination(); // converts magnetic north into true north
When we turn the phone to true north now, azimuth will then equal to 0
Your code for correcting the azimuth is no longer necessary.
// Remove / uncomment this line
azimuth = azimuth % 360;
We will now continue to the point of where we calculate the real rotation. But first i will summarize what type of values we have now and explaining what they really are:
bearTo = The angle from true north to the destination location from the point we're your currently standing.
azimuth = The angle that you've rotated your phone from true north.
By saying this, if you point your phone directly at true north, we really want the arrow to rotate the angle that bearTo is set as. If you point your phone 45 degrees from true north, we want the arrow to rotate 45 degrees less than what bearTo is. This leaves us to the following calculations:
float direction = bearTo - azimuth;
However, if we put in some dummy values:
bearTo = 45;
azimuth = 180;
direction = 45 - 180 = -135;
This means that the arrow should rotate 135 degrees counter clockwise. We will need to put in a similiar if-condition as we did with the bearTo!
// If the direction is smaller than 0, add 360 to get the rotation clockwise.
if (direction < 0) {
direction = direction + 360;
}
Your bearing text, the N, E, S and W is off, so i've corrected them in the final method below.
Your onSensorChanged method should look like this:
public void onSensorChanged( SensorEvent event ) {
// If we don't have a Location, we break out
if ( LocationObj == null ) return;
float azimuth = event.values[0];
float baseAzimuth = azimuth;
GeomagneticField geoField = new GeomagneticField( Double
.valueOf( LocationObj.getLatitude() ).floatValue(), Double
.valueOf( LocationObj.getLongitude() ).floatValue(),
Double.valueOf( LocationObj.getAltitude() ).floatValue(),
System.currentTimeMillis() );
azimuth -= geoField.getDeclination(); // converts magnetic north into true north
// Store the bearingTo in the bearTo variable
float bearTo = LocationObj.bearingTo( destinationObj );
// If the bearTo is smaller than 0, add 360 to get the rotation clockwise.
if (bearTo < 0) {
bearTo = bearTo + 360;
}
//This is where we choose to point it
float direction = bearTo - azimuth;
// If the direction is smaller than 0, add 360 to get the rotation clockwise.
if (direction < 0) {
direction = direction + 360;
}
rotateImageView( arrow, R.drawable.arrow, direction );
//Set the field
String bearingText = "N";
if ( (360 >= baseAzimuth && baseAzimuth >= 337.5) || (0 <= baseAzimuth && baseAzimuth <= 22.5) ) bearingText = "N";
else if (baseAzimuth > 22.5 && baseAzimuth < 67.5) bearingText = "NE";
else if (baseAzimuth >= 67.5 && baseAzimuth <= 112.5) bearingText = "E";
else if (baseAzimuth > 112.5 && baseAzimuth < 157.5) bearingText = "SE";
else if (baseAzimuth >= 157.5 && baseAzimuth <= 202.5) bearingText = "S";
else if (baseAzimuth > 202.5 && baseAzimuth < 247.5) bearingText = "SW";
else if (baseAzimuth >= 247.5 && baseAzimuth <= 292.5) bearingText = "W";
else if (baseAzimuth > 292.5 && baseAzimuth < 337.5) bearingText = "NW";
else bearingText = "?";
fieldBearing.setText(bearingText);
}
You should be able to set the matrix to the ImageView without having to recreate the bitmap each time, and er.. 'normalise' (is that the word?) the readings.
float b = mLoc.getBearing();
if(b < 0)
b = 360 + b;
float h = item.mHeading;
if(h < 0)
h = 360 + h;
float r = (h - b) - 360;
matrix.reset();
matrix.postRotate(r, width/2, height/2);
In the above example mLoc is a Location returned by a gps provider and getBearing returns the number of degrees east of north of the current direction of travel. item.mHeading has been calculated using the Location.bearingTo() function using mLoc and the item's location. width and height are the dimensions of the image view.
So, make sure your variables are in degrees and not radians, and try 'normalising' (getting headings into the range of 0-360 and not -180-180). Also, if the results are off by 180 degrees, make sure you're getting the bearingTo your target, rather than the degrees from your target to you.
The above matrix can then be set in an ImageView that has a ScaleType.Matrix
imageView.setMatrix(matrix);
imageview.setScaleType(ScaleType.Matrix);
Since you're rotating around the centre point of the imageView (the width/2, height/2 in the postRotate), your drawable should be pointing upwards and will be rotated at draw time, rather than re-creating a new bitmap each time.
I spent about 40 hours one weekend trying to do this.
Pain in the butt, hopefully I can spare you that pain.
Ok, I am warning you, this is some ugly code.
I was in a pinch to finish it, it has no naming schemes, but i tried to comment it as best as I could for you.
It was used to locate large piles of nuts laying out in fields for storage
Using the phones current latitude and longitude, the lat/lon of the destination, the compass sensor, and some algebra, I was able to calculate the direction to the destination.
Lat/lon and sensor readings are pulled from the MainApplication class
This is some of the code for arrow.class, which I used to draw an arrow on a canvas towards a direction.
//The location you want to go to//
//"Given North"
double lat=0;
double lon=0;
//////////////////////////////////
protected void onDraw(Canvas canvas) {
//Sensor values from another class managing Sensor
float[] v = MainApplication.getValues();
//The current location of the device, retrieved from another class managing GPS
double ourlat= MainApplication.getLatitudeD();
double ourlon= MainApplication.getLongitudeD();
//Manually calculate the direction of the pile from the device
double a= Math.abs((lon-ourlon));
double b= Math.abs((lat-ourlat));
//archtangent of a/b is equal to the angle of the device from 0-degrees in the first quadrant. (Think of a unit circle)
double thetaprime= Math.atan(a/b);
double theta= 0;
//Determine the 'quadrant' that the desired location is in
//ASTC (All, Sin, Tan, Cos) Determines which value is positive
//Gotta love Highschool algebra
if((lat<ourlat)&&(lon>ourlon)){//-+
//theta is 180-thetaprime because it is in the 2nd quadrant
theta= ((Math.PI)-thetaprime);
//subtract theta from the compass value retrieved from the sensor to get our final direction
theta=theta - Math.toRadians(v[0]);
}else if((lat<ourlat)&&(lon<ourlon)){//--
//Add 180 degrees because it is in the third quadrant
theta= ((Math.PI)+thetaprime);
//subtract theta from the compass value retreived from the sensor to get our final direction
theta=theta - Math.toRadians(v[0]);
}else if((lat>ourlat)&&(lon>ourlon)){ //++
//No change is needed in the first quadrant
theta= thetaprime;
//subtract theta from the compass value retreived from the sensor to get our final direction
theta=theta - Math.toRadians(v[0]);
}else if((lat>ourlat)&&(lon<ourlon)){ //+-
//Subtract thetaprime from 360 in the fourth quadrant
theta= ((Math.PI*2)-thetaprime);
//subtract theta from the compass value retreived from the sensor to get our final direction
theta=theta - Math.toRadians(v[0]);
}
canvas.drawBitmap(_bitmap, 0, 0, paint);
float[] results = {0}; //Store data
Location.distanceBetween(ourlat, ourlon, lat, lon, results);
try{
//Note, pileboundary is a value retreived from a database
//This changes the color of the canvas based upon how close you are to the destination
//Green < 100 (or database value), Yellow < (100)*2, Otherwise red
if((results[0])<(pileboundary==0?100:pileboundary)){
_canvas.drawColor(Color.GREEN);
}else if((results[0])<(pileboundary==0?100:pileboundary)*2){
_canvas.drawColor(Color.YELLOW);
}else{
_canvas.drawColor(Color.rgb(0xff, 113, 116)); //RED-ish
}
//Draw the distance(in feet) from the destination
canvas.drawText("Distance: "+Integer.toString((int) (results[0]*3.2808399))+ " Feet", 3, height-3, textpaint);
}catch(IllegalArgumentException ex){
//im a sloppy coder
}
int w = canvas.getWidth();
int h = height;
int x = w / 2; //put arrow in center
int y = h / 2;
canvas.translate(x, y);
if (v != null) {
// Finally, we rotate the canvas to the desired direction
canvas.rotate((float)Math.toDegrees(theta));
}
//Draw the arrow!
canvas.drawPath(thearrow, paint);
}
//Some of my declarations, once again sorry :P
GeomagneticField gf;
Bitmap _bitmap;
Canvas _canvas;
int _height;
int _width;
Bitmap b;
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Get the current GeomagneticField (Should be valid until 2016, according to android docs)
gf = new GeomagneticField((float)lat,(float)lon,(float)MainApplication.getAltitude(),System.currentTimeMillis());
_height = View.MeasureSpec.getSize(heightMeasureSpec);
_width = View.MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(_width, _height);
_bitmap = Bitmap.createBitmap(_width, _height, Bitmap.Config.ARGB_8888);
_canvas = new Canvas(_bitmap);
b=Bitmap.createBitmap(_bitmap);
drawBoard();
invalidate();
}
//Here is the code to draw the arrow
thearrow.moveTo(0, -50);
thearrow.lineTo(-20, 50);
thearrow.lineTo(0, 50);
thearrow.lineTo(20, 50);
thearrow.close();
thearrow.setFillType(FillType.EVEN_ODD);
Hopefully you can manage to read my code... If I get time, I will make it a bit prettier.
If you need any explaining, let me know.
-MrZander

Convert values form Sensor.TYPE_ORIENTATION to Euler angles?

I have to write a compass app in Android. The only thing the user sees on the screen is a cube with a red wall which has to point north. This is not important. What's important is that I need to rotate that cube accordingly to the rotation of the device itself so that the red wall continues to point north no matter how the phone is being held. My code is simple and straightforward:
#Override
public void onSensorChanged(SensorEvent event) {
synchronized (this) {
switch (event.sensor.getType()){
case Sensor.TYPE_ACCELEROMETER:
direction = event.values[2];
break;
case Sensor.TYPE_ORIENTATION:
if (direction < 0) {
angleX = event.values[1];
angleY = -event.values[2];
angleZ = event.values[0];
} else {
angleX = -event.values[1];
angleY = -event.values[2];
angleZ = event.values[0];
}
break;
}
}
}
I have added this extra direction variable that simply stores whether the phone's display is pointing downwards or upwards. I don't know if I need it but it seems to fix some bugs. I am using the SensorSimulator for android but whenever my pitch slider goes in the [-90, 90] interval the other variables get mixed up. It's like they get a 180 offset. But I can't detect when I am in this interval because the range of the pitch is from -90 to 90 so I can move that slider from left to write and I will always be in that interval.
This was all just to show you how far has my code advanced. I am not saying how this problem should be solved because I will only probably stir myself into a dead end. You see, I have been trying to write that app for 3 days now, and you can imagine how pissed my boss is. I have read all sorts of tutorials and tried every formula I could find or think of. So please help me. All I have to do is know how to rotate my cube, the rotation angles of which are EULER ANGLES in degrees.
Here's some code I wrote to do something pretty similar, really only caring about the rotation of the device in the roll direction. Hope it helps! It just uses the accelerometer values to determine the pitch, no need to get orientation of the view.
public void onSensorChanged(SensorEvent event) {
float x = -1 * event.values[0] / SensorManager.GRAVITY_EARTH;
float y = -1 * event.values[1] / SensorManager.GRAVITY_EARTH;
float z = -1 * event.values[2] / SensorManager.GRAVITY_EARTH;
float signedRawRoll = (float) (Math.atan2(x, y) * 180 / Math.PI);
float unsignedRawRoll = Math.abs(signedRawRoll);
float rollSign = signedRawRoll / unsignedRawRoll;
float rawPitch = Math.abs(z * 180);
// Use a basic low-pass filter to only keep the gravity in the accelerometer values for the X and Y axes
// adjust the filter weight based on pitch, as roll is harder to define as pitch approaches 180.
float filterWeight = rawPitch > 165 ? 0.85f : 0.7f;
float newUnsignedRoll = filterWeight * Math.abs(this.roll) + (1 - filterWeight) * unsignedRawRoll;
this.roll = rollSign * newUnsignedRoll;
if (Float.isInfinite(this.roll) || Float.isNaN(this.roll)) {
this.roll = 0;
}
this.pitch = filterWeight * this.pitch + (1 - filterWeight) * rawPitch;
for (IAngleListener listener : listeners) {
listener.deviceRollAndPitch(this.roll, this.pitch);
}
}

Categories

Resources