Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Our response to Improbable’s blog post (and why you can keep working on your SpatialOS game). Read more here
    Dismiss Notice
  4. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Balancing Motorcycle?

Discussion in 'Physics' started by Bimmy02, Jan 11, 2019 at 2:34 PM.

  1. Bimmy02

    Bimmy02

    Joined:
    Friday
    Posts:
    2
    I've been trying to make a script for a motorcycle game but i don't know how to make the balancing part. I've tried to use the rigidbody constrainers but it doesn't work, it still falls after some time. I have also been trying to use AddTorque and AddForce. I don't know how to make this work so I hope someone can help me with this problem i have. Thanks!
     
  2. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    1,293
    I'm really interested on this as well.
     
    Bimmy02 likes this.
  3. SparrowsNest

    SparrowsNest

    Joined:
    Apr 6, 2017
    Posts:
    965
    How about a PID controller to self balance?
    Think of it like the rider shifting it's weight side-to-side.
     
    Bimmy02 likes this.
  4. Bimmy02

    Bimmy02

    Joined:
    Friday
    Posts:
    2
    That seems like a really good idea. I'll try it as soon as i've learned it
     
  5. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    1,293
    Let us know how it goes! :)
     
  6. Marcos-Schultz

    Marcos-Schultz

    Joined:
    Feb 24, 2014
    Posts:
    176
  7. Marcos-Schultz

    Marcos-Schultz

    Joined:
    Feb 24, 2014
    Posts:
    176
    Motorcycle physics is a little complex. You can use the inverted pendulum equations to try to stabilize things, or you can do everything in the most realistic way possible: https://en.wikipedia.org/wiki/Bicycle_and_motorcycle_dynamics

    Personally, I believe that using a few tricks controlling "ribidbody.anglarVelocity" directly is simpler and more effective. Unless you are trying to create a realistic simulator.
     
  8. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    1,293
    I had tried by setting the center of mass below the surface but then it behaves like a pendulum, oscillating from side to side. Also the bike tilts in the opposite way when accelerating and braking.
     
  9. Marcos-Schultz

    Marcos-Schultz

    Joined:
    Feb 24, 2014
    Posts:
    176
    I did some testing here. Just play the code below on an empty object and press Play.

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. [RequireComponent(typeof(Rigidbody))][RequireComponent(typeof(BoxCollider))]
    7. public class Motorcycle : MonoBehaviour { //MS Motorcycle test - Marcos Schultz (www.schultzgames.com)
    8.  
    9.     WheelCollider frontWheel;
    10.     WheelCollider rearWheel;
    11.     GameObject meshFront;
    12.     GameObject meshRear;
    13.     Rigidbody ms_Rigidbody;
    14.  
    15.     float rbVelocityMagnitude;
    16.     float horizontalInput;
    17.     float verticalInput;
    18.     float medRPM;
    19.  
    20.     void Awake () {
    21.         transform.rotation = Quaternion.identity;
    22.         ms_Rigidbody = GetComponent<Rigidbody> ();
    23.         ms_Rigidbody.mass = 400;
    24.         ms_Rigidbody.interpolation = RigidbodyInterpolation.Extrapolate;
    25.         ms_Rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
    26.  
    27.         //centerOfMass
    28.         GameObject centerOfmassOBJ = new GameObject ("centerOfmass");
    29.         centerOfmassOBJ.transform.parent = transform;
    30.         centerOfmassOBJ.transform.localPosition = new Vector3 (0.0f, -0.3f, 0.0f);
    31.         ms_Rigidbody.centerOfMass = transform.InverseTransformPoint(centerOfmassOBJ.transform.position);
    32.         //
    33.         BoxCollider collider = GetComponent<BoxCollider>();
    34.         collider.size = new Vector3 (0.5f, 1.0f, 3.0f);
    35.         //
    36.         GenerateWheels();
    37.     }
    38.  
    39.     void OnEnable(){
    40.         WheelCollider WheelColliders = GetComponentInChildren<WheelCollider>();
    41.         WheelColliders.ConfigureVehicleSubsteps(1000, 30, 30);
    42.     }
    43.  
    44.     void FixedUpdate () {
    45.         horizontalInput = Input.GetAxis ("Horizontal");
    46.         verticalInput = Input.GetAxis ("Vertical");
    47.         medRPM = (frontWheel.rpm + rearWheel.rpm) / 2;
    48.         rbVelocityMagnitude = ms_Rigidbody.velocity.magnitude;
    49.  
    50.         //motorTorque
    51.         if (medRPM > 0) {
    52.             rearWheel.motorTorque = verticalInput * ms_Rigidbody.mass * 4.0f;
    53.         } else {
    54.             rearWheel.motorTorque = verticalInput * ms_Rigidbody.mass * 1.5f;
    55.         }
    56.  
    57.         //steerAngle
    58.         float nextAngle = horizontalInput * 35.0f;
    59.         frontWheel.steerAngle = Mathf.Lerp (frontWheel.steerAngle, nextAngle, 0.125f);
    60.  
    61.  
    62.         if(Mathf.Abs(rearWheel.rpm) > 10000){
    63.             rearWheel.motorTorque = 0.0f;
    64.             rearWheel.brakeTorque = ms_Rigidbody.mass * 5;
    65.         }
    66.         //
    67.         if (rbVelocityMagnitude < 1.0f && Mathf.Abs (verticalInput) < 0.1f) {
    68.             rearWheel.brakeTorque = frontWheel.brakeTorque = ms_Rigidbody.mass * 2.0f;
    69.         } else {
    70.             rearWheel.brakeTorque = frontWheel.brakeTorque = 0.0f;
    71.         }
    72.         //
    73.         Stabilizer();
    74.     }
    75.  
    76.     void Update(){
    77.         //update wheel meshes
    78.         Vector3 temporaryVector;
    79.         Quaternion temporaryQuaternion;
    80.         //
    81.         frontWheel.GetWorldPose(out temporaryVector, out temporaryQuaternion);
    82.         meshFront.transform.position = temporaryVector;
    83.         meshFront.transform.rotation = temporaryQuaternion;
    84.         //
    85.         rearWheel.GetWorldPose(out temporaryVector, out temporaryQuaternion);
    86.         meshRear.transform.position = temporaryVector;
    87.         meshRear.transform.rotation = temporaryQuaternion;
    88.     }
    89.  
    90.     void Stabilizer(){
    91.         Vector3 axisFromRotate = Vector3.Cross (transform.up, Vector3.up);
    92.         Vector3 torqueForce = axisFromRotate.normalized * axisFromRotate.magnitude * 50;
    93.         torqueForce.x = torqueForce.x * 0.4f;
    94.         torqueForce -= ms_Rigidbody.angularVelocity;
    95.         ms_Rigidbody.AddTorque (torqueForce * ms_Rigidbody.mass * 0.02f, ForceMode.Impulse);
    96.  
    97.         float rpmSign = Mathf.Sign (medRPM) * 0.02f;
    98.         if (rbVelocityMagnitude > 1.0f && frontWheel.isGrounded && rearWheel.isGrounded) {
    99.             ms_Rigidbody.angularVelocity += new Vector3 (0, horizontalInput * rpmSign, 0);
    100.         }
    101.     }
    102.  
    103.     void GenerateWheels(){
    104.         GameObject frontWeelObject = new GameObject ("frontWheel");
    105.         frontWeelObject.transform.parent = transform;
    106.         frontWeelObject.transform.localPosition = new Vector3 (0, -0.5f, 1.0f);
    107.         frontWheel = frontWeelObject.gameObject.AddComponent<WheelCollider> () as WheelCollider;
    108.         //
    109.         GameObject rearWheelObject = new GameObject ("rearWheel");
    110.         rearWheelObject.transform.parent = transform;
    111.         rearWheelObject.transform.localPosition = new Vector3 (0, -0.5f, -1.0f);
    112.         rearWheel = rearWheelObject.gameObject.AddComponent<WheelCollider> () as WheelCollider;
    113.  
    114.         //settings
    115.         frontWheel.mass = rearWheel.mass = 40;
    116.         frontWheel.radius = rearWheel.radius = 0.5f;
    117.         frontWheel.wheelDampingRate = rearWheel.wheelDampingRate = 0.75f;
    118.         frontWheel.suspensionDistance = rearWheel.suspensionDistance = 0.35f;
    119.         frontWheel.forceAppPointDistance = rearWheel.forceAppPointDistance = 0;
    120.  
    121.         //spring
    122.         JointSpring suspensionSpringg = new JointSpring ();
    123.         suspensionSpringg.spring = 15000;        
    124.         suspensionSpringg.damper = 4000;        
    125.         suspensionSpringg.targetPosition = 0.5f;
    126.         frontWheel.suspensionSpring = rearWheel.suspensionSpring = suspensionSpringg;
    127.  
    128.         //Friction
    129.         WheelFrictionCurve wheelFrictionCurveFW = new WheelFrictionCurve(); //friction FW
    130.         wheelFrictionCurveFW.extremumSlip = 2.0f;
    131.         wheelFrictionCurveFW.extremumValue = 4.0f;
    132.         wheelFrictionCurveFW.asymptoteSlip = 4.0f;
    133.         wheelFrictionCurveFW.asymptoteValue = 2.0f;
    134.         wheelFrictionCurveFW.stiffness = 2.0f;
    135.         frontWheel.forwardFriction = rearWheel.forwardFriction = wheelFrictionCurveFW;
    136.  
    137.         WheelFrictionCurve wheelFrictionCurveSW = new WheelFrictionCurve(); //friction SW
    138.         wheelFrictionCurveSW.extremumSlip = 0.2f;
    139.         wheelFrictionCurveSW.extremumValue = 1.0f;
    140.         wheelFrictionCurveSW.asymptoteSlip = 0.5f;
    141.         wheelFrictionCurveSW.asymptoteValue = 0.75f;
    142.         wheelFrictionCurveSW.stiffness = 2.0f;
    143.         frontWheel.sidewaysFriction = rearWheel.sidewaysFriction = wheelFrictionCurveSW;
    144.  
    145.  
    146.         //generateMeshes
    147.         GameObject wheelFrontMesh = new GameObject ("wheelFrontMesh");
    148.         GameObject meshFrontTemp = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
    149.         Destroy (meshFrontTemp.GetComponent<CapsuleCollider> ());
    150.         meshFrontTemp.transform.parent = wheelFrontMesh.transform;
    151.         meshFrontTemp.transform.localPosition = new Vector3 (0.0f, 0.0f, 0.0f);
    152.         meshFrontTemp.transform.localEulerAngles = new Vector3 (0.0f, 0.0f, 90.0f);
    153.         meshFrontTemp.transform.localScale = new Vector3 (1.0f, 0.1f, 1.0f);
    154.         meshFront = wheelFrontMesh;
    155.         meshFront.transform.parent = transform;
    156.         meshFront.transform.localPosition = new Vector3 (0, -0.5f, 1.0f);
    157.         //
    158.         GameObject wheelRearMesh = new GameObject ("wheelRearMesh");
    159.         GameObject meshRearTemp = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
    160.         Destroy (meshRearTemp.GetComponent<CapsuleCollider> ());
    161.         meshRearTemp.transform.parent = wheelRearMesh.transform;
    162.         meshRearTemp.transform.localPosition = new Vector3 (0.0f, 0.0f, 0.0f);
    163.         meshRearTemp.transform.localEulerAngles = new Vector3 (0.0f, 0.0f, 90.0f);
    164.         meshRearTemp.transform.localScale = new Vector3 (1.0f, 0.1f, 1.0f);
    165.         meshRear = wheelRearMesh;
    166.         meshRear.transform.parent = transform;
    167.         meshRear.transform.localPosition = new Vector3 (0, -0.5f, -1.0f);
    168.         //
    169.         GameObject meshCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
    170.         Destroy (meshCube.GetComponent<BoxCollider> ());
    171.         meshCube.transform.parent = transform;
    172.         meshCube.transform.localPosition = new Vector3 (0.0f, 0.0f, 0.0f);
    173.         meshCube.transform.localScale = new Vector3 (0.5f, 1.0f, 3.0f);
    174.     }
    175. }
    176.  
    177.  
    It has several problems, but it is already a principle to achieve a little stability.
     
    Last edited: Jan 16, 2019 at 2:08 AM