Problem to to implement Hooke´s Law

Hi!

I am trying to apply hooke’s law to my box.
The problem here is that this “car” not remains in the ground, it starts jumping.

I set this values based on streetcars:

Mass: 1000
Suspension length: 1
Stiffness: 8000

This is my code:

 void FixedUpdate()
    {
        RaycastHit hit;

        for (int i = 0; i < wheelPoints.Length; i++)
        {
            var wheelPoint = wheelPoints[i];

            if (Physics.Raycast(wheelPoint.transform.position,
                                -transform.up,
                                out hit,
                                suspensionLength,
                                layerMask))
            {
                // Spring force
                float contactDepth = hit.distance - suspensionLength;  

                float springForce = - stiffness * contactDepth;
               
                // Final force or suspension force
                float suspensionForce = springForce;
               
                rigidBody.AddForceAtPosition(transform.up * suspensionForce, wheelPoints[i].transform.position, ForceMode.Force);
                vehicleInAir = false;
            }
            else
            {
                vehicleInAir = true;
            }
        }
    }

Is there drag force somewhere? Drag and inefficiency in the spring are what prevent real springs from endlessly oscillating.

Nop, drag force is 0 and Angular Drag is 0.05.

Sorry, the screenshot that I added before is very small.

Easy. You are simulating springs without damper. An ideal spring alone just keeps oscillating forever. What you have there is a Harmonic Oscillator.

Real car suspensions have springs and dampers. Dampers are critical as they dissipate the oscillating energy in the spring allowing them to come to a rest pose. The damper can be implemented easily as a force that opposes the movement of the spring. Check out the mass–spring–damper example in the Wikipedia’s Damping article.

Before I added the damper force, the car has been crazy but it is even worse now. I don’t know what am I doing wrong…

https://www.youtube.com/watch?v=iACL-2KlU18

Current values:
Mass: 1000
Suspension length: 1
Stiffness: 8000
damping: 800 // 10% of the stiffness

Current code:

 void FixedUpdate()
    {
        RaycastHit hit;
        for (int i = 0; i < wheelPoints.Length; i++)
        {
            var wheelPoint = wheelPoints[i];
            if (Physics.Raycast(wheelPoint.transform.position,
                                -transform.up,
                                out hit,
                                suspensionLength,
                                layerMask))
            {
                // Spring force
                float contactDepth = hit.distance - suspensionLength;  
                float springForce = - stiffness * contactDepth;
               
                //Damper force
                float compressionSpeed = contactDepth - lastContactDepth;
                float damperForce = - damping * compressionSpeed;
              
                // Final force or suspension force
                float suspensionForce = springForce + damperForce;
              
                rigidBody.AddForceAtPosition(transform.up * suspensionForce, wheelPoints[i].transform.position, ForceMode.Force);
               
                vehicleInAir = false;
               
                lastContactDepth = contactDepth;
            }
            else
            {
                vehicleInAir = true;
            }
        }

1m is a large and unrealistic suspension.

For Mass=1000, I have a vehicle where these suspension settings work rather good:

Suspension length: 0.25
Spring rate: 25000
Damper rate: 1500

These are the settings at the WheelCollider. I’m not sure if/how they work implemented with direct forces.

Also note that in your code vehicleInAir depends on the latest evaluated wheel only, regardless all other wheels.

Just add wheels it works

Damper force is damping coefficient * speed
In your formula, I think compressionSpeed is not actually a speed, because you forgot dt
Try

                float compressionSpeed = (contactDepth - lastContactDepth)/Time.deltaTime;
                float damperForce = - damping * compressionSpeed;