Rotation direction continuos check - c#

I'm working on a moltitouch application in actionscript 3, I'm also porting it in C#, Basically, im working on a Knob, that can be rotated with a finger, what i would like to achieve is that rotating CW or CCW i can have continuos direction, instead everytime angle is passing by 180 I got an inversion of direction, any hint ?
Which way can be detected a continuos rotation direction ?
this is the code I'm uding to detect direction:
private function findDirection(currentAngle : Number, targetAngle : Number) : int
{
currentAngle = refineAngle(currentAngle);
targetAngle = refineAngle(targetAngle);
if (targetAngle < 0)
{
targetAngle += (Math.PI * 2);
}
if (currentAngle < 0)
{
currentAngle += (Math.PI * 2);
}
if (targetAngle < currentAngle)
{
targetAngle += (Math.PI * 2);
}
if (targetAngle - currentAngle <= Math.PI)
{
return 1;
}
else
{
return -1;
}
}
private function refineAngle(angle : Number) : Number
{
return angle * Math.PI / 180;
}

Maybe this helps. The variable continuousAngle will track the total knob turning performed, i.e. turning the knob twice counterclockwise will get you to 720. Then turning it three times clockwise takes you back down to -360. Everything else should be easy to derive - limiting the minimum and maximum values, making the value wrap around, scale the value to for example 1 per turn or whatever else you want.
var lastAngle = 0;
var continuousAngle = 0;
function HandleDown(angle)
{
lastAngle = angle;
}
function HandleMove(angle)
{
// The orientation change in degrees of the knob since the last event with
// a range of [-180;+180). A positive value indicates counterclockwise, a
// negative value clockwise turning.
var change = (360 + angle - lastAngle) % 360;
if (change >= 180)
{
change -= 360;
}
// It may also be a good idea to not update continuousAngle if the absolute
// value of change is larger than say 10°, 20° or 40° because such large
// changes may indicate some kind of glitch like the user moving straight
// across the knob. But I am not sure and 20 is just a random guess.
if (Math.Abs(change) <= 20)
{
continuousAngle += change;
}
lastAngle = angle;
}
For floating point numbers the reminder can be calculated using Math.IEEEReminder instead of the remainder operator %. The linked page also shows how to implement this function yourself if it is not available in your language.

Related

Yaw rate calculation from GPS Heading

I have a dual GPS mounted on robot and getting data at 20Hz. I got heading data from GNTRA sentence which gives the heading from dual antenna. I am trying to get yaw rate of vehicle. I am having problem when I turn to left side of North. Normally, I am trying to get difference of two measurement and divide it with time interval. I am not good at trigonometry. For example, when I am driving to 5 degree of heading and making turn to left to 350 degree.I need to measure -15 degree/ time_interval. But I am measuring 345/time_interval with my code. I am making mistake and I could not figure out how to solve it. Can anybody help me? Thanks
public double calc_yawrate(heading)
{
mywatch.Stop();
double t = (double)mywatch.ElapsedMilliseconds / 1000;
mywatch.Reset();
mywatch.Start();
Speed = Speed / 3.6;
Speed = Math.Round(Speed, 2);
double yaw = heading;
double yawrate;
yawrate = (yaw- yawpast) / t;
yawpast = yaw;
}
It seems like you want the difference in range [-180°, 180°], then you can add/minus the value by 360° until it's in range.
var diff = yaw - yawpast;
if(diff > 180)
{
do
{
diff -= 360;
}
while(diff <= 180);
}
else if(diff < -180)
{
do
{
diff += 360;
}
while(diff >= -180);
}
yawrate = diff / t;

In unity how to acces transform rotation in script

I'm making a bouncing and spinning box game. For each spin score will increase.I wrote a code about that but doesn't work. I searched internet but couldn't find answer.
GameObject thePlayer = GameObject.Find("Player");
PlayerEverything player1 = thePlayer.GetComponent<PlayerEverything>();
if (!player1.isGrounded)
{
if(thePlayer.transform.localRotation.z == 0)
{
scorePoint++;
scoreCombo++;
}
if(thePlayer.transform.localRotation.z == 90)
{
scorePoint++;
scoreCombo++;
}
if(thePlayer.transform.localRotation.z == 180)
{
scorePoint++;
scoreCombo++;
}
if(thePlayer.transform.localRotation.z == -180)
{
scorePoint++;
scoreCombo++;
}
if(thePlayer.transform.localRotation.z == -90)
{
scorePoint++;
scoreCombo++;
}
scoreCombo = scorePoint;
score += scorePoint;
}
this is my edited code
if (!player1.isGrounded)
{
currentRotation += Vector3.SignedAngle( transform.parent.right,Vector3.up, transform.right);
if (Mathf.Abs(currentRotation) > 90)
{
scorePoint++;
scoreCombo++;
}
Debug.Log("" + currentRotation);
currentRotation = 0;
}
Multiple issues here!
First of all never compare two float values using ==! Due to the floating point precision this might fail even e.g. for 5f * 0.2f / 10f == 1f .. the result might be 0.9999999 or 1.000000001.
Instead you rather would use a certain range like e.g.
if(Mathf.Abs(a-b) <= someThreshold)
Unity provides Mathf.Approximately
Compares two floating point values and returns true if they are similar.
Floating point imprecision makes comparing floats using the equals operator inaccurate. For example, (1.0 == 10.0 / 10.0) might not return true every time. Approximately() compares two floats and returns true if they are within a small value (Epsilon) of each other.
so using
if(Mathf.Approximately(a-b))
basically equals doing
if(Mathf.Abs(a-b) <= Mathf.Epsilon)
where Mathf.Epsilon is
The smallest value that a float can have different from zero.
Then Transform.rotation and Transform.localRotation is a Quaternion which has four components x, y, z and w. Each of these moves in a range [-1; 1]. Except you know exactly what you are doing (which you don't ;) ) never directly read or write components of a Quaternion!
Your checks will simply never be true!
Instead you should rather work with vectors and check e.g.
// for storing the current rotation
private float currentRotation;
// for storing the last right direction
private Vector3 lastRight;
...
if (!player1.isGrounded)
{
// add the rotation delta since the last frame
currentRotation += Vector3.SignedAngle(lastRight, transform.right, transform.forward);
// if it exceeds +/- 90°
if(Mathf.Abs(currentRotation) > 90)
{
// get points
scorePoint++;
scoreCombo++;
// and reset the rotation counter
currentRotation = 0;
}
}
// Update the last right direction with the current one
lastRight = transform.right;
see Vector3.SignedAngle

Accelerate rotation from 0 to x angle in x seconds in Unity

This is more of a math question than a coding question. I would like to reach for example an rotation angle of 90 in 1 second while speed is accelerating at constant value. My current version takes 1.4 seconds to reach the desired rotation angle, and it should reach it in 1 second. I believe that the reason for that is that it currently accelerates to speed of 90 in 1 second and not to rotation angle of 90. Since I am not that good in math, I have no idea how I need to adjust the acceleration calculation. I am unable to find any solution to this.
NOTE: I need to adjust the rotation angles manually, I am not able to use any existing functions, like for example transform.Rotate(), since in my complete version the rotation direction can change at any time and the rotation also has deceleration value.
This is a very simplified version of what I have (it only rotates the z axis to one direction and runs once on start):
private float accelerationInSeconds = 1;
private float targetAngle = 90f;
private float speed = 0;
private float axis = 1;
private bool rotate = true;
private float acceleration;
void Start() {
// Calculate acceleration (this calculation should be changed)
acceleration = targetAngle / accelerationInSeconds;
}
void Update() {
if (rotate) {
// Accelerate
speed += axis * (acceleration * Time.deltaTime);
// Calculate next rotation position
Vector3 rotationVector = transform.rotation.eulerAngles;
rotationVector.z += speed * Time.deltaTime;
// Rotate object
transform.rotation = Quaternion.Euler(rotationVector);
// Check if rotation has gone over the target angle
if (rotationVector.z >= targetAngle) {
rotationVector.z = targetAngle;
speed = 0;
rotate = false;
}
}
}
Thanks in advance for anyone who can help!
EDIT: Modified code to be more efficient. I can't use RotateTowards() since in my complete code I need to clamp the rotation between targetAngle and negative targetAngle. Hopefully this code is more efficient and performance friendly. But I still have not found a solution for my original math related question, which was the whole point of this question.
private float accelerationInSeconds = 1;
private float targetAngle = 90f;
private float speed = 0;
private float angle = 0;
private float axis = 1;
private bool rotate = true;
private float acceleration;
void Start() {
// Calculate acceleration (this calculation should be changed)
acceleration = targetAngle / accelerationInSeconds;
}
void Update() {
if (rotate) {
// Accelerate
speed += axis * (acceleration * Time.deltaTime);
// Calculate next rotation position
angle += speed * Time.deltaTime;
// Check if rotation has gone over the target angle
if (angle >= targetAngle) {
angle = targetAngle;
speed = 0;
rotate = false;
}
// Rotate object
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
}
}
I finally figured it out, thanks to Math section in StackExchange.
So the simple answer is this:
acceleration = 2 * targetAngle / Mathf.Pow(accelerationInSeconds, 2);
As was suggested before I would use a Coroutine. Coroutines are like temporary Update methods and often easier to control and maintain than doing stuff directly in Update.
// Flag to avoid concurrent routines
private bool isRotating;
public void Rotate(float targetAngle, float duration)
{
if(! isRotating) StartCoroutine (RotateRoutine(targetAngle, duration));
}
private IEnumerator RotateRoutine (float targetAngle, float duration)
{
// Just to be sure
if(isRotating) yield break;
// block concurrent routines
isRotating = true;
// Pre-calculate the start and end rotation
var start = transform.rotation;
var end = Quaternion.Euler(0, 0, targetAngle);
var timePassed = 0f;
while(timePassed < duration)
{
// This value will grow linear from 0 to 1 in exactly "duration" seconds
var x = timePassed / duration;
// TODO!
var y = MAGIC;
// Interpolate between the start and end rotation using given factor "y"
transform.rotation = Quaternion.Lerp(start, end, y);
// "pause" the routine here, render this frame
// and continue from here in the next frame
yield return null;
// Increase by the time passed since last frame
timePassed += Time.deltaTime;
}
// To be sure to end with clean values
transform.rotation = end;
// Allow next routine
isRotating = false;
}
So what do we have to fill in for MAGIC?
Basically it can be any mathematical function that maps given input 0 to 1 to 0 to 1.
There are multiple possibilities.
What you currently ask for is a linear growing speed. That means the resulting movement shall be quadratic! So we already know the Formular
var y = a * x * x + b;
We further know from your code that speed always starts from 0 -> b = 0. And the last step is pretty straight forward:
What value do we have to fill in so y goes from 0 to 1 at the same time that x goes from 0 to 1?
1 = a * 1 * 1 + 0;
=> a = 1!
So in your case it is simply
var y = x * x;
If you also want ease-out you could also simply use Mathf.Smoothstep which automatically adds ease-in and ease-out
var y = Mathf.SmoothStep(0, 1, x);
To make it even easier to control you could use an AnimationCurve and adjust the movement curve exactly to your needs in the Inspector
[SerializeField] private AnimationCurve curve;
The curve editor already comes with some preset curves like e.g. linear, logarithmic, exponential and eased-in/-out grow from 0 to 1!
And then use AnimationCurve.Evaluate to get the value (y) in the routine for a given input time (x).
var y = curve.Evaluate(x);

Equalize over slope and flat surface velocity in Unity

I've posted a similar question but it is not exactly the same problem so here I go.
I'm not using physics in my project, so every force it's calculated and applied by me. The point is that the character covers the same area in the same time regardless the inclination of the surface is running on.
Being applied the same movement into the CharacterController.Move() function, the velocity of the controller increases exponentially to try to move along the same surface than being in a flat area.
For example. If a prints the movemement calculated that will be applied in the "Move()" function, it is a normalize one, being (0,0,1) in perpendicular and (0.7,0,0.7) in diagonal. However, if I retrieve the velocity via CharacterController.velocity.magnitude I get a different one, being 8 on flat surface and 11.47 in a 45º slope.
I've made a formula to calculate what is the value that should be retrieved with that "velocity.magnitude" function.
groundAngle = Mathf.Abs(Mathf.Round(Vector3.Angle(hit.normal, transform.forward)) - 90);
groundMovementMagnitude = characterController.velocity.magnitude;
slopeMovementIdeal = ((((groundAngle/2) - groundAngle) + 100) * (groundMovementMagnitude / 100));
With this formula, I get in fact a value of "8" in a flat surface and instead of "11.47", the value of the velocity retrieved in a 45º inclination slope is "6.4"
Nevertheless, this value is simply informative, because the velocity of the character controller can not be set. Instead of that, I need a way to modify the movement Vector3 that will be used to trigger the movement, so, instead of moving (0,0,1) on a slope, or (0.7,0,0.7) in diagonal on a slope, apply a reducer to deduct this Vector3 depending on the angle of the slope.
What I've finally done is using the velocity magnitude to calculate the difference between on flat movement and on slope. Then, I just converted that value into a normalized vector and deduct it to the characters movement.
float minMovement = 0.01f;
float difference = 0.0f;
float x = 0.0f;
float z = 0.0f;
if (OnSlope() && characterController.velocity.magnitude - moveSpeed > minMovement) {
difference = characterController.velocity.magnitude - moveSpeed;
//Diagonal
if ((movement.x > minMovement || movement.x < -minMovement) && (movement.z > minMovement || movement.z < -minMovement)) {
x = z = (difference / 2) / characterController.velocity.magnitude;
if (movement.x < 0)
x *= -1;
if (movement.z < 0)
z *= -1;
}
//Perpendicular
else {
if (movement.x > minMovement || movement.x < -minMovement) {
x = difference / moveSpeed;
if (movement.x < 0)
x *= -1;
}
if (movement.z > minMovement || movement.z < -minMovement) {
z = difference / moveSpeed;
if (movement.x < 0)
z *= -1;
}
}
movement.x -= x;
movement.z -= z;
}
It is working fine.

calculating rotation delta based off initial angle and current angle

I'm looking to track the rotation delta (y axis) between two readings.
There's a game object that I read an initial angle from when it starts moving.
Then I have another variable that reads the live angle during the update loop.
I want the delta value to be agnostic of whether it's negative or positive, essentially I'm going to apply the same updates whether the object rotation 20 degrees to the left or right.
EDIT:
I want the delta value to be the smallest angle, so the maximum it could be is 180, before counting back down to 0.
EXAMPLE:
If my initFaceAngle == 5 and currentFaceAngle == 355 then myAngle == 10
void Start()
{
initFaceAngle = hmd.transform.rotation.eulerAngles.y;
}
void update()
{
currentFaceAngle = hmd.transform.rotation.eulerAngles.y;
// My terrible first attempt... look ma' I can math.
float myAngle = (float)Math.Abs(initFaceAngle - currentFaceAngle);
}
Obviously my calculation won't work because getting the difference between two angles doesn't take into account the 360 degree. So I figured I need some pie (pi) on this, but outside of being an impressive pie (pi) eater I don't have a clue how to invoke its magical math powers.
What formula do I need to use to capture the delta?
How can I make it read the same whether rotating left or right?
Because you only want the angle between the initial and current position, it's actually no math involved, only a simple check to see which value is the greatest.
void update()
{
currentFaceAngle = hmd.transform.rotation.eulerAngles.y;
float myAngle;
if(initFaceAngle > currentFaceAngle)
myAngle = initFaceAngle - currentFaceAngle;
else
myAngle = currentFaceAngle - initFaceAngle;
if(myAngle > 180)
myAngle = 360 - myangle;
}
I think I've worked out a solution, not sure if it's the most graceful but the output values look correct.
void Start()
{
initFaceAngle = hmd.transform.rotation.eulerAngles.y;
}
void update()
{
currentFaceAngle = hmd.transform.rotation.eulerAngles.y;
float myAngle = getDeltaAngle(initFaceAngle, currentFaceAngle);
}
public static float getDeltaAngle(float a, float b)
{
float x;
float y;
if (a > b)
{
x = a;
y = b;
}
else
{
x = b;
y = a;
}
if (x - y < 180)
{
x = x - y;
}
else
{
x = (360 - x) + y;
}
return x;
}

Categories