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. We've updated our Terms of Service. Please read our blog post from Unity CTO and Co-Founder Joachim Ante 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.

  1. Bimmy02

    Bimmy02

    Joined:
    Jan 11, 2019
    Posts:
    4
    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,302
    I'm really interested on this as well.
     
    Bimmy02 likes this.
  3. SparrowsNest

    SparrowsNest

    Joined:
    Apr 6, 2017
    Posts:
    983
    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:
    Jan 11, 2019
    Posts:
    4
    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,302
    Let us know how it goes! :)
     
  6. Marcos-Schultz

    Marcos-Schultz

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

    Marcos-Schultz

    Joined:
    Feb 24, 2014
    Posts:
    177
    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.
     
    Bimmy02 likes this.
  8. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    1,302
    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:
    177
    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
    alexeu and Bimmy02 like this.
  10. Bimmy02

    Bimmy02

    Joined:
    Jan 11, 2019
    Posts:
    4
    Thanks! That code is actually really good. Do anyone have any idea how to make the motorcycle lean when i press A/D
     
  11. alexeu

    alexeu

    Joined:
    Jan 24, 2016
    Posts:
    89
    motorcycle lean...
    You mean like this ?
     
  12. Bimmy02

    Bimmy02

    Joined:
    Jan 11, 2019
    Posts:
    4
    Yes! Exactly like that.
     
  13. alexeu

    alexeu

    Joined:
    Jan 24, 2016
    Posts:
    89
    That depends on your own built/hierarchy... you also have to deal with wheels colliders settings etc...etc...
    But basicaly you just rotate the Cube Mesh(basicaly meshs and Renderers) that represents the body of your vehicle.
    Lets say we declare this vehicle body as
    Code (CSharp):
    1. public Transform bikeBody;
    2.  
    In Update() you can rotate it like this
    Code (CSharp):
    1. Quaternion bodyRotation = transform.rotation * Quaternion.Euler(0f, 0f, -frontWheel.steerAngle * verticalInput);
    2. bikeBody.rotation = Quaternion.Lerp(bikeBody.rotation, bodyRotation, 0.1f);
     
  14. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    4,888