# Dynamic thruster balancing of space ship

The space ships in my game a meant to be player-built with an arbitrary amount of thrusters attached anywhere with any rotation. I currently have some dirty code to rotate the ship to a given angle (accelerating and decelerating).

Here's an example of a symmetrical ship facing where the red line points, being told to rotate left.

However, as you would imagine, depending on where the player has put the thrusters, sometimes undesired linear forces are affecting the ship. In this case, the ship starts moving forward.

I'm elaborating on whether it's possible to find the maximum thrust a thruster can apply to cause no linear velocity. (In the above case that would be none since there's nothing to counteract the forces from the rear thrusters, and the front ones kill eachother).

What I've come up with so far is a formula to determinate the "turn efficiency" e.g. how much rotation is caused in relation to linear movement.

a - position vector to thruster a b - position vector to thruster b v1 - force from thruster a v2 - force from thruster b

efficiencyDelta = a.cross(v1) / |v1| - ( a.cross(v1) + b.cross(v2) ) / |v1 + v2|

, basically "a.cross(v1 * t) / |v1|" is supposed to be the turn efficiency. And then we subtract it by the turn efficiency of the thrusters combined, to see if firing the new thruster is worth it.

Problem arises when I realize that thrusters aren't surposed to be on/off, but can vary their thrust from 0 to 1. And how to go about when the player wants the ship to go forward. Ofcourse, there would need to be a balance of how much to rotate/move.

I'm no rocket scientist so I'm hoping there's someone who can tell me if it's even possible to calculate the throttle of each thruster this way and give me a push in the right direction.

Thank you for taking the time! / Kim

• I started on the same path, but with many configurations, it's impossible to both rotate and not translate. So do you take away rotation? Or do you allow translation? Ultimately, it's up to the user designing the ship. For my demo of this, I faked it. Related: gamedev.stackexchange.com/questions/58216/…, gamedev.stackexchange.com/questions/40615/… – MichaelHouse May 10 '14 at 14:47
• I went down a similar path and ended up writing a demo on this page. As you move the thrusters around (drag them on the ship to set position and power) it draws three shapes. The intuition is that you can think of all possible movements as a point in 3d space (x, y, rotation), and being limited to 0-1 is a constraint in that space. So you end up with a 3d shape containing all possible movements. If you want no linear velocity you're looking at the (x=0,y=0) line in that space (Q,W,E,S all 0 in my demo) – amitp May 16 '14 at 16:37

I will assume that you have physically correct motion for your ship, as otherwise this analysis will not hold. You need something stronger than efficiency to solve this problem properly.

Each thruster will produce two effects on the motion of the ship: linear and angular. These can be considered independently. If the thruster produces a force f in a direction dir, and is offset from the center of mass by a vector r (not geometric center or the center of the sprite!), then the effect on the linear component is:

t = f * dir // f is a scalar, dir is unit length


The effect on angular velocity is given by the torque:

tau = f * <dir.x, dir.y, 0> CROSS <r.x, r.y, 0> // cross product


t is an force vector (i.e. the linear thrust). tau is a signed scalar which, when divided by the mass moment of inertia, will give the angular acceleration. It is important that dir and r are both in the same coordinate space, i.e. both in local coordinates or both in world coordinates.

The overall linear acceleration of the ship is given by the sum of the t's for each thruster divided by the ship's mass. Similarly, the angular acceleration is just the sum of the torques divided by the mass moment of inertia (which is another scalar). The ship will not turn if the total torque is zero. Similarly, it will not move if the total thrust is zero. Recall torque is a scalar but thrust (the sum of the t's) is a 2D vector.

The point of this exposition is that now we can write our problem as a Linear Program. Say first we want our ship to turn without moving. We have a variable for each thruster, $x_1, x_2, ...$, which is the amount of thrust that thruster will provide. One set of constraints is:

0 <= x_i < fmax_i  //for each i


where fmax is the maximum force for that thruster (this lets us have stronger or weaker ones). Next, we say that both equalities:

0 = Sum_i  x_i * dir_i.x
0 = Sum_i  x_i * dir_i.y


This encodes the constraint that we will not apply a linear acceleration, by saying the total thrust is zero (thrust is a vector, so we just say each part is zero).

Now we want our ship to turn. Presumably we want to do so as quickly as possible, so we want to:

max (Sum_i  x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0>


Solving for the x_i's while satisfying the inequalities and equalities above, while maximizing the summation above, will give us the desired thrust. Most programming languages have a LP library available for them. Just put the above problem into it and it will produce your answer.

A similar problem will let us move without turning. Say we re-write our problem in a coordinate system in which we want to move in the positive x direction. Then the constraints are:

0 <= x_i < fmax_i  //for each i
max Sum_i  x_i * dir_i.x
0 = Sum_i  x_i * dir_i.y
0 = (Sum_i  x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0> // as before


With the constraint that the thrusters can only produce thrust in a single direction, there are going to be limits to the kind of rotations and linear velocities that you will be able to achieve. This will manifest as the solution being 0 = x_1 = x_2 = ... = x_n, which means you won't ever get anywhere. To mitigate this, I suggest adding a pair of small, weak (say 5%, or 10%) thrusters for each player placed thruster at 45-degrees on either side. This will give the solution more flexibility, because these can be used to counteract weak secondary effects of the main thrusters.

Finally, for up through maybe 100 thrusters, the solution to the LP is fast enough to be done per frame. However, because the solution does not depend on location or the current state, you can precompute the solution for each reasonable controller input combination whenever the shape changes (this includes adding non-thrusters which change the moment of inertia or the mass of the ship, because then the thrusters are in a different location relative to the center of mass!). This is 24 possibilities (i.e. 8 directions times {left spin, no rotation, right spin}).

• Very well explained! – Kim Jun 10 '14 at 22:01
• What does Sum_i mean in this context? – S. Tarık Çetin Aug 5 '17 at 18:02

My first thought was a purely empirical solution, that is simulate the rig in a sandbox environment for varying degrees of thrust to work out how it behaves. Instead of balancing a lot of complex math in the search for a deterministic solution you can reach it numerically for example using newtons's method. Example:

Range for thrust is 0 to 1000 where 1000 is ALOT.

Step #1

Simulate with trust (0+1000)/2=500. Result: too much trust

Step #2

Range is now 0 to 500 Simulate with trust (0+500)/2=250. Result: too much trust

Step #3

Range is now 0 to 250 Simulate with trust (0+250)/2=125 Result: too little trust

Step #4

Range is now 125 to 250 Simulate with trust (125+250)/2=187.5 Result too much trust

Step #5 Range is now 125 to 187.5 Simulate with trust (125+187.5)/2=156.25 Result is too little trust

Step #6 Range is now 156.25 to 187.5 Range is below threshold of 35 which means that it is a good enough estimate

Final result= (187.5+156.25)/2 = 171.875