- Home /
Velocity from Rigidbody and from Transform don't match for small dt
Hello,
for simulating an IMU attached to a robot I need to calculate accelerations from GameObject Transformation. A rigidbody cannot be attached to an articulated body without affecting it. Therefore I need to come up with a "Passive"-RigidBody. While checking my script against the RigidBody in a simple example i.e. a cube falling under gravity things look good for typical default dt (0.01, 0.001). But when decreasing fixed dt (<=0.0001) to improve physics simulation quality things get awkward.
A body falling in constant gravity should build up velocity constantly and acceleration should be constant and equal gravity. This is the case for RigidBody.velocity. But velocity and acceleration calculated from differentiating transform.position shows step changes in velocity and jumps in acceleration. Indicating that transform.position is not updated for gravity and perhaps not synchronized with the physics system as I would expect.
Please use script attached on a GameObject with a rigidbody falling in gravity. VelocityError will be Zero for dt=0.01 but significant for dt<=0.0001. (Fixed Time Step). Sync Transformation in Physics script is enabled!
Any idea on how to measure velocity and acceleration with high quality in unity using a passive sensor?
Thanks a lot,
Tobias
sing System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class IMUtest : MonoBehaviour
{
public Vector3 velocityError; //diff between velcity reported from rigidbody and calculated from transformation
public Vector3 velocity; //real velocity in world frame
public Vector3 acceleration; //real acceleration in world frame
public Vector3 angularVelocity { get; private set; } //real angularVelocity in world frame
public Vector3 angularAcceleration { get; private set; } //real angularVelocity in world frame
public Vector3 accel{ get; private set; } //measured accelerations in [g] in local frame
public Vector3 gyro{ get; private set; } //measured angular rates in [rad/s] in local frame
private Rigidbody rb;
private Vector3 posOld;
private Quaternion rotOld;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
posOld = transform.position;
rotOld = transform.rotation;
velocity = new Vector3(0.0f, 0.0f, 0.0f);
acceleration = new Vector3(0.0f, 0.0f, 0.0f);
angularVelocity = new Vector3(0.0f, 0.0f, 0.0f);
angularAcceleration = new Vector3(0.0f, 0.0f, 0.0f);
accel = new Vector3(0.0f, 0.0f, 0.0f);
gyro = new Vector3(0.0f, 0.0f, 0.0f);
}
void FixedUpdate()
{
FixedUpdateVelocityAndAcceleration();
FixedUpdateMeasurements();
//just debugging
velocityError = velocity- rb.velocity;
Debug.Log(velocityError);
}
private void FixedUpdateVelocityAndAcceleration()
{
//Calculate Linear Velocity and Acceleration in World Coordinates!
var vNew = (transform.position - posOld) / Time.fixedDeltaTime;
var aNew = (vNew - velocity) / Time.fixedDeltaTime;
posOld = transform.position;
velocity = vNew;
acceleration = aNew;
//Calculate Angular Velocity in World Coordinates!
var deltaRot = transform.rotation * Quaternion.Inverse(rotOld);
deltaRot.ToAngleAxis(out var angle, out var axis);
var angularVelocityNew = (angle * Mathf.Deg2Rad) * axis / Time.fixedDeltaTime;
var angularAccelerationNew = (angularVelocityNew - angularVelocity) / Time.fixedDeltaTime;
rotOld = transform.rotation;
angularVelocity = angularVelocityNew;
angularAcceleration = angularAccelerationNew;
}
private void FixedUpdateMeasurements()
{
accel = transform.InverseTransformDirection( acceleration - Physics.gravity) / Physics.gravity.magnitude;
gyro = transform.InverseTransformDirection( angularVelocity );
}
// Update is called once per frame
void Update()
{
Debug.DrawRay(transform.position, transform.TransformDirection(accel), Color.blue);
Debug.DrawRay(transform.position, transform.TransformDirection(gyro), Color.yellow);
}
}
For comparison purposes, how would using Rigidbody.position compare, as opposed to using Transform.position as you are now? Where Transform.position should essentially update its information for an Update() cycle, it looks like Rigidbody.position should be strictly tied to the current FixedUpdate()/physics cycle.
Answer by TobiasWeber · Sep 06, 2021 at 01:16 PM
Hi Eno-Khaon,
as suggested I've compared Rigidbody.position with Transform.position. They are both equal. So update between Rigidbody and Transform happens as documented.
>
Based on your hint I see the mismatch is between Rigidbody.velocity and (Transform.position - old.Transform.position)/Time.fixedDeltaTime. Transform is limited to float accuracy and I already spend significant amount of its accuracy for the "absolute" position. While Rigidbody.velocity either is using double precision math inside or works with better scaled / smaller relative numbers.
Take away is:
Transform is float and that limits the applicability of Unity for the type of engineering task I had intended.
Alternative route is to learn on how to combine an articulated body with RigidBody to directly read it's velocity and acceleration with higher resolution form the Physics system. Or another type of passive sensor running within the physics backend
Any Idea on how DOTS is going to change the available accuracy of the physics sub-system?
Thanks a lot for your support!
Tobias