I am working with a drone, and I can read the yaw navigation angle from its sensors. However, I would like to establish this angle as the "0" angle when I start my process. The range of this angle is between -180 degrees to 180 degrees.
initial_yaw = read_yaw_angle()
current_yaw = read_yaw_angle() - initial_yaw
but if initial_yaw is 180 degrees, and the measured angle is, let's say, -50 degrees. Now I have that the current_yaw is -230 which is out of the range -180 to 180 degrees. How can I solve this issue? (is it modulo operator what I need to use?)
current_yaw = read_yaw_angle() - initial_yaw;
if (current_yaw < -180) {
current_yaw += 360;
} else if (currrent_yaw > 180) {
current_yaw -= 360;
}
Related
So basically what I am trying to do is when I move my character via joystick I want to calculate the current angle the character is rotating and the new angle in which he should rotate. for example: i am moving the joystick to 45 degrees so my character is rotating at 45 degrees to right. now I move the joystick to 90 degrees. So basically I want to calculate the difference between the current and new angle and than rotate at that specific angle. In this case it would be 45 degrees to left and my character should rotate 45 degrees to left.
Whats the best way to do it?
void Update()
{
// move
_rigidbody.MovePosition(transform.position + (transform.forward * leftController.GetTouchPosition.y * Time.deltaTime * speedMovements) +
(transform.right * leftController.GetTouchPosition.x * Time.deltaTime * speedMovements) );
if (myX != leftController.GetTouchPosition.x || myY != leftController.GetTouchPosition.y) { //checks if player changed position.
myX = leftController.GetTouchPosition.x;
myY = leftController.GetTouchPosition.y;
double rad = Mathf.Atan2(leftController.GetTouchPosition.y, leftController.GetTouchPosition.x); // In radians
double deg = rad * (180 / System.Math.PI); // values from up right to up left : +0 to +180 and from down left to down right: -180 to -0
// double difference =....; here i want to calc the angle my char. should rotate
// transform.Rotate(Vector3.up,(float)difference * Time.deltaTime);
}
I'm trying to do a rotating cannon which rotates back and forward.
I want to limit the rotation from -55 to 55 (i mean transform.position.z), but i can't make it work.
For the moment my code is:
public class Cannon : MonoBehaviour
{
bool hit = false;
void Update ()
{
float angle = transform.rotation.z;
if (angle > -55 & angle < 55 & !hit)
{
transform.Rotate(Vector3.back * Time.deltaTime);
}
if (angle <= -55)
{
transform.Rotate(Vector3.back * Time.deltaTime);
hit = true;
}
if (angle >= 55)
{
transform.Rotate(Vector3.forward * Time.deltaTime);
hit = true;
}
}
}
The only think that is working is the first rotation which I've done for the object to start rotating, so it just rotates back and don't stop, it seems to be ignoring "angle"
I've also tried to put the last 2 If statements, inside the first one but still not working.
I want to make it rotate until it hit -55, then start rotating until it hits +55 and repeat this.
The first thing you need to do is to use Euler Angles rather than Quarternions to find the rotation in degrees.
Then, since it doesn't report negative angles but rather angles from 0 to 360, you will need to subtract 360 whenever greater than 180 to get the negative angle equivalent.
From there you can apply your test to keep it in bounds:
public class Cannon : MonoBehaviour {
public float direction = 1f; // initial direction
public float speed = 20f; // speed of rotation
void Update ()
{
float angle = transform.eulerAngles.z;
if (angle > 180f) angle -= 360f;
if ((angle < -55f) || (angle > 55f)) direction *= -1f; // reverse direction (toggles between 1 & -1)
transform.Rotate (0, 0, speed * direction * Time.deltaTime);
}
}
For my explanation I will use degrees.
Let's say I have an angle of 45 degrees seen from the center of a canvas.
I have objects at 10°, 60°, 180° and 350° seen from the center.
In this case the previous angle from 45° is 10°.
The next angle from 45° is 60°.
But now the problem:
What if the angle is 6°, for example. Then the previous angle is 350°.
Or if the angle is 355°, then the next angle is 10°.
How can I figure out which one to get, assuming we have an array similar to the following?
angles = [10, 60, 180, 350]
theAngle = 45
Psuedo-code will do.
You can just use a modulo operator, e.g. to find the "previous" angle using C or C-like languages:
int N = 4;
int angles[N] = { 10, 60, 180, 350 };
int theAngle = 45;
int prevAngle = angles[0]; // init - assume angle[0] is "previous" angle
int minAngleDelta = (theAngle - prevAngle) % 360;
for (i = 1; i < N; ++i) // for each remaining angle
{
int angleDelta = (theAngle - angles[i]) % 360;
if (angleDelta < minAngleDelta) // if we found a smaller delta (modulo 360)
{
minAngleDelta = angleDelta; // track min angle delta
prevAngle = angles[i]; // and corresponding angle
}
}
Note: this works even if your array of angles is not sorted.
I am trying to calculate the rotation from one cross to another. The correspondences between lines in the crosses are known.
The rotation needs to be calculated within 180 degrees either clockwise or anti-clockwise, currently I can calculate within 90 degrees but the algorithms fails with anything larger. The problem seems to be when the matching bearings pass around 360 degrees, such that A = 350 and A' = 80. Repeating this for each line of the cross, causes an incorrect total rotation to be calculated.
The algorithm at present, works as follows for comparing the rotation between two lines, from two crosses is; where crossB and crossA are the corresponding bearings for each cross.
if ((crossB < 360 && crossB >= 270)
&& (crossA >= 0 && crossA < 90))
{
angle = -((360) - crossB) - crossA;
}
else if ((crossA < 360 && crossA >= 270)
&& (crossB >= 0 && crossB < 90)
{
angle = crossB + (360 - crossA);
}
else
{
angle = crossB - crossA;
}
Any thoughts on how to improve or change the algorithm so that it will allow any amount of rotation to be determined?
If I understand correctly, you want to find the smallest angle between two vectors, where the vectors are expressed in a bearing angle in degrees. If that's the case you should be able to use the following code, from NASA's open source WorldWind project
/**
* Computes the shortest distance between this and angle, as an angle.
*
* #param angle the angle to measure angular distance to.
*
* #return the angular distance between this and <code>value</code>.
*/
public Angle angularDistanceTo(Angle angle)
{
if (angle == null)
{
String message = Logging.getMessage("nullValue.AngleIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
double differenceDegrees = angle.subtract(this).degrees;
if (differenceDegrees < -180)
differenceDegrees += 360;
else if (differenceDegrees > 180)
differenceDegrees -= 360;
double absAngle = Math.abs(differenceDegrees);
return Angle.fromDegrees(absAngle);
}
Where subtract works the way you would think it does. The algorithm should be easy to adapt to a non-object oriented approach.
I need an algorithm to figure out if one angle is within a certain amount of degrees from another angle.
My first thought was (a-x < b) && (a+x > b), but it fails when it has to work with angles that wrap around from -179 to 180.
In the diagram above, the region (green) that the angle must be between wraps between the negative and positive sides. How can I determine whether the angle (the red line) falls inside this region?
try this formula:
360-(|a-b|)%360<x || (|a-b|)%360<x
Or, in PHP:
<?php
$b = 10;
$angle1 = -179;
$angle2 = 180;
$diff = $angle1 - $angle2;
if(abs($diff % 360) <= $b || (360-abs($diff % 360))<=$b) {
echo "yes";
} else {
echo "no";
}
?>
As Marcel rightly points out, modulo on negative numbers is potentially problematic. Also, what is the difference between 355 and 5 degrees? It might be worked out to be 350 degrees but 10 degrees is probably what people are expecting. We make the following assumptions:
we want the smallest positive angle between two other angles so 0 <= diff <= 180;
we are working in degrees. If radians, substitute 360 for 2*PI;
angles can be positive or negative can be outside the range -360 < x < 360 where x is an input angle and
order of input angles or the direction of the difference is irrelevant.
Inputs: angles a and b. So the algorithm is simply:
Normalize a and b to 0 <= x < 360;
Compute the shortest angle between the two normal angles.
For the first step, to convert the angle to the desired range, there are two possibilities:
x >= 0: normal = x % 360
x < 0: normal = (-x / 360 + 1) * 360 + x
The second is designed to remove any ambiguity on the difference in interpretation of negative modulus operations. So to give a worked example for x = -400:
-x / 360 + 1
= -(-400) / 360 + 1
= 400 / 360 + 1
= 1 + 1
= 2
then
normal = 2 * 360 + (-400)
= 320
so for inputs 10 and -400 the normal angles are 10 and 320.
Now we calculate the shortest angle between them. As a sanity check, the sum of those two angles must be 360. In this case the possibilities are 50 and 310 (draw it and you'll see this). To work these out:
normal1 = min(normal(a), normal(b))
normal2 = max(normal(a), normal(b))
angle1 = normal2 - normal1
angle2 = 360 + normal1 - normal2
So for our example:
normal1 = min(320, 10) = 10
normal2 = max(320, 10) = 320
angle1 = normal2 - normal1 = 320 - 10 = 310
angle2 = 360 + normal1 - normal2 = 360 + 10 - 320 = 50
You'll note normal1 + normal2 = 360 (and you can even prove this will be the case if you like).
Lastly:
diff = min(normal1, normal2)
or 50 in our case.
You can also use a dot product:
cos(a)*cos(b) + sin(a)*sin(b) >= cos(x)
For a radius of 1, the distance between the line endpoints is 2sin((a-b/2). So throw away the 2 since you are only interested in a comparison, and compare sin(x/2) with sin((a-b)/2). The trig functions take care of all the wrapping.
c++ implementation:
float diff = fabsf(angle1 - angle2);
bool isInRange = fmodf(diff, 360.0f) <= ANGLE_RANGE ||
360.0f - fmodf(diff, 360.0f) <= ANGLE_RANGE;