Of No Particular Significance

There was supposed to be something here but you get a dinosaur I drew instead.

You might be here because you're wondering about me. Without elucidating too much: I've been in a really dark place for a while and will be unreachable likely indefinitely, or at least until I can rid myself of this mindset.

Alfred – “Took quite a fall, didn't we, Master Bruce?”
Thomas Wayne – “And why do we fall, Bruce? So we can learn to pick ourselves up.”

Friday, October 1, 2010

Missile Trajectories Using PID Control

Proportional-Integral-Derivative control sound unfamiliar? Unless you're an engineer I'd assume so. It's basically a way to give instructions to a system with feedback. For example, whenever I have cereal for breakfast in the morning I'm a living PID controller. I try to regulate the ratio of cereal to milk in the bowl so I never have solely cereal or milk left over (this is normal right?). I set my spoonful contents to contain a particular Cereal-Milk ratio (say 80% milk 20% cereal). After each bite I visually measure the remaining overall ratio and adjust the cereal concentration in my next spoonful based on the perceived error my last mouthful caused. I think my example is awesome but you can get a more in depth look on the PID Control wiki page.

private const Kp:Number = 0.033;
private const Ki:Number = 0.0165;
private const Kd:Number = 0.0165;
/**
* Returns a new control variable based on the setPoint and current processVariable 
* using a PID Controller. 
* @param    setPoint - The target point for the process. (i.e. 80% milk 20% cereal) 
* @param    processVariable - The current input to control the process. (current spoonful's ratio) 
* @returns  The new input to the process. (next spoonful's ratio) 
*/
var integral:Number = 0;
var lastError:Number = 0;
private function PIDControl(setPoint:Number, processVariable:Number):Number 
{
    var error:Number = setPoint - processVariable; 
    var manipulatedVariable:Number = 0;  // Time Step is 1 frame. 
    integral += error;
    var derivative:Number = error - lastError;
    manipulatedVariable = Kp*error + Ki*integral + Kd*derivative; 
    lastError = error;
    return manipulatedVariable;
}

The reason I'm posting about this is because I'm using PID control in my Asteroids remake to guide seeking missiles to enemy targets. Try the demo below to see it in action.

Note: This is a custom build of code from several months back.
I've had some difficulty migrating the PID code to the current version in which I'm using a much better physics engine.
Arrow keys to move, Spacebar to shoot.

The Process Variable in this application is the distance from the estimated nearest approach location (the empty green circles) to the predicted place where where the asteroid and missile will collide (the filled red circle). The Manipulated Variable is the change in heading (i.e. how much to turn left or right) of the missile. The regular method first finds the asteroid which requires the smallest deviation from its current path. It then turns the missile to this asteroid (n.b. both missiles have turn angle constraint).

Visualization of PID Control (from a single trial)


The 'Smart' PID controlled method is much more effective compared to 'Regular' method and also makes for interesting trajectories!

1 comment: