- Home /
Two ways to calculate velocity without using Rigidbody, which one is more accurate?
Hi all,
I've learn't two ways to calculate velocity of a 3D game object without using Rigidbody, which are shown below. I attached the two scripts onto a same object (a cube) and I've noticed the velocity outcomes of the two methods at the same moment are not exactly the same. Can you please tell me which one can represent the velocity more precisely? And can you please tell me why the two scripts work differently? Thanks a million.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class VelocityReader : MonoBehaviour
{
public Vector3 linearVelocity;
private float previousRealTime;
//private GeometryTwist message;
private Vector3 previousPosition = Vector3.zero;
private Quaternion previousRotation = Quaternion.identity;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
float deltaTime = Time.realtimeSinceStartup - previousRealTime;
linearVelocity = (transform.position - previousPosition) / deltaTime;
Vector3 angularVelocity = (transform.rotation.eulerAngles - previousRotation.eulerAngles) / deltaTime;
Debug.Log("Vlinear" + linearVelocity);
previousRealTime = Time.realtimeSinceStartup;
previousPosition = transform.position;
previousRotation = transform.rotation;
}
}
And the second script is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjVelocityReader : MonoBehaviour
{
Vector3 PrevPos;
Vector3 NewPos;
Vector3 PrevRot;
Vector3 NewRot;
public Vector3 ObjVelocity;
public Vector3 ObjRotation;
// Use this for initialization
void Start()
{
PrevPos = transform.position;
PrevRot = transform.eulerAngles;
}
// Update is called once per frame
void FixedUpdate()
{
transform.rotation = Quaternion.identity;
NewPos = transform.position; // each frame track the new position
ObjVelocity = (NewPos - PrevPos) / Time.fixedDeltaTime;
PrevPos = NewPos; // update position for next frame calculation
Debug.Log("ObjVlinear" + ObjVelocity);
NewRot = transform.eulerAngles; // each frame track the new rotation
ObjRotation = (NewRot - PrevRot) / Time.fixedDeltaTime;
PrevRot = NewRot; // update position for next frame calculation
}
}
Answer by highpockets · Jun 03, 2019 at 08:09 AM
Ok, a few things are a bit off here. In the first script, you are calculating the delta time like this Time.realtimeSinceStartup - previousRealTime;
, but a variable already exists in the Time class that has that ready for you. It's called deltaTime Time.deltaTime;
is all you need, no need to recalculate it. Secondly, the second script is using fixedDeltaTime which is always the same number, whatever you have set in the project settings of unity ( 0.02f is the default I believe ), so you should use Time.deltaTime
there as well. Also, you will be getting the readings at different times, because one is calculating in the physics loop (FixedUpdate()) and one is calculating every frame (Update()). But I think the real game changer here is the use of fixedDeltaTime. Take a look at the documentation:
https://docs.unity3d.com/ScriptReference/Time-fixedDeltaTime.html
For reading the delta time it is recommended to use Time.deltaTime instead because it automatically returns the right delta time if you are inside a FixedUpdate function or Update function.
Hi highpockets, Thanks a lot for your reply. Do you think I should use Update() or FixedUpdate() in the two scripts above? And in the first script previousPosition is declared and assigned Zero below the class definition. However in the second script PrevPos is declared in the start() function but not assigned Zero as shown below. Is there any difference? Thanks a million. 1.
public class VelocityReader : $$anonymous$$onoBehaviour
{
public Vector3 linearVelocity;
private float previousRealTime;
private Vector3 previousPosition = Vector3.zero;
private Quaternion previousRotation = Quaternion.identity;
2.
void Start()
{
PrevPos = transform.position;
PrevRot = transform.eulerAngles;
FixedUpdate is generally considered the best place to calculate physics and that is what you are doing here, so I would say FixedUpdate() to be safe. It would be best to declare and assign previousPosition in the Start() method like the second script because assigning it (0,0,0) is not correct unless the object is at the world origin at the start. Assigning transform.position to it in the start method will always start with the correct position regardless of the start position of the object in question
Note that when you read Time.deltaTime inside FixedUpdate it will actually return the value of Time.fixedDeltaTime. So it makes no difference inside FixedUpdate. That's why it's recommended to use deltaTime all the time because you can easily use the same code elsewhere without any changes.
Whether or not one should use Update or FixedUpdate depends on how and where the object is actually moved. If it's moved in FixedUpdate, using FixedUpdate will be more accurate. Though the better results you get when moving the object in Update if you are not using the physics system.
Though the question to "measure" the velocity is rather strange to begin with. Since no physics are involved an object doesn't move on its own. So there has to be some code that actually moves the object (unless it's animation driven). In that case the code that moves the object already knows the velocity.
For example the eulerAngles calculations can give you funky results when the angles wrap around. There is no accurate way to deter$$anonymous$$e the angular velocity just from looking at two snapshots. This is know as the wagon wheel effect. If you measure a certain speed it could be v but also any v-+(360*i) for any integer "i". So if you measure say -10 degree per second on the y axis, it could also be 350°/s or -370°/s or 2510°/s
Oops ya, that’s right so the game changer is not fixedDeltaTime as FixedUpdate is always calculating at that set interval.. I’m once again corrected by @Bunny83 haha, cheers
Hi highpockets, @highpockets Can you please also take a look at my explanation to my application? Thanks a lot for your constant support. Cheers.
Hi Bunny83, @Bunny83 Thank you so much for your explanation. So from your point of view, the second script mostly does the work.And I'd like to tell you what I am doing. I am grabbing and moving a cube object in unity with either Leap$$anonymous$$otion sensor or the HTC vive controller and I want to learn about the velocity of this cube that I am moving in order to use this data to move something else.What's more, I also want to save this same velocity data of the cube into a CSV file in order to reply the whole movement of the cube when I am not grabbing it at all(by saying reply I mean read the velocity data I saved while grabbing and moving a cube then the cube or some other object can repeat the whole movement of the cube moved by Leap$$anonymous$$otion or HTC vive). Does this make any sense to you?
Honestly, I am not sure at all if my idea can be done with getComponent().Velocity through rigidbody. What do you think? The reason why I tried to calculate the velocity of the cube is simply I could drag the cube to move in the scene in unity without using the Leap $$anonymous$$otion or Vive Controller to check if I can obtain the speed or not. By saying this I mean if you drag the cube to move in the scene in unity without using the Leap $$anonymous$$otion or Vive Controller to check the rigid body velocity, it always returns 0. Because I never accessed the rigidbody component i.e add force to it, all I did was simply change the object's location based on mouse input.
$$anonymous$$orrow I would put in my Leap $$anonymous$$otion or HTC vive controller and add rigidbody to the cube to check if I can get the rigid body velocity of the cube. According to your expertise, do you think I can use rigid body velocity for my application. What is the best way? Thanks a lot.
@Bunny83 Hi, One more questions about the two scripts above. When it come to the calculation of angular speed, the fist script uses transform.rotation.eulerAngles but transform.eulerAngles is used in the second one. Can you please tell me the difference between the two? Which one do you recommend? Thanks a lot
None of them ^^. Both Transform.eulerAngles and Transform.rotation.eulerAngles are calculated the same way from the quaternion rotation. Euler angles simply have too many issues for calculating delta information.
Ins$$anonymous$$d you may want to store the last rotation as Quaternion and calculate the difference between the old and the new one like this:
Quaternion dif = lastRot * Quaternion.Inverse(transform.rotation);
To turn this into an actual rotation vector you want to use ToAngleAxis:
float angle;
Vector3 axis;
dif.ToAngleAxis(out angle, out axis);
Vector3 angularVelocity = axis * angle / Time.deltaTime;
I haven't tested this but it should work. Note as i said if the actual angular velocity is too large (more than 180° per frame) it's impossible to get accurate information. There could be countless full turns between two measurements which you can not detect. Rotating at for example 270° pre frame would be equal to a rotation of -90° so the deter$$anonymous$$ed velocity would be the other way round (again wagon wheel effect as mentioned above).