Raycast suspension makes car accelerates when inclined

The speed increases forever when the car is inclined like the pic below. Doesn’t make sense to me, but I can’t find where is the error in my code.
The raycasts are in empty GameObjects in each place that will have a wheel.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Suspension : MonoBehaviour
{
    [Header("Which Wheel")]
    public bool WheelFrontLeft;
    public bool WheelFrontRight;

    private Rigidbody rb;
    [Header("Suspension")]
    public float restLength;
    public float springTravel;

    private float minLength;
    private float maxLength;
    public float springLength;
    public float lastSpringLength;

    public float springForce;
    public float springStiffness = 30000;



    public Vector3 suspensionForce;
    [Header("Wheel")]
    public float wheelRadius;
    public float steerAngle;

    void Start()
    {
        rb = transform.parent.transform.parent.GetComponent<Rigidbody>();
        minLength = restLength - springTravel;
        maxLength = restLength + springTravel;
    }

    // Update is called o   nce per frame
    void FixedUpdate()
    {
        Ray ray = new Ray(transform.position, -transform.up);

        Debug.DrawLine(ray.origin, -restLength * transform.up + transform.position, Color.yellow);
        Debug.DrawLine(-restLength * transform.up + transform.position, -restLength * transform.up + transform.position + transform.up * -wheelRadius, Color.blue);

        if (Physics.Raycast(ray, out RaycastHit hitInfo, maxLength + wheelRadius))
        {


            springLength = hitInfo.distance - wheelRadius;
            springLength = Mathf.Clamp(springLength, minLength, maxLength);
            springForce = (restLength - springLength) * springStiffness;

            suspensionForce = springForce * transform.up;
            suspensionForce = (suspensionForce + transform.up * 1000 * (lastSpringLength - springLength) / Time.fixedDeltaTime); //+ Physics.gravity * rb.mass * Mathf.Cos(Vector3.Angle(Physics.gravity, transform.up));
            rb.AddForceAtPosition(suspensionForce, transform.position);
            lastSpringLength = springLength;

        }
    }
}

When you car is tilted forward, the transform.up vector is also tilted forward. With that, suspensionForce also has a forward component. I actually made the same mistake :slight_smile: the suspension force should point in the direction of hitInfo.normal, which is the same as “up” for a flat ground.

I also noticed (lastSpringLength - springLength). Better use rb.GetVelocityAtPoint(wheel position) and project the velocity onto transform.up (the direction of the spring) with Unity - Scripting API: Vector3.Project to get only the velocity along the suspension.

And additionally, you should add a property springDamping

2 Likes

Shouldn’t the suspensions have the forward component when it is tilted? What if I want my suspension to be like in the pic, one higher than the other, without being orthogonal?
When I imagine a car like that, I visualize it compressing down and backward, then uncompressing towards up and forward. Am I wrong?

Think in a extreme case: a car driving on two wheels.

The total force that sustain the car is applied vertically. However this vertical force has two components:

  • The suspension spring, applied along the local car’s “up” direction.
  • The suspension strut (rigid), applied sideways (local car’s “right” direction).

The sum of both forces is exactly the vertical force necessary to sustain the car’s weight. However, the more angle of inclination the less force is required from the suspension spring and more from the rigid suspension components. If we tilt the car 90 degrees then the suspension spring wouldn’t apply any force at all.

2 Likes

Thanks @Edy , I was already thinking back and forth about how to explain this. Good job :slight_smile:

On the matter: You can also think about it like this: When the car is tilted more, the effective spring constant gets increased. If you spring constant is 3000 (like in your example), it becomes 3000 / cos(alpha). So for a car that is tilted 60 degrees (doesn’t matter if sideways like in the picture or front to back), the effective spring constant will be 3000 / cos(60°) = 3000 / 0.5 = 6000.

If we overdo this and put the car all the way on the side: cos(90°) = 0 => 3000 / 0 the spring constant becomes virtually infinite and will feel like a rigid collision.

1 Like

@tjmaul it’s a way to see it, but I can’t see the practical sense. The amount of weight that has to be sustained is finite. It’s only distributed among the suspension spring (local “up”) and the rigid suspension strut (local “right”).

When the car is tilted the suspension spring has to sustain less weight, but the suspension strut must sustain the remaining amount of weight so the vector sum of both forces result the same. If the car is all the way on the side then the spring doesn’t have to sustain any weight. All the stress falls on the rigid suspension components, which must support the entire weight.

2 Likes

First of all, thank you both. I feel like I understand more now.

Now the question: are these diagrams correct? It’s weird to me that the weight is distribuited this way. I mean, the weight is perpendicular to the ground, but the other two forces aren’t. However, I can decompose a vector in an infinite number of other vectors, right? So the logic isn’t wrong. Idk if it is what you guys where trying to explain.

No, it’s more like this:

The total force (red) is the vector sum of the suspension force (green) and the lateral force applied by the tire sidewall and the rigid suspension components (blue).

PS: Magnitudes are not to scale. The white arrow should have the same length as the red arrow.