# How to create a suspension model with 2 springs?

This topic is 1339 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Basically I want to create a suspension that has 2 springs with 2 seprate compressions, one spring is actually for the tire.

I am keeping things simple, so its only the vertical action(raycast for example)

As far as I know and wich works quite well, is this method:

• create a raycast with a length of:
rayLength = suspensionTravel + radius; // (so it's basically something like 0.2 + 0.3 = 0.5)
rayHit = CreateRay(rayLength,suspensionPosition);
• calculate the compression like this:
prevCompression = compression;
compression = (suspensionTravel - (rayHit.distance - radius));
• calculate vertical force like this:
springVelocity = (compression - prevCompression)/timeStep;
springForce = springRate * compression; // springRate is something like 50000
damperForce = damperRate * springVelocity; // damperRate is something like 2500
totalSpringForce = springForce + damperForce;

Now I'd like to know how I'd add a secondary spring to the same raycast?
The difficult part for me, is to know how to calculate the secondary compression(tire deflection in this case) ?
And how to combine these 2 compressions, so that they would have theyr seprate functionality?

##### Share on other sites

For the tire deflection should I do something like this?

prevTireDeflection = tireDeflection;
tireDeflection = (radius - (rayHit.distance - (suspensionTravel + rimRadius)));

If this is the right way, then how to make it so that the tire 3d mesh can "sink" into the car to represent a flat tire etc. ?

##### Share on other sites

Sorry. Messed up the derivation and deleted a bunch of incorrect equations. In any case, the situation is as shown. The previous positions are immaterial. At any point in time, where D is the distance from the suspension arm to the ground (your raycast from the suspension arm to the ground), the point between the springs (spring and tire) is (momentarily) at rest and, because it's at rest, the force from spring1 = force from spring2.

I have to run - will update later if I can. Apologies.

[attachment=21736:two-springs.png]

D = x1 + x2

Given x1rest as the "rest" position for spring1, the force for spring1 is (x1rest - x1)*k1. Similarly for spring2.

(x1rest - x1)*k1 = (x2rest - x2)*k2

k1*x1 = k1*x1rest - (x2rest - x2)*k2

x1 = D - x2

k1 * (D-x2) = k1*x1rest - (x2rest-x2)*k2

Solve for x2, as k1, k2, D, x1rest and x2rest are known.

EDIT: gather knowns on one side of the equation as follows:

k1*D - k1*x1rest + k2*x2rest = k1*x2 + k2*x2 = (k1+k2)*x2

-or-

x2 = (k1*D - k1*x1rest + k2*x2rest) / (k1+k2)

x1 = D - x2, and you have the point between the tire and the spring, where x2 would be the "squashed" radius of the tire.

The upward force on the car (at the suspension point) is either k1*x1 or k2*x2.  If that upward force is less than the downward force (primarily due to m*g) then the car when "accelerate" downward, and D will decrease until k1*x1 = downward force.

To make the tire go flat, just decrease k2 (proportional to air pressure) and solve again.

Edited by Buckeye

##### Share on other sites

Thanks for the math Buckeye! But I have a few questions, mostly what's the "dynamical" ray length?
Here I see these:
D - maxLength/rayLength
x1 - springDeflection/compression/travel
x2 - tireDeflection
k1 - springRate
k2 - tireRate
x1rest - resting suspension position (half the actual spring length?)
x2rest - the rim radius ?

So using your algebra I get this:

rayLength = compression+tireDeflection; // should this be the actual ray length after the ray is created i.e. hit.distance?

totalSpringForce = springRate * rayLength;
staticSpringForce = springRate*springRestLen;

tireDeflection = (totalSpringForce  - staticSpringForce  + staticTireForce) / (springRate+tireRate);
compression = rayLength - tireDeflection; // tireDeflection should be the dynamic radius wich is close to the actual loaded radius

springForce = (springRestLen - compression)*springRate;
// springForce = tireForce ... if so, then I dont have to add them together to act on the rigid body right?
// and if one of the forces contains a static weight, I have to add it to the other aswell i.e. wheel mass?

upwardforce = springRate*compression; // the load on wheel

I added some questions to the comments but here are my other questions:

Are x1rest & x2rest the actual lengths(spring length and wheel radius (rim+sidewall)) or the resting positions?

Do I define the actual ray length as x1rest+x2rest or maxTravel+wheelRadius?

And what part of the math is for tire sidewall height?

Also, how could I make it so that tire pressure (wich would be a part of calculating tireRate) would change the wheel load, because right/under- &over-inflated tires behave differently, so I'm not sure that "springForce = tireForce" is always the case. Now I can think of a pressure ratio to multiply the actual wheel load, or is there another way to do this?

Edit:
I found this page, seems to be the same stuff, but more documented, I'll see what I can come up with...

##### Share on other sites

I'm having a little trouble translating your variable names to what they are in the "real world."

Hopefully I can expand a little.

In my equations:

D is the distance between the top of the suspension spring and the ground. That is, I assume the spring is attached to the chassis at the top. I assumed (perhaps incorrectly) that you cast a ray from the top of the spring to the ground.

D therefore represents the length of the compressed spring plus the distance between the center of the tire and the ground. Half of the "compressed" tire is shown at the bottom of the compressed spring.

[attachment=21740:spring-and-tire.png]

The term x1rest is the uncompressed length of the spring. That is, if you let any spring relax (no compression or stretching), it will be of a certain length. That is the "rest" or "relaxed" length of the spring. If you push or pull on the spring (compress it or stretch it), it takes force to do so. That force = -k * dx,  where k is the spring constant, and dx is the displacement from the relaxed length, in either direction from the rest length. The force is shown as negative because the force will be in the opposite direction of the movement. It always resists being compressed or stretched. E.g., if a relaxed spring is one meter long, and you compress it to a length of 90 centimeters, the force it takes to do that is: F = -k * 10cm.

I am always characterizing the tire (from the center of the wheel to the ground) as a spring. If you inflate a tire to some pressure, it will have a certain radius. That equivalent to the equivalent spring's relaxed length. If you try to compress the tire, it takes force which I am modeling as a spring. The force = -k * dx, where k is modeled as proportional to the tire pressure, and dx is the difference in the relaxed radius and the compressed radius.

Hope that helps a bit.

Edited by Buckeye

##### Share on other sites

I cant get it working, the vertical force sticks the car to the ground or pushes it away intensely, causing it "pumping" on the surface

heres my code sofar:

		float x1,x2;	// position
float v1,v2;	// velocity
float F1,F2;	// force
float D1,D2;	// damper
float L1,L2;	// how much is stretched

float w1,w2;	// width
float k1,k2;	// spring constant (springRate)
float b1,b2;	// damping constant (friction)
float R1,R2;	// rest length of springs

w1 = maxTravel; // block 1 width, should this be the static spring length or not?
w2 = 0;
R1 = 0.08f;
R2 = 0.0f;
k1 = 55000.0f;
k2 = 111000.0f;
b1 = 2000;
b2 = 1000;

//x1
lastCompression = compression;
compression = (hitDistance - tireDeflection);

//x2
lastTireDeflection = tireDeflection;
tireDeflection = (k1*hitDistance - k1*R1 + k2*R2) / (k1+k2);

L1 = compression - R1;
L2 = tireDeflection - compression - w1 - R2; // from http://www.myphysicslab.com/dbl_spring1.html

F1 = -k1 * L1;
F2 = -k2 * L2;
v1 = (compression - lastCompression) / deltaTime;
v2 = (tireDeflection - lastTireDeflection) / deltaTime;
D1 = v1 * b1;
D2 = v2 * b2;
force = -(F1+D1)+(F2+D2); // F1 negative = car jumps, F1 positive = car sticks



I suspect the problem is in L2 or tireDeflection...

##### Share on other sites

It would help if you describe what each of your variables represents. maxTravel? compression? hitDistance? Without knowing how you determine/define those, it's difficult to compare to the model. Can you describe how you're relating variables to my equations, for instance, D = x1 + x2, etc.?

Also, it hasn't been mentioned before, but you'll probably have to model the shock absorber, also. Without damping, you'll likely get oscillation. That is, if you deflect a spring and let it go, it'll bounce up-and-down forever. And damping is where your velocity will come into play. The shocks provide a resistive force proportional to velocity2. EDIT: It looks like you're applying it as proportional to v, rather than v2. And you're not checking the sign of the velocity. In general, the direction of the motion shouldn't come into play, only the magnitude - which would be taken care of with the square.

Also, ensure the signs of all your factors are correct.

force = -(F1+D1)+(F2+D2)

That's sort of confusing. One factor is negated, and the other is not. I suggest you check that you're equations are correct as they should both be applied similarly.

Edited by Buckeye

##### Share on other sites

maxTravel is the spring static length, 0.2 for example

rayLength is the total ray length, radius+maxTravel 0.3+0.2=0.5 etc.
compression is x1 in your code

tireDeflection is x2 in your code
hitDistance is the distance where ray has a contact, from suspension position to contact point(road) should be D in your code? Or should it be inverse (raylength-hitDistance)?

And I have dampers for both springs, D1 and D2 are the dampers, b1 and b2 are the damping coefficients.

v1 and v2 are the spring velocities.

The thing is that I can get one spring work just fine when I use inverted "D" (raylength-hitDistance) and positive spring rates, it works just fine with a single spring, but when I make it a double spring, it gets messed up tires jump around like they have 1000psi in them. If I lower the tire spring rate (k2) nothing changes, there is no "inflation" effect... I just get rid of the tire spring...

##### Share on other sites

hitDistance is the distance where ray has a contact, from suspension position to contact point(road) should be D in your code? Or should it be inverse (raylength-hitDistance)?

EDIT: D in my code is the distance from the top of the suspension spring to the bottom of the tire. I'm avoiding using your terms as I'm not sure what you mean by "suspension position."

            compression = (hitDistance - tireDeflection);

//x2
lastTireDeflection = tireDeflection;
tireDeflection = (k1*hitDistance - k1*R1 + k2*R2) / (k1+k2);

?? You're using tireDeflection in your compression equation before you calculate it.

Also, you've defined R2 = 0. Are you using R1 and R2 as the static lengths?

EDIT2:

v1 and v2 are the spring velocities.

..which, as you calculate them, may be negative or positive. Not good. Shock absorber resistance is proportional to the magniture of the square of the velocity, and is not dependent on the direction of travel.

EDIT3: It appears you're using the equations I posted without understanding the sequence. What I posted is not copy-and-paste - it's a derivation. Big difference.

Edited by Buckeye

##### Share on other sites

Sorry, by suspension position I mean the body contact position.

The tireDeflection was used before calculation because its in a loop and it doesnt make a huge difference in this case, the last frame will be used (the variables are globaly deffined)

R1 and R2 are static currently yes, should they be dynamic?

##### Share on other sites

Sorry, by suspension position I mean the body contact position.

I don't know what you mean by "body contact position" either, I'm afraid.

The tireDeflection was used before calculation because its in a loop and it doesnt make a huge difference in this case,

My mistake. I thought you were trying to implement the model I described.

R1 and R2 are static currently yes, should they be dynamic?

If they represent the static spring length and static tire radius, they should be constants.

##### Share on other sites

body contact position is the top of the spring.

I'm a terrible describer..

uhm I'm trying to implement the model you described, but in a loop.

And for some reason I dont seem to understand what Im doing wrong... I think I'm following the math you posted before + the page I posted(seems to have the same model), but with the adition of simple dampers.

As for R1 and R2, I made them constants in my code. R1 represents the resting position of the spring, so it's about half the actual spring length. As for R2, I dont know what to use here, seems like it's a radius offset...

But on the bright side, when I use this: L2 = tireDeflection - compression - R2;

L2 as tire stretching. There seems to be some inflation now, but its oposite... more tire spring rate = visually tire being empty... less tire spring rate the tire feels inflated.

##### Share on other sites

uhm I'm trying to implement the model you described, but in a loop.

As the loop code you posted appears to use the the tire deflection from the previous frame (i.e., the force due to the previous tire compression) to calculate the spring compression for the current frame, I'd have to think about the effects of that for a while. I'll leave that for another time.

Understand, I am not trying to get you to use any particular algorithm. I just don't have a clear idea of your algorithm or how you're trying to implement it.

As for R1 and R2, I made them constants in my code. R1 represents the resting position of the spring [EDIT: sounds good], so it's about half the actual spring length [EDIT: ??? you need to decide - is it the static spring length or not? I'm afraid I don't understand what a spring length=half spring length even means]. As for R2, I dont know what to use here, seems like it's a radius offset...

Pretty much my point. You need to decide what algorithm you want to implement, how you want to implement it, and what variables/constants in your code are the variables/constants in the algorithm. It pretty much appears as if you're hacking at it, trying to get something that "works." Your choice.

Edited by Buckeye

##### Share on other sites

Well, I wanted a logical solution, but while implementind it, everything went bad, so I began hacking it, wich Is bad...

Let me take a deeper look over it once again and if I cant get it to work, well let me start over from scratch then..

How are you calculating the stretching? In my case L1 and L2, as I understand L1 is

L1 = compression*R1 - (R2-tireDeflection)*tireDeflection;

Am I correct?

I'm out of ideas, here's my atempt at it:

public const float springLength = 0.2;	// Spring length (max travel)
public const float rimRadius = 0.28;	// This is the tire deflection limit, when this point is reached, no deflection takes place, because rim's are solid
public float springRestength = 0.1;

private RayCast ray;
private float rayLength;// total ray length (springLength+weelRadius) should be static but not sure...
private float hitDistance // The distance from the ray's origin to the impact point. (From top of the suspension to surface)
private float D;		// inverse distance (from surface to top of the suspension)
private float x1p,x2p;	// previous stretch position for velocity calcs...
private float x1,x2;	// stretch position (compression)
private float v1,v2;	// spring velocity
private float F1,F2;	// spring force
private float D1,D2;	// spring damper
private float L1,L2;	// how much is stretched (compression-restLength)

private float k1,k2;	// spring constant (springRate)
private float b1,b2;	// damping constant (friction)
private float R1,R2;	// rest length of springs

private float force;	// vertical force (suspension and tire stiffness)

init()
{
R1 = 0.0f;		// define the suspension spring resting position (usually half of the total spring length, can be used to adjust ride height etc...
R2 = 0.0f;		// what is this exactly?
k1 = 55000.0f;	// suspension spring rate
k2 = 11100.0f;	// tire spring rate
b1 = 2000f;		// suspension damper rate
b2 = 100.0f;	// tire damper rate
}

// In loop that is updated in a timestep(deltaTime) of 0.001 (1000hz)
loop()
{
// Cast down a ray from a position(suspensionBodyContactPosition) to detect contact and measure its distance (from top of the spring aka "body contact position" to surface contact point)
rayLength = springLength + wheelRadius;		// Static ray length
ray = CreateRayCast(rayLength,down,suspensionBodyContactPosition);
hitDistance = ray.hitDistance;				// Dynamic ray length

// inverse hit distance, because otherwise I get weird results...
D = rayLength - hitDistance;

// Tire Deflection
x2p = x2;
x2 = (k1*D - k1*R1 + k2*R2) / (k1+k2);

// Spring Compression
x1p = x1;
x1 = D - x2;

// Stretching
L1 = x1 - R1;
L2 = x2 - x1 - R2;

// Calculate spring forces
F1 = k1 * L1;
F2 = k2 * L2;

// Calculate spring velocity for dampers
v1 = (x1 - x1p) / deltaTime;
v2 = (x2 - x2p) / deltaTime;

// Calculate dampers
D1 = v1 * b1;
D2 = v2 * b2;

// Calculate final force
force = (F1+D1)+(F2+D2);

// Use one of the springs as wheel load...
}


##### Share on other sites

How are you calculating the stretching? In my case L1 and L2, as I understand L1 is

L1 = compression*R1 - (R2-tireDeflection)*tireDeflection;

Am I correct?

I'm not sure if it's correct because I'm not sure what you mean by calculating "stretching," what L1 and L2 are, etc. At this point in the discussion, I also don't know if compression and/or tireDelflection are from the current or previous frame, etc. Just a suggestion but:

decide what algorithm you want to implement, how you want to implement it, and what variables/constants in your code are the variables/constants in the algorithm.

##### Share on other sites

well I just want a double spring to work like this:

First spring is for suspension the other for the tire.
Suspension is simple, but tire is tricky (atleast for me)
I want the tire to have a rim radius (lets say 0.28)
and a total radius of 0.30 so the sidewall can deflect 0.02m  wich is 20mm at most (when the tire is under-inflated / low tire spring rate)

... this is all I want and I thought it would be a simple task, but it seems to be really tricky.

So far the algorythms seem to be more or likely the same.

This is the best page I've found about double springs:
http://www.myphysicslab.com/dbl_spring1.html

I use about the same model, the only thing I do differently is Velocity part.

My appologies for my stupidness but my brains are fried, been trying to crack this for 2 days now

Edit:

Unsure why, but using

L2 = tireDeflection*tireDeflection;

seems to work but should I concider this as a hack, because I dont know why should I use a square at this situation ???

Edit:

Meanwhile I drawed something, of what I would like to achieve:

##### Share on other sites

Hmm. Not sure about the rim radius or what you want to do with that. If you want to include the rim as a fixed distance from the center of the wheel to the bead of the tire, then you have x1 spaced correctly, but the spring is drawn to the bottom of the rim, not the center of the wheel (which is where it is on real vehicles.)

Variables S and R don't appear to have any use. I would suggest your physics model be something like the following. You have to define values for the static length of the spring, the radius of the rim, and the wall height of the tire. Those will be constant values. On the right below, this is the situation on the road: you can raycast to find the distance D from the chassis (top of the spring) to the ground. You know the rim radius (a constant). The unknowns are x1, the compressed length of the spring, and x2, the compressed wall height of the tire.

[attachment=21742:spring-and-tire_2.png]

1) D = x1 + rim + x2

The spring is compressed by a distance (L1 - x1). The tire is compressed by an amount (L2 - x2)

The forces at the center of the wheel:

2) k1 * (L1 - x1) = k2 * (L2 - x2)

Two equations and two unknowns (x1 and x2).

From 1):

3) x2 = D - x1 + rim

Substitute 3) in 2):

4) k1 * (L1 - x1) = k2 * (L2 - (D-x1+rim)) = k2 * (L2 - D + x1 - rim)

Collect terms:

5) -k1*x1 - k2*x1 = k2 *(L2 - D - rim) - k1*L1

Simplify:

6) x1 = ( k2 *(L2-D-rim) - k1*L1 ) / (-k1-k2) = -(k2*(L2-D-rim) - k1*L1) / (k1+k2)

Solve for x1 as all the terms on the right of the equation are known.

Once you've solved for x1, solve for x2 using 3)

EDIT: Be careful! (L1-x1) should really be | L1-x1 | throughout. That deltaX should always be positive - the same force whether the spring is compressed or stretched beyond it's static length. The derivation assumes a compression of both the spring and tire from there static lengths.

Edited by Buckeye

##### Share on other sites

Hmm, seems to be somewhat working, tho the tire spring can reach over wheel radius for some reason...

This is my code sofar, please note that the double spring model and single spring model are slightly different in velocity calulations aswell.


if(doubleSpring)
{
float D = rayLength - hitDistance; // Different compared to single spring!
L1 = maxTravel;

x1p = x1;
x1 = ( k2 *(L2-D-rimRadius) - k1*L1 ) / (-k1-k2);
x2p = x2;
x2 =  D - x1 + rimRadius;
compression = x1 - L2; // just pass the value for the visuals

F1 = k1 * (L1 - x1); // Different compared to single spring!
F2 = k2 * (L2 - x2);
v1 = (x1 - x1p) / deltaTime;
v2 = (x2 - x2p) / deltaTime;
D1 = v1 * b1;
D2 = v2 * b2;
force = (F1+D1)-(F2+D2);
}
else
{
float D = hitDistance - radius; // Different compared to double spring!
L1 = maxTravel;

x1p = x1;
x1 = L1 - D;
compression = x1; // just pass the value for the visuals

F1 = k1 * (x1); // Different compared to double spring!
v1 = (x1 - x1p) / deltaTime;
D1 = v1 * b1;
force = (F1+D1);
}


With double spring I get the effect, like the tire is expanding while driving over bumps

##### Share on other sites

the code is very convoluted and hard to follow and it doesn't make any sense tbh.

I think you are deluding yourself and you are just getting the wrong results out of this.

By having only the car body as simulated rigid body that's the only thing you can model. Simulating what you call a "double spring" simply means simulating a spring in serie, you can google and find the formulas for springs in series and in parallel... the code will look identical to a single spring, with different k and d.

But the point is that that is able to model the right behavior of this springs in serie system only for the forces and motion seen by your car body.

If you want to simulate the wheel movements, the only way is to have the wheels as rigid body as well.. with this connections body->spring->wheel->spring->ground.

You cannot extract the wheel movement from a system where the wheel is massless and not simulated at all.

##### Share on other sites

Thanks for explaining kunos. But I think I'm quite close, because on surface the behaviour is close to(if not the actual thing) what I'm after, thanks to Buckeye's explanations.

I made some changes to it in general and now it works quite good, but I think the code itself can be optimized.

Here's the code for doublespring aka 2 springs in series.
It may not be right, but it sure works right:

			bool doubleSpring = true;

if(doubleSpring)
{
float D = rayLength - hitDistance;
L1 = maxTravel;

x1p = x1;
x1 = ( k2 *(L2-D-rimRadius) - k1*L1 ) / (-k1-k2);

x2p = x2;
x2 =  D - x1 +rimRadius;

compression = D-x2 +L2; // for visuals

F1 = -k1 * (L1 - x1); // Different compared to single spring!
F2 = -k2 * (L2 - x2);
v1 = (x1 - x1p) / deltaTime;
v2 = (x2 - x2p) / deltaTime;
D1 = v1 * b1;
D2 = v2 * b2;
force = (F1+D1)+(F2+D2);
}
else
{
float D = hitDistance - radius;
L1 = maxTravel;

x1p = x1;
x1 = L1 - D;
compression = x1; // just pass the value for the visuals

F1 = k1 * (x1);
v1 = (x1 - x1p) / Time.deltaTime;
D1 = v1 * b1;
force = (F1+D1);
}


the code is basically the same as Buckeye sugested, but the "compression" is a little different and is only used for visuals

##### Share on other sites

Note that the algorithm I posted has a possibility of incorrect behavior. I wrote it for compression only, assuming that (L1-x1) would always be a positive value. That is, I didn't look at the possibility that the the spring/tire would be stretched. That could occur if the car goes airborne and the suspension stretches where D > sum of static lengths.

However, looks like you're getting something useable.

##### Share on other sites

This looks a lot like what you are looking for. It is in German, but the translator gives reasonable results. Maybe it is helpful:

http://www.cbcity.de/dynamik-eines-viertelfahrzeugs#more-976