0
\$\begingroup\$

I'm making a car simulation in Javascript and I am using this website to help me with the physics: http://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html

The current progress of the simulation can be seen on my website: https://cloudynet.tk/projects/car-sim/code.html

The problem I have is with the car steering physics. I have managed to get the low-speed steering to work correctly but the high-speed steering (where lateral forces are introduced) is very hard to get right. I understand how slip angles influence the lateral force but in my simulation, it is not working very well. I'm wondering if the implementation of the lateral force is correct or is there something wrong with the code? Also, I don't quite understand if the longitudinal force and the lateral force affects a single velocity vector or is separated into two "directional" vectors.

Here's my current physics function (whole code can be seen on the website):

applyPhysics() {
    // Get car direction vector

    let direction = new Vector(1, 0);
    direction = Vector.rotate(direction, this.carAngle);

    // LONGITUDINAL FORCES

    // Traction forces
    let tractionForce = direction.copy(); // Traction force (engine power)
    if (this.engineForce) {
        tractionForce.mult(this.engineForce);
    }
    else if (this.brakingForce) {
        tractionForce.mult(-this.brakingForce);
    }

    // Frictional forces

    let dragForce = this.velocity.copy(); // Air resistance force
    dragForce.mult(this.velocity.getMag())
    dragForce.mult(-this.drag);

    let rollingResistanceForce = this.velocity.copy(); // Rolling resistance force (friction with ground)
    rollingResistanceForce.mult(-this.rrDrag);

    let netLongitudinalForce = tractionForce.copy(); // Total longitudinal force
    netLongitudinalForce.add(dragForce)
    netLongitudinalForce.add(rollingResistanceForce);

    // Calculate acceleration
    this.acceleration = netLongitudinalForce.copy();
    this.acceleration.div(this.mass);
    if (this.acceleration.getMag() < 0.001)
        this.acceleration = new Vector();

    // Calculate velocity
    let accelerationDelta = this.acceleration.copy();
    accelerationDelta.mult(dt);
    this.velocity.add(accelerationDelta);

    this.velDir = this.velocity.getDir();
    this.sideslipAngle = this.carAngle - this.velDir; // Calculate side slip angle

    if (this.speed > 20) { // High speed-turning
        // LATERAL FORCES

        let peakSlipAngle = 5;

        // Calculate slip angle for back wheel
        var c = this.wheels.baseline/2;
        var omegaC = this.angularVelocity*c;
        var longV = Math.cos(this.carAngle) * this.velocity.getMag();
        var latV = Math.sin(this.carAngle) * this.velocity.getMag();
        this.wheels.back.slipAngle = Math.atan(((latV - omegaC)/Math.abs(longV)) || 0);
        var backSlipDeg = deg(this.wheels.back.slipAngle)

        this.wheels.back.lateralForce = 5000*Math.sign(this.wheels.back.slipAngle);
        if (backSlipDeg < peakSlipAngle && backSlipDeg > -peakSlipAngle) {
            this.wheels.back.lateralForce = 5000*backSlipDeg/peakSlipAngle;
        } else {
            this.wheels.back.lateralForce = 5000*(1-((Math.abs(backSlipDeg)-peakSlipAngle)/500))*Math.sign(this.wheels.back.slipAngle);
        }

        // Calculate slip angle for front wheel
        var b = this.wheels.baseline/2;
        var omegaB = this.angularVelocity*b;
        var longV = Math.cos(this.wheels.front.slipAngle) * this.velocity.getMag();
        var latV = Math.sin(this.wheels.front.slipAngle) * this.velocity.getMag();
        this.wheels.front.slipAngle = Math.atan((((latV - omegaB)/Math.abs(longV)) || 0)-this.steeringAngle*Math.sign(longV));
        var frontSlipDeg = deg(this.wheels.front.slipAngle);

        this.wheels.front.lateralForce = 5000*Math.sign(this.wheels.front.slipAngle);
        if (frontSlipDeg < peakSlipAngle && frontSlipDeg > -peakSlipAngle) {
            this.wheels.front.lateralForce = 5000*frontSlipDeg/peakSlipAngle;
        } else {
            this.wheels.front.lateralForce = 5000*(1-((Math.abs(frontSlipDeg)-peakSlipAngle)/500))*Math.sign(this.wheels.front.slipAngle);
        }

        // Calculate cornering force
        this.corneringForce = this.wheels.back.lateralForce + Math.cos(this.steeringAngle) * this.wheels.front.lateralForce;

        // Calculate centripetal force
        this.centripetalForce = this.mass * (this.velocity.getMag() ** 2) / this.wheels.baseline/Math.sin(this.steeringAngle);

        var lateralDirection = new Vector(0, -1);
        lateralDirection = Vector.rotate(lateralDirection, this.carAngle);

        let lateralForce = lateralDirection.copy();
        lateralForce.mult(this.corneringForce);

        this.latAcceleration = lateralForce.copy();
        this.latAcceleration.div(this.mass);
        if (this.latAcceleration.getMag() < 0.001)
            this.latAcceleration = new Vector();

        let latAccelerationDelta = this.latAcceleration.copy();
        latAccelerationDelta.mult(dt);
        this.latVelocity.add(latAccelerationDelta);

        // Calculate position
        let latVelocityDelta = this.latVelocity.copy();
        latVelocityDelta.mult(dt);
        this.pos.add(latVelocityDelta);
    } else {
        this.velocity = Vector.rotate(this.velocity, this.carAngle - this.velDir); // Correct velocity based on car orientation
    }

    // Calculate position
    let velocityDelta = this.velocity.copy();
    velocityDelta.mult(dt);
    this.pos.add(velocityDelta);

    // Calculate speed
    this.speed = this.velocity.getMag();
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.