For a project I need to detect the inclination (pitch) of an android device. For that, I use the acceleration sensor and the magnetic field sensor and everything works fine. The device is able to move forward and backward hanging on a pendulum. If I have the angle of the pendulum/device, I can calculate the acceleration. The problem is: All that works only stationary. If the device is in a car which is moving, it doesnn't work any more. When the car is braking, the pendulum moves forward and the inclination changes, but the device cannot detect that because the force is still acting "downward" along the y-axis.
Is it any possible to detect the inclination angle in this case?
Not sure if I've explained my problem clearly. What I need is the angle of a moving pendulum, detected by device sensors.
<< EDIT >>
What I need is the correctly measrued angle of the pendulum even when it is within a moving car (please take a look at my pdf lying in my Dropbox):
https://dl.dropboxusercontent.com/u/5655235/sensors.pdf
As you can see on the image, the measured angle is not correct if the box is accelerating.
Here is my code:
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
acc = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mag = event.values;
if (acc != null && mag != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, acc, mag);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
phiRad = orientation[1];
phi = Math.toDegrees(phiRad);
}
}
I hope that I understood your problem correctly!! So you want to detect the inclination of the device when it is in a moving car...
First of all, when you say that:
When the car is braking, the pendulum moves forward and the inclination changes, but the device cannot detect that because the force is still acting "downward" along the y-axis.
Are you sure that the device is kept vertically straight?
So, when the car is moving the pendulum will obtain an acceleration of the car in forward direction. Here, forward doesn't mean that it is directed towards x-axis of the device, but the x-axis of the car/surface. As per my understanding, you are trying to check the pendulum's movement towards x-axis, but you should check for the position of device. Hope it helps, if I understood your problem correctly.
Related
Earthquake threat circle on the map
I am using UnfoldingMaps to display earthquake information on the map.
I plan to show the threat circle on the map.
A circle is drawn given its radius and center position in pixels. How to get the radius is the problem I met.
Suppose I have the threat circle radius R in kilometers and the center marker A.
I want to create a marker B on the circle so that I can use the screen distance as the screen radius.
I decided to create B with the same longitude but a different latitude from A. I change R to delta latitude.
But after drawing the circle I found it is not the right one since the red triangular should be in the circle according to their distance.
The main difficulty is exactly how to calculate screen radius according to kilometers.
public void calcThreatCircleOnScreen(UnfoldingMap map) {
float radius = 0;
float deltaLat=(float) (threatCircle()/6371/2/3.1415927*360);
Location centerLocation = this.getLocation();
Location upperLocation = new Location(centerLocation);
upperLocation.setLat(centerLocation.getLat() + deltaLat);
SimplePointMarker upperMarker = new SimplePointMarker(upperLocation);
ScreenPosition center = this.getScreenPosition(map);
ScreenPosition upper = upperMarker.getScreenPosition(map);
radius = Math.abs(upper.y - center.y);
setThreatCircleOnScreen(radius);
}
This is going to depend on two things: the zoom level of the map, and the projection you're using.
You need to unproject kilometers to pixels, and you can probably figure out how to do that using google and the Unfolding API.
For example, I found a MercatorProjection class that contains a constructor that takes a zoom level, and methods for projecting and unprojecting points between world coordinates and pixel coordinates.
That's just a starting point, since I'm not sure what units those methods are taking, but hopefully this is a direction for you to take your googling and experimenting.
I'd recommend trying to get something working and posting an MCVE if you get stuck. Good luck.
Now I have the answer for this question. Hope it will be helpful for others.
Earthquake threat circle on the map
My early solution to calculate radius in pixels from km is correct. I think it a simple and powerful idea (independent of projecting API)
The only problem is I should use diameter rather than radius in drawing the circle. I should draw with d=2r like this
float d = 2 * threatCircleRadius();
pg.noFill();
pg.ellipse(x,y,d,d);
I found another cleaner solution like below by consulting the author of UnfoldingMaps. (https://github.com/tillnagel/unfolding/issues/124)
My early solution first changes distance to delta latitude, then create new location by changing latitude.
The new solution use the API GeoUtils.getDestinationLocation(sourceLocation, compassBearingDegree, distanceKm) to directly get the new location!
In addition, I needn't create a new marker to find its screen position.
public void calcThreatCircleOnScreen(UnfoldingMap map) {
float radius = 0;
Location centerLocation = this.getLocation();
Location upperLocation = GeoUtils.getDestinationLocation(centerLocation, 0, threatCircle());
//SimplePointMarker upperMarker = new SimplePointMarker(upperLocation);
ScreenPosition center = map.getScreenPosition(centerLocation);
ScreenPosition upper = map.getScreenPosition(upperLocation);
radius = PApplet.dist(center.x, center.y, upper.x, upper.y);
setThreatCircleOnScreen(radius);
}
I am trying to shoot an object(a spell) depending on the rotation of the players arm. The spell is supposed to come out of the hand and shoot towards where the mouse cicked(the arm rotates and points to where the mouse is). This is how the arm rotates in game.
public boolean mouseMoved(int screenX, int screenY) {
tmp.x = screenX;
tmp.y = screenY;
tmp.z = 0;
cam.unproject(tmp);
rot = MathUtils.radiansToDegrees * MathUtils.atan2((float)tmp.y - (float)player.getArmSprite().getY() - player.getArmSprite().getHeight(),
tmp.x -player.getArmSprite().getX() - player.getArmSprite().getWidth());
if (rot < 0) rot += 360;
//Last right or left means if hes looking left or right
if(player.lastRight)
player.setObjectRotation(rot + 80);
if(player.lastLeft)
player.setObjectRotation(-rot - 80);
And this is how the spell is supposed to shoot based off rotation
//destination is a vector of where on screen the mouse was clicked
if(position.y < destination.y){
position.y += vel.y * Gdx.graphics.getDeltaTime();
}
if(position.x < destination.x){
position.x += vel.x * Gdx.graphics.getDeltaTime();
}
However this is very wonky and never really reacts the way it supposed to with a few exceptions. It fires from the hand and then if the y axis is equal it completely evens out and goes till it reaches the x position, I want it to fire from the hand to the position clicks perfectly straight from point a to point b, this is clearly a rotation problem that I just can't seem to figure out how to tackle.
Here is an image of what is happening
Example image
The red indicates where I clicked, as you can see it reached the x pos first and now is traveling to the y when it should have reached the x and y pos of where I clicked first
Any help with this problem is extremely appreciated!
I'm pretty bad at radians and tangents but luckily we have vectors.
Since you have the rot ation in degrees of the arm. I advice to use Vectors to use for any Vector related math now.
//A vector pointing up
Vector2 direction = new Vector2(0, 1);
//Let's rotate that by the rotation of the arm
direction.rotate(rot);
Now direction is the direction the arm is pointing. If your rotation is calculated where up = 0. So you might need to rotate it 180, 90 or -90 degrees. Or in the case you did something silly any degrees.
Your spell should have a Vector too for it's position. Set that to the hand or wherever you want to start from. Now all you need to do is scale that direction since it's currently has a length of 1. If you want to move 5 units each frame you can do direction.scl(5) now it is of length 5. But technically speaking it's no direction anymore now everybody calls it velocity so let's do.
//when you need to fire
float speed = 5;
Vector2 velocity = direction.cpy().scl(speed);
//update
position.add(velocity);
draw(fireballImage, position.x, position.y);
I copied direction first, otherwise it would also be scaled. Then I just added the velocity to the position and draw using that Vector.
And to show Vectors are awesome you should see this awesome badlogic vs mouse program I created. https://github.com/madmenyo/FollowMouse there are just a view lines of my own code. It just takes a little bit of vector knowledge and it's very readable.
In my 3d application I wish to have an object (a tree, for example), and my camera to look at this object. Then, I want the camera to rotate about the object, in a circle, while looking at the tree the whole time. Imagine walking around a tree, while constantly changing your angle so that you are still looking at it. I know this requires both rotation of my camera, and translation of my camera, but the math is far beyond the level I have been taught in schooling thusfar. Can anyone point me in the right direction?
Here is one way with very simple math. First, you need a constant for the distance the camera is from the center of the tree (the radius of the circle path it travels on). Also, you need some variable to track it's angle around the circle.
static final float CAM_PATH_RADIUS = 5f;
static final float CAM_HEIGHT = 2f;
float camPathAngle = 0;
Now you can change the camPathAngle to anything you want from 0 to 360 degrees. 0 degrees corresponds with the location on the circle that is in the same direction as the world's X-axis from the tree's center.
On each frame, after you've update camPathAngle, you can do this to update the camera position.
void updateTreeCamera(){
Vector3 camPosition = camera.getPosition();
camPosition.set(CAM_PATH_RADIUS, CAM_HEIGHT, 0); //Move camera to default location on circle centered at origin
camPosition.rotate(Vector3.Y, camPathAngle); //Rotate the position to the angle you want. Rotating this vector about the Y axis is like walking along the circle in a counter-clockwise direction.
camPosition.add(treeCenterPosition); //translate the circle from origin to tree center
camera.up.set(Vector3.Y); //Make sure camera is still upright, in case a previous calculation caused it to roll or pitch
camera.lookAt(treeCenterPosition);
camera.update(); //Register the changes to the camera position and direction
}
I did it like that for the sake of commenting it. It's actually shorter than the above if you chain commands:
void updateTreeCamera(){
camera.getPosition().set(CAM_PATH_RADIUS, CAM_HEIGHT, 0)
.rotate(Vector3.Y, camPathAngle).add(treeCenterPosition);
camera.up.set(Vector3.Y);
camera.lookAt(treeCenterPosition);
camera.update();
}
I need help with some math related stuff.
I need to rotate a model on the screen with my mouse, but this rotation also needs to be based on the current yaw and pitch of the camera. I've got the first part down, but I don't know how to go on with transforming my roll and pitch to be relative to the camera. Right now, the rotation only works if the camera has not been rotated yet (which is to be expected considering that's what the current code was made to do.)
Also, do note that I do mean roll instead of yaw. I want the roll to be controlled with the left and right swipes of the mouse.
I've read that quaternions can solve the problem, but being a learn-by-example learner, I haven't been able to figure out how to do this.
Here is my current code (Note that PI2 is simply Pi * 2):
float dx = (input.getMouseDX() * prefs.mouseSensitivity);
float dy = (input.getMouseDY() * prefs.mouseSensitivity);
double roll = rollAngle, pitch = pitchAngle;
roll = (roll+dx) % PI2;
if(roll < 0){
roll += PI2;
}
pitch += dy;
rollAngle = (float) yaw;
pitchAngle = (float) pitch;
Also, here's a GIF of the desired effect at all angles (but the GIF was taken at a non-rotated camera, the only point where I mentioned it worked.)
I found the solution after visiting a few math websites and what not.
For anyone in the future who has this problem, here's a basic mathematical formula for it:
Variables:
RPYToRot = Function to convert (roll, pitch, yaw) to rotation matrix
RotToRPY = Opposite of above
RCam = camera rotation (roll, pitch, yaw)
RPos = player rotation (roll, pitch, yaw)
The formula itself being:
RNew = RotToRPY(RPYToRot(RPos)*Rcam)
And here's the code I used:
if (!markedMa){
camMa.setFromEulerAngles((float) Math.toDegrees(-camera.getYaw()), (float) Math.toDegrees(camera.getPitch()), 0f);
markedMa = true;
}
float dx = (input.getMouseDX() * (prefs.mouseSensitivity * 5f));
float dy = (input.getMouseDY() * (prefs.mouseSensitivity * 5f));
utilMatrix.setFromEulerAngles(0f, -dy, -dx);
camMa.mul(utilMatrix);
plaMa.setFromEulerAngles((float) Math.toDegrees(trueYaw), (float) Math.toDegrees(pitch), (float) Math.toDegrees(roll));
plaMa.mul(camMa);
The trick is to get the camera rotation as soon as you start the rotating on the model (assuming you lock the camera orientation), and multiply it by the mouse movement each frame rather than resetting the camera rotation matrix yourself.
plaMa has your final transformation you can then use to apply to your model.
I'm trying to map my movements with a android device into an OpenGL scene.
I've recorded accelerometer values for a simples movement: Moving the phone (lies flat on a table) 10cm forward (+x), and then 10cm backward (-x).
The problem is that this values when used to calculate velocity and position, makes only the opengl cube go forward. Seems like the negative acceleration recorded was not enough to reduce the speed and invert its movement.
What can be the problem?
This is my function that updates the velocity and position every time new data comes in:
void updatePosition(double T2) {
double T = 0.005;
Vec3 old_pos = position.clone(), old_vel = velocity.clone();
velocity = old_vel.plus(acceleration.times(T));
position = old_pos.plus(old_vel.times(T).plus(acceleration.times(0.5 * Math.pow(T, 2))));
}
This is the X,Y,Z accelerometer values over the entire captured time:
alt text http://img25.imageshack.us/img25/7528/forces.jpg
Your function takes the parameter T2 which I am assuming is the accelerator input? but you are using T which you have declared as double T = 0.005; so your function will be always going forward at a static rate.