# Tank movement based on track speeds

I want a system, where a tank moves and rotates based on the speeds I give him for the two tracks, for example, if I give the left track a speed of 1 and the right one a speed of -1, then I want the tank to stay still and rotate right, while if I give the left track 1 and the right track -0.5, I want it to rotate, but at the same time move forward

Of course the speeds will be between -1 and 1

• Average the speeds to get forward speed, take difference and divide by tank radius to get the angular velocity? – avl_sweden Feb 21 '17 at 17:56

Disclaimer: this is based on intuition only, and there's definitely a missing piece for it to be mathematically exact. However, as far as I can tell, it should be a good enough approximation for small displacement values.

The idea is that the center of each tread describes a perfect motion, without skidding. Let's draw a diagram:

O is your tank's origin, L and R are the treads' centers. Then you'd perform as follows:

• L and R are found by taking the left and right orthogonal rotations of your direction vector d, and adding them to the origin;
• L' and R' are found by applying the two lateral speeds to L and R WRT the direction vector.
i.e. L' = L + speed(L) x d and R' = R + speed(R) x d;
• O' is the middle of [L'R'], i.e. (L' + R') / 2;
• The new direction vector is orthogonal to [L'R'].

The approximation comes from the fact that L'R' > LR, that is, the tank actually stretches slightly when turning. Fixing that would require more advanced tools (some sort of curved vector ? I have no clue :p). However, as long as the speeds for each frame remain relatively small, this should be good enough.

The following example code shows a simple way to move a tank around realistically. It animates a 2D tank from a bird's eye view, but the calculations are the same in any case.

It assumes you have created a sprite named tank, and that you have centred its origin. There are some general notes after the code.

const hone = function(current, target) {

// This helper takes current and target speeds, and returns
// the value that the current speed should update to next.

return current - Math.sign(current - target) / 100;
};

let speed, differential; // the tank speed and track differential

// The user can only set the *target* speed of a track. The actual
// track will usually take some time to reach that speed:

let leftSpeed = 0;  // the actual speed of the left track
let rightSpeed = 0; // the actual speed of the right track
let leftTargetSpeed = 0;  // the target speed of the left track
let rightTargetSpeed = 0; // the target speed of the right track

engine.update = function() {

// Update the target speeds, then update the actual speeds:

[leftTargetSpeed, rightTargetSpeed] = ui.levers.getState();
leftSpeed = hone(leftSpeed, leftTargetSpeed);
rightSpeed = hone(rightSpeed, rightTargetSpeed);

// Calculate the speed and differential:

speed = (leftSpeed + rightSpeed) / 2;
differential = leftSpeed - rightSpeed;

// Then the magic happens...

tank.rotation += differential;
tank.position.x += Math.cos(tank.rotation) * speed;
tank.position.y += Math.sin(tank.rotation) * speed;
};

• The engine.update function will be invoked on every animation frame.
• The ui.levers.getState method returns a list of two floats (each between -1 and 1), representing the state of two levers that the user pushes and pulls to control each track.
• In practice, you'll need to multiply or divide some values, else your tank will drive too fast, or spin too slowly or something.

Have a vector for each wheel and then calculate the cross product for the direction the tank should be facing with the result of cross(leftWheel, rightWheel);

• You can't use cross on 2d vectors... – Bálint Feb 20 '17 at 8:44