Space Game Throttle Control (PID Controller)

As part of AI control for AI dogfighting I want to implement some kind of throttle control.
The general idea is:

  • The AI should have a desired attack range (let’s call it MinAttackRange and MaxAttackRange)

  • When the distance to the target is in between MinAttackRange and MaxAttackRange, match speed with target

  • When distance is smaller than MinAttackRange, slow down

  • When distance is bigger than MaxAttackRange, speed up

  • The throttle is controlled by values between 0.0f and 1.0f

I have taken the general idea for an PID controller from PID process control, a “Cruise Control” example - CodeProject

            // calculate the difference between
            // the desired value and the actual value
            error = desiredSpeed - currentSpeed;
            // track error over time, scaled to the timer interval
            integral = integral + (error * Dt);
            // determine the amount of change from the last time checked
            derivative = (error - preError) / Dt;
            // calculate how much to drive the output in order to get to the
            // desired setpoint.
            output = (Kp * error) + (Ki * integral) + (Kd * derivative);
            // remember the error for the next time around.
            preError = error;

So my overall idea is

  • decide what speed is desired by rules above (I think for the start hardcoding some kludge values TargetSpeed +/- Constant for SpeedUp/SlowDown will do)
  • calculate the error by using this desiredSpeed and the currentSpeed of the AI controlled vehicle
  • calculate the rest as in pseudo code sample above

Sticking points:

  • I think my problem is that the code sample operates on speed, not on throttle values? How do I get throttle values if I do not know what throttle value represents what speed?
  • If I get this to work, what to do with the actual closing velocity? Currently I am assuming the AI vehicle is directly behind and facing the target, which will seldom be the case in the actual game. What to do about that? Simply ignore to get a good enough solution?

PS: hope this is the right forum, it is kind of between game design and scripting, I think

So you’ve got a loop that is going to produce the answer to the question “Where should my throttle be?”

Here’s something from a project I was fooling around with, using the physics engine for movement.

    private void CalculateLinearForces()
    {
        // Now calculate forces acting on the aeroplane:
        // we accumulate forces into this variable:
        var forces = Vector3.zero;
        var forwardForce = CalculateForwardThrust();
        var lateralForce = CalculateLateralThrust();
        //Add the forward thrust
        forces += forwardForce;

        //Add the strafe thrusters
        forces += lateralForce;

        m_Rigidbody.AddForce(forces, ForceMode.Impulse); //This does the actual pushing.
        if (InertialBrakes)
        {
            DampInertia(forwardForce + lateralForce);
        }
    }

    private Vector3 CalculateForwardThrust()
    {
        Vector3 forwardThrust = Vector3.zero;
        forwardThrust += EnginePower * transform.forward; //Engine power is Throttle * MaxEnginePower
        return forwardThrust;
    }

ForceMode.Impulse Reference

Your speed is going to be rigidbody.Velocity.magnitude - you can predict what your speed is going to be after applying force by doing velocity = force/mass * time - of course unless time is constant you’ll have some error there, but it shouldn’t be enough to matter.

Hope that helps somewhat. -Luke

I don’t think it can be that difficult, basically it is like a cruise control for a car, and I don’t think especially older models could predict the speed of a certain throttle value (factoring in going uphill/downhill, friction, wind, current gear… some of them unknown to the controller I would guess).

So how does a cruise control control the throttle?
My guess is it knows

  • current speed
  • desired speed
  • current throttle position (0 to 1)

Output should be another throttle position.
I am currently thinking the “magic” lies in the PID coefficients.
For simplicity I will ignore the ID part and try a simple P controller (as far as I understand it the ID part is for getting better results closer to the target value and could be ignored if a value close enough to the target is ok, like 45 or 55 in this case, just to throw some numbers around).
So lets say current throttle value is 0.5, current speed is 30mph, desired speed is 50mph.
This gives an error of 20mph. So with a Kp = 0.05 I would get:

  • iteration: error 20, 0.05 * 20 = 1 throttle
  • iteration: error 10 (arbitrary number), 0.05 * 10 = 0.5 throttle
  • iteration error 0, 0.05 * 0 = 0 throttle

But that 0 can’t be right, since to maintain 50mph the throttle has to be > 0 (let’s say 0.6)

It should be a fairly simple problem, but I just can’t get my head around it.

EDIT: do I have to interpret the output as an absolute value or a change to the current value?