Tuesday, October 1, 2019

ai - Target Tracking: When to accelerate and decelerate a rotating turret?


Say I have a moving circular target defined as:


Vector2 position;
Vector2 velocity;
float radius;


And a rotating turret (mounted on a moving vehicle of some kind) defined as:


Vector2 position;
Vector2 velocity;
float angle; // radians
float angularVelocity; // radians per second
const float maxAngularVelocity; // radians per second
const float maxAngularAcceleration; // radians per second per second

(Or something along those lines. Note that position and velocity of both are controlled elsewhere - assume velocity is constant and position changes based on velocity.)


I am trying to write two related AI functions to determine, on a given frame:





  • What angular acceleration (and in which direction) to apply to the turret's angle to keep the turret pointing at the target?




  • If the target is currently in sight, can it (any part within its radius) be kept in sight for x seconds, where x is a fraction of a second? (Alternatly: is there another strategy to ensure the target is actually "locked on" and not simply flying across the sights?)




And I could use some help...



Answer




First you need to determine the difference in angle between the turret facing direction and the direction to the target.


Vector2 turretToTarget = target.position - turret.position;
float desiredAngle = atan2(turretToTarget.y, turretToTarget.x);
float angleDiff = desiredAngle - turret.angle;

// Normalize angle to [-PI,PI] range. This ensures that the turret
// turns the shortest way.
while (angleDiff < -PI) angleDiff += 2*PI;
while (angleDiff >= PI) angleDiff -= 2*PI;


Once you have these quantities you can set up a second degree expression for the turret angle. You need to compute this on each update to make sure you always use the latest data of positions and velocities.


// Compute angular acceleration.
const float C0 = // Must be determined.
const float C1 = // Must be determined.
float angularAcc = C0 * angleDiff - C1 * turret.angularVelocity;

Here, the first term (zero degree) in the acceleration expression will cause the turret to begin turning towards the target. However it will not stop in time but rather oscillate back and forth over it. To make it stop we need the dampening second term (first degree) which causes a high turning velocity to be opposed by a high acceleration.


Now the positive constants (not necessarily program constants) need to be determined and balanced to make the system behave well. C0 is the major control for the speed of the system. A high value for C0 will give a fast turning speed and a low value will give a low turning speed. The actual value depends on many factors so you should use trial and error here. C1 controls the damping magnitude. The discriminant of the quadratic equation tells us that if C1*C1 - 4*C0 >= 0 we have a non-oscillating system.


// New definition.
const float C1 = 2*sqrt(C0); // Stabilizes the system.


You probably should choose C1 a little bigger than this for numerical reasons, but not too big because it may get very over-damped and slow to respond instead. Again, you need to tweak.


Also it is important to note that this code only computes the angular acceleration. The angle and angular velocity needs to be updated from this somewhere else, using and integrator of some sort. From the question I assume that this has been covered.


Finally there is something to say about lagging, because the turret will probably always be behind when tracking a fast target. A simple way to tackle this is to add a linear prediction to the target's position, i.e. always aim slightly ahead in the target's forward direction.


// Improvement of the first lines above.
const float predictionTime = 1; // One second prediction, you need to experiment.
Vector2 turretToTarget = target.position + predictionTime * target.velocity - turret.position;
/// ...

As for keeping the turret aimed within the radius of the target for some time, this may be a tough requirement to impose directly on this sort of system. You can be certain that this controller will strive to keep the turret aimed at the target (or rather the predicted position) at all times. If the result turns out not to be satisfactory you have to modify the parameters predictionTime, C0 and C1 (within stable bounds).



No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...