Search Unity

Featherstone's solver for articulations

Discussion in 'Physics Previews' started by yant, Dec 11, 2019.

  1. jselstad

    jselstad

    Joined:
    Apr 12, 2016
    Posts:
    6
    Thank you, kstorey.

    I am using drives on the fingers (yields the best friction); I’m not sure the current Unity API allows for Articulation roots to be parented/constrained to other Rigidbodies or have spatial linear drives... yet... but luckily the Force/Torque solution I’m using works relatively well.

    The new properties in 2020.1a23 should be very useful for suppressing solver instability. The physics timestep is currently running at 90hz, but increasing that may be another path towards improvement (since I’m able to sample interpolated hand tracking frames for each physics timestep as well).

    Is there a plan for implementing “Rigidbody interpolation” for articulations, Yant? (It re-interpolates the motion of the objects from the physics timestep to the render timestep). If not, I’ll need to keep the simulation timestep as a multiple of the framerate to maintain smooth motion...
     
  2. Kobix

    Kobix

    Joined:
    Jan 23, 2014
    Posts:
    79
    How to enable..? Are PhysX Articulations calculated on GPU?
     
  3. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    368
    This is not exposed yet in Unity, I'm afraid.
     
  4. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    368
    We don't have this ready yet -- as there are some architectural difficulties in how Joints were designed over a decade ago, but this is on the short-list to be addressed.
     
  5. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    368
    No, we don't have a plan for interpolation yet.

    Just wanted to voice this idea that we have this call Physics.Simulate(), which is useful to run the simulation once. The way you use it is disable the automatic simulation and then write a script that calls into Physics.Simulate() as required. That setup should allow easy integration for custom update schemes, including twice per frame. (as opposed to trying to match the required frequency per update by tweaking the global simulation frequency).

    Hope that helps.
     
    mvaandrager and jselstad like this.
  6. flawless_code

    flawless_code

    Joined:
    Feb 5, 2020
    Posts:
    7
    It's ok, new AMD processors have very high core count :)
     
  7. flawless_code

    flawless_code

    Joined:
    Feb 5, 2020
    Posts:
    7
    Cool! That would make Unity much more universal.

    Upgrading to new alpha version as we speak, might report soon about improvements.
     
    yant likes this.
  8. zalo10

    zalo10

    Joined:
    Dec 5, 2012
    Posts:
    18
    So I made a simple test scene for spherical joints. ArticulationBug.gif

    It looks like there's a bug in the way that the X, Y, and Z drives work together... I suspect there's a wrongly-ordered quaternion multiplication somewhere.

    Here's the code and scene I'm using:
    Code (CSharp):
    1. using UnityEngine;
    2. public class ArticulationTest : MonoBehaviour {
    3.     public ArticulationBody body;
    4.     void FixedUpdate() {
    5.         // Normalize Quaternion to suppress greater than 360 degree rotations
    6.         Quaternion normalizedRotation = Quaternion.Normalize(transform.rotation);
    7.  
    8.         // Calculate drive targets
    9.         Vector3 driveTarget = new Vector3(
    10.           Mathf.DeltaAngle(0, normalizedRotation.eulerAngles.x),
    11.           Mathf.DeltaAngle(0, normalizedRotation.eulerAngles.y),
    12.           Mathf.DeltaAngle(0, normalizedRotation.eulerAngles.z));
    13.  
    14.         // Copy the X, Y, and Z target values into the drives...
    15.         ArticulationDrive xDrive = body.xDrive; xDrive.target = driveTarget.x; body.xDrive = xDrive;
    16.         ArticulationDrive yDrive = body.yDrive; yDrive.target = driveTarget.y; body.yDrive = yDrive;
    17.         ArticulationDrive zDrive = body.zDrive; zDrive.target = driveTarget.z; body.zDrive = zDrive;
    18.     }
    19. }
    20.  
     

    Attached Files:

  9. zalo10

    zalo10

    Joined:
    Dec 5, 2012
    Posts:
    18
    After some trial-and-error, drive code without any singularities looks like this:
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. public class ArticulationTest : MonoBehaviour {
    4.     public ArticulationBody body;
    5.     public float Strength = 1f;
    6.     void FixedUpdate() {
    7.         // Calculate the delta between the current rotation and the desired rotation
    8.         Quaternion deltaRotation = Quaternion.Normalize(Quaternion.Inverse(body.transform.localRotation) * transform.rotation);
    9.  
    10.         // Calculate drive velocity necessary to undo this delta in one fixed timestep
    11.         ArticulationReducedSpace driveTargetForce = new ArticulationReducedSpace(
    12.           ((Mathf.DeltaAngle(0, deltaRotation.eulerAngles.x) * Mathf.Deg2Rad) / Time.fixedDeltaTime) * Strength,
    13.           ((Mathf.DeltaAngle(0, deltaRotation.eulerAngles.y) * Mathf.Deg2Rad) / Time.fixedDeltaTime) * Strength,
    14.           ((Mathf.DeltaAngle(0, deltaRotation.eulerAngles.z) * Mathf.Deg2Rad) / Time.fixedDeltaTime) * Strength);
    15.  
    16.         // Apply the force in local space (unlike AddTorque which is global space)
    17.         // Ideally we'd use inverse dynamics or jointVelocity, but jointVelocity is bugged in 2020.1a22
    18.         body.jointForce = driveTargetForce;
    19.     }
    20. }
    21.  
    I assume this can be substituted in for the existing xDrive, yDrive, and zDrive code in the engine. The bug probably comes from one of two places...

    1. You can't just reconstruct the body's orientation from the reducedCoordinate joint positions (it's unclear why not, probably a different ordering in which x, y, and z are applied):

    Code (CSharp):
    1.         // This will give you the incorrect orientation
    2.         Quaternion jointRotation = Quaternion.Euler(
    3.             body.jointPosition[0] * Mathf.Rad2Deg,
    4.             body.jointPosition[1] * Mathf.Rad2Deg,
    5.             body.jointPosition[2] * Mathf.Rad2Deg);
    2. It's possible the ordering of the quaternion multiply in line 8 above is reversed; I see similar unstable behavior in my code when I intentionally reverse the order...

    EDIT: It looks like setting the jointVelocity directly is bugged for any of the joints further down the kinematic chain... Looks like another bug...

    EDIT 2: Setting jointForce has a similar effect, but it propagates down the chain properly. Please fix jointVelocity!

    EDIT 3: Colliders that are children of the articulation do not appear to be detected by the articulation's joints... Do they need to be fixed joint articulations?

    EDIT 4: Fixed Joint articulation children do not appear to be incorporated properly either... Looks like I'm not going to be able to weasel out of some deep quaternion management if I want oriented colliders in my articulations...

    EDIT 5: Setting jointForce on a branching articulation (eg a humanoid) hard-crashes the editor :(
     
    Last edited: Feb 9, 2020
    CodeKiwi likes this.
  10. flawless_code

    flawless_code

    Joined:
    Feb 5, 2020
    Posts:
    7
    Hey, try to have at least one collider on every Articulation, with non-zero weight. It can be very small sphere, I think that helped me in the past.
     
    mvaandrager likes this.
  11. zalo10

    zalo10

    Joined:
    Dec 5, 2012
    Posts:
    18
    Thank you, I did try that, but only the rotary joint's small, centered collider affected the inertia of the system appropriately. :(
     
  12. flawless_code

    flawless_code

    Joined:
    Feb 5, 2020
    Posts:
    7
    Btw, I noticed new alpha is out:

     
unityunity