How can I implement a stiff spring for modelling vehicle suspension?

Mar 16, 2011 at 7:33 AM

Short version: How can I implement a stiff spring for modelling vehicle suspension?

Hi, I am trying to emulate a vehicle's suspension using Farseer Physics 3.

I have a rectangle fixture representing the chassis and two circle fixtures representing the wheels. I have two bodies rearAxle and frontAxle positioned in the center of the wheels. I have a revolute joint connecting each axle to each wheel, and two prismatic joints connecting each axle to the chassis.

 

            _chassis = FixtureFactory.CreateRectangle(_world, 6f, 1.5f, _chassisDensity, _chassisCenter);
            _chassis.Body.IsStatic = false;
            _chassis.CollisionFilter.CollisionGroup = 1;

            _rearWheel = FixtureFactory.CreateCircle(_world, _wheelRadius, _wheelDensity, _chassisCenter + new Vector2(-_wheelHorizontalDisplacement, -_wheelVerticalDisplacement));
            _rearWheel.Body.IsStatic = false;
            _rearWheel.CollisionFilter.CollisionGroup = 1;

            _frontWheel = FixtureFactory.CreateCircle(_world, _wheelRadius, _wheelDensity, _chassisCenter + new Vector2(_wheelHorizontalDisplacement, -_wheelVerticalDisplacement));
            _frontWheel.Body.IsStatic = false;
            _frontWheel.CollisionFilter.CollisionGroup = 1;

            _rearAxle = BodyFactory.CreateBody(_world, _rearWheel.Body.Position);
            _rearAxle.IsStatic = false;

            _frontAxle = BodyFactory.CreateBody(_world, _frontWheel.Body.Position);
            _frontAxle.IsStatic = false;

            _rearAxleJoint = JointFactory.CreateRevoluteJoint(_world, _rearWheel.Body, _rearAxle, Vector2.Zero);

            _frontAxleJoint = JointFactory.CreateRevoluteJoint(_world, _frontWheel.Body, _frontAxle, Vector2.Zero);
            
            Vector2 rearChassisSuspensionPoint = new Vector2(_chassisCenter.X - _wheelHorizontalDisplacement, _chassisCenter.Y);
            _rearSuspension = JointFactory.CreatePrismaticJoint(_world, _rearAxle, _chassis.Body, new Vector2(-_wheelHorizontalDisplacement, 0), (rearChassisSuspensionPoint - _rearAxle.Position).NormalizeR());
            _rearSuspension.LimitEnabled = true;
            _rearSuspension.LowerLimit = _suspensionLowerLimit;
            _rearSuspension.UpperLimit = _suspensionUpperLimit;
            _rearSuspension.MotorEnabled = true;
            _rearSuspension.MaxMotorForce = _suspensionMaxMotorForce;
            _rearSuspension.MotorSpeed = _suspensionSpeed;

            Vector2 frontChassisSuspensionPoint = new Vector2(_chassisCenter.X + _wheelHorizontalDisplacement, _chassisCenter.Y);
            _frontSuspension = JointFactory.CreatePrismaticJoint(_world, _frontAxle, _chassis.Body, new Vector2(_wheelHorizontalDisplacement, 0), (frontChassisSuspensionPoint - _frontAxle.Position).NormalizeR());
            _frontSuspension.LimitEnabled = true;
            _frontSuspension.LowerLimit = _suspensionLowerLimit;
            _frontSuspension.UpperLimit = _suspensionUpperLimit;
            _frontSuspension.MotorEnabled = true;
            _frontSuspension.MaxMotorForce = _suspensionMaxMotorForce;
            _frontSuspension.MotorSpeed = _suspensionSpeed;

 

My first thought was to model the suspension by adjusting the speed of the prismatic joint motor according to the absolute translation of the joint:

 

            _rearSuspension.MotorSpeed = Math.Abs(_rearSuspension.JointTranslation);
            _frontSuspension.MotorSpeed = Math.Abs(_frontSuspension.JointTranslation);

 

However I found out that my assumption that the prismatic joint motor attempts to drive joint translation to 0 was false, and instead the prismatic joint motor just drives the joint translation upwards.

I'm now stuck for ideas: There doesn't seem to be any springs in Farseer Physics 3, however there are springs in previous versions.

How can I implement a stiff spring for modelling vehicle suspension?

Mar 16, 2011 at 7:58 AM
Edited Mar 16, 2011 at 8:22 AM

I have come up with another solution to model the suspension. In addition to the prismatic joints, I created two DistanceJoints, connecting the chassis to each axle, and set the damping and frequency properties.

However this solution is still sub-optimal. You can imagine this by lifting the car up and having very heavy wheels - with a spring, the wheels would be stretched down below, but with the DistanceJoint approach the wheels oscillate and the return to the resting position.

So my initial question is still valid. Thanks.

 

Edit: I needed to keep playing with the damping and frequency, it seems to be working like a spring now. Consider this question solved. Thanks.

Mar 18, 2011 at 3:50 AM

James,

 

I'm curious to how you solved your suspension problem.  I am making a dirt bike game and am running into a similar problem with the suspension.  I first tried a prismatic joint but I couldn't get it to be anywhere close to what I needed.  I eventually settled with the solution posted below but it's less than optimal.  There seems to be a lot of bounce in the suspension (almost like the shocks are worn out but the spring is still good on a car if you've ever experienced that).

 

            DistanceJoint FrontSuspension1 = new DistanceJoint(compund[0].Body, FrontHub.Body, new Vector2(2f, -2.4f), new Vector2(0, 0));
            FrontSuspension1.DampingRatio = 1f;
            FrontSuspension1.Frequency = 10f;
            FrontSuspension1.Length = 1.8f;
            DistanceJoint FrontSuspension2 = new DistanceJoint(compund[0].Body, FrontHub.Body, new Vector2(6f, -2.4f), new Vector2(0, 0));
            FrontSuspension2.DampingRatio = 1f;
            FrontSuspension2.Frequency = 10f;
            FrontSuspension2.Length = 1.8f;

 

In the above code the compound is the list of fixtures containing my chassis and the FrontHub is the center of the front wheel.  What this does it put two distance joints 4 meters apart horizontally with the wheel in the middle.  It allows a lot of travel vertically and very little horizontally.

I'd love to know if someone else has a better solution.  I was looking at this thread in the Box2D forums but it doesn't seem like that functionality is replicated in Farseer:

http://www.box2d.org/forum/viewtopic.php?f=8&t=1669&p=11404

 

 

Mar 18, 2011 at 4:45 AM

Have you guys looked at the Car Sample in the latest builds?  It uses Line Joints for the car's suspension.  I had also tried to use prismatic joints with axels and revolute joints...could never get the suspension to work correctly.  The line joints work great.

Mar 18, 2011 at 5:25 AM

Hi winnerct,

I used two prismatic joints with the limit enabled (but not the motor enabled), to set the absolute max distance the chassis could travel from the wheels, and to constrain the wheel to the angle I wanted.

Then I used two distance joints to add the springiness by playing with the dampingratio and the frequency properties. I've been playing with all the properties for a while now, its very hard to get an acceptable car!