Search Unity

Question Writing a Gyroscopic Stabilizer Script for a Mech

Discussion in 'Scripting' started by UnityFledgling, May 18, 2023.

  1. UnityFledgling

    UnityFledgling

    Joined:
    Jan 30, 2022
    Posts:
    20
    Hi,

    I am modeling a Reverse-knee leg Mech in Maya. I will be setting it up for player control in Unity.

    My question is: Are there any resources you know of that cover how to script a gyroscopic staiblizer that keeps the cab of the mech level as the mech's feet step onto uneven ground?

    The cab sits and rotates on the mech's chassis. The reverse knee legs are children of the chassis.

    Thank you for any assistance or referrals.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697
    Simplest is to just SET the rotation of the head to be flat, rock solid.

    But that might not feel... "COOL" enough... I imagine you would want some kind of slight lag or bounce or struggle in the stabilization as it changes, like giant hydraulics fighting to stabilize you.

    To do this you could do various filters on the tilt change, not snapping it always to level but perhaps only driving it towards level by a fraction of how "off" it is from level. You could probably individually lerp two axes, like the +Z and +X axis of the cabin.

    That would give you a tilt if you suddenly lurched, then it would level back off as the Lerp caught up.

    I did all kinds of crazy camera and input system filtering on my Jetpack Kurt game. Check it:

     
    orionsyndrome and UnityFledgling like this.
  3. UnityFledgling

    UnityFledgling

    Joined:
    Jan 30, 2022
    Posts:
    20
    Thanks for the suggestion. Your project looks really cool.

    I do want the cab of the mech to tilt as needed to compensate for the lurching of the chassis in relation to the mech's footing.
     
  4. Elhimp

    Elhimp

    Joined:
    Jan 6, 2013
    Posts:
    75
    For gyrostab topic look for PID controllers. Perfectly applicable to rotation control.
    For making it feel right, make mech parts' rotations follow camera and not otherwise. AKA irl you're moving eyes and head instead of twisting shoulders to looks at things.
    And finally, for uneven terrain there's IK (inverse kinematics). Bipedal entities usually stay upright on all sorts of stuff by using legs and back positioning. And besides other thing IK imitates this exactly.
     
    UnityFledgling and Kurt-Dekker like this.
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697
    Exactly this. I didn't treat it as true roll however: I processed all stab aug off the y component of the transform right and forward vectors to get each axis' deviation from flat. The most interesting parts of the stab aug occur near flat and level and at that point d/dx of sine is nearly 1 so it is quite undistorted.

    Basically the system is constantly trying to level you to some flattened tilt plane indicated by the INCOMING roll and pitch, which once we consider, we promptly discard and replace with the P/D outputs. If you look at the control cyclic stick in the following video you can see how its motion is driven from the stab output and wiggles around essentially as the first time derivative of the user's actual cyclic input.



    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. // @kurtdekker Stability augmentation for Jetpack Kurt Space Flight
    6.  
    7. public partial class SpaceFlightTest1
    8. {
    9.     const float SineOfMaxDeflection = 0.9f;
    10.  
    11.     // The stability augmentation system modifies user cyclic inputs to stabilize the ship.
    12.     //
    13.     // roll and pitch refer to the actual inputs already commanded by the user.
    14.     //
    15.     // We may modify them according to P/D filter outputs below.
    16.     void UpdateStabilityAugmentation( ref float roll, ref float pitch)
    17.     {
    18.         // you're inverted, stab hold is disconnected
    19.         if (rb.transform.up.y < 0)
    20.         {
    21.             return;
    22.         }
    23.  
    24.         SpaceFlightStabilityAugmentationType augmentationType =
    25.             (SpaceFlightStabilityAugmentationType)(DSM.SpaceFlightStabilityAugmentationLevel.iValue);
    26.  
    27.         switch( augmentationType)
    28.         {
    29.         default :
    30.             DSM.SpaceFlightStabilityAugmentationLevel.iValue = (int)SpaceFlightStabilityAugmentationType.DEFAULT;
    31.             return;
    32.  
    33.         case SpaceFlightStabilityAugmentationType.NONE :
    34.             rb.angularDrag = 0.0f;
    35.             rb.drag = 0.0f;
    36.             return;                        // CAUTION: EARLY-OUT!
    37.  
    38.         case SpaceFlightStabilityAugmentationType.LOW :
    39.             rb.angularDrag = 1.0f;
    40.             rb.drag = 0.02f;
    41.             goto case SpaceFlightStabilityAugmentationType.COMMON_STABILITY;
    42.  
    43.         case SpaceFlightStabilityAugmentationType.HIGH :
    44.             rb.angularDrag = 1.5f;
    45.             rb.drag = 0.03f;
    46.             goto case SpaceFlightStabilityAugmentationType.COMMON_STABILITY;
    47.  
    48.         case SpaceFlightStabilityAugmentationType.COMMON_STABILITY :
    49.             {
    50.                 // this is exactly the opposite: the cosine of either Z or X
    51.                 const float MinTiltLimit = 0.01f;
    52.                 const float MaxTiltLimit = 0.10f;
    53.  
    54.                 // post-filtering input
    55.                 const float MinUprightingAuthority = 0.1f;
    56.                 const float MaxUprightingAuthority = 1.0f;
    57.  
    58.                 // the combined MinTiltLimit and MinUprightingAuthority
    59.                 // works with the angular drag to eliminate hunting over
    60.                 // the tiny central area, giving a slight "slop" feel to the controls
    61.  
    62.                 // put it into local transform space so the values are
    63.                 // accurate for our own local coordinate system.
    64.                 var iq = Quaternion.Inverse( rb.rotation);
    65.                 Vector3 LocalAngularVelocity = iq * rb.angularVelocity;
    66.                 const float AngularVelocityCoupling = 0.2f;
    67.  
    68.                 {
    69.                     float rollSine = rb.transform.right.y;        // P
    70.  
    71.                     rollSine += LocalAngularVelocity.z * AngularVelocityCoupling;    // D
    72.  
    73.                     rollSine -= roll * SineOfMaxDeflection;        // user input
    74.  
    75.                     if (Mathf.Abs( rollSine) > MinTiltLimit)
    76.                     {
    77.                         float rollSign = -Mathf.Sign( rollSine);
    78.  
    79.                         float rollAlpha = Mathf.InverseLerp( MinTiltLimit, MaxTiltLimit, Mathf.Abs( rollSine));
    80.  
    81.                         roll = Mathf.Lerp( MinUprightingAuthority, MaxUprightingAuthority, rollAlpha) * rollSign;
    82.                     }
    83.                 }
    84.  
    85.                 {
    86.                     float pitchSine = -rb.transform.forward.y;        // P
    87.  
    88.                     pitchSine += LocalAngularVelocity.x * AngularVelocityCoupling;        // D
    89.  
    90.                     pitchSine -= pitch * SineOfMaxDeflection;        // user input
    91.  
    92.                     if (Mathf.Abs( pitchSine) > MinTiltLimit)
    93.                     {
    94.                         float pitchSign = -Mathf.Sign( pitchSine);
    95.  
    96.                         float pitchAlpha = Mathf.InverseLerp( MinTiltLimit, MaxTiltLimit, Mathf.Abs( pitchSine));
    97.  
    98.                         pitch = Mathf.Lerp( MinUprightingAuthority, MaxUprightingAuthority, pitchAlpha) * pitchSign;
    99.                     }
    100.                 }
    101.             }
    102.             break;
    103.         }
    104.     }
    105. }
     
    Last edited: May 19, 2023
    UnityFledgling likes this.