13

Does anyone have an example of implementing Orbital Mechanics (preferably in XNA)? The code I am currently using is below, but it doesn't "feel right" when it executes. The object just bends ever so slightly to the planet, and no matter how much I tweak the variables I cant get it to enter an orbit, or even a partial orbit.

shot.Position += shot.Velocity;  

foreach (Sprite planet in planets)  
{  
  Vector2 directionToPlanet = (planet.Position - shot.Position);  
  directionToPlanet.Normalize();  

  float distance = Vector2.DistanceSquared(shot.Position, planet.Position);  

  float gPull = (float)(planet.gravityStrength * (planet.Mass * shot.Mass) / distance) + planet.gravityField;  
  shot.Position += new Vector2(directionToPlanet.X * gPull, directionToPlanet.Y * gPull);  
} 

Edit Marking Mendelt's answer correct for pointing out that I need to update the velocity, not the position. I also needed to change the calculation of gPull to

float gPull = shot.Mass * planet.Mass / distanceSqr * planet.gStr;
Svante
  • 50,694
  • 11
  • 78
  • 122
  • About your edit: The coefficient for gPull should be the same for all masses (that is gPull = G * mass1 * mass2 / distance^2). If planet.gStr is the surface gravity of the planet, then it is *not* what you want! Here G is constant: G = 6.6e-11 m^3/kg/s^2 (in Si units) – dmckee --- ex-moderator kitten Mar 17 '09 at 21:28
  • @dmckee Yeah, but I wanted different planets to have a stronger/weaker pull on the object –  Jan 09 '13 at 16:38

5 Answers5

10

In the last line you're updating the position of the shot. You should be updating the velocity.

You might want to take a look at the code in this blogpost http://blog.mendeltsiebenga.com/post/Fun-with-planets.aspx No xna, but working orbital mechanics. (although i never got rid of the screen-flicker)

Mendelt
  • 36,795
  • 6
  • 74
  • 97
8

Newton-Raphson iteration is not a stable way to solve this problem (that is you can't get it right using so simple an integrator for the differential equation). Consider using a second (or higher) order solution: Runge-Kutta is good and is fairly easy to implement in this case.

From the point of view of numeric analysis, the problem of orbital mechanics reduces to that of solving the set of coupled differential equations:

x_i'' + G m_i \sum_{i != j} m_j r_ji/(|r_ji|)^3 = 0

where the x's are three-vectors representing the positions of the bodies, the m's are the masses of the same bodies, and r_ji = x_j - x_i is the vector displacement between bodies j and i.

dmckee --- ex-moderator kitten
  • 98,632
  • 24
  • 142
  • 234
  • True, but you can get a few orbits to happen without resorting to Runge-Kutta. It just won't stay in the same orbit as long as it would in the real world, as the errors accumulate rapidly. – Daniel Earwicker Mar 17 '09 at 21:27
  • @Earwiker: Yep. It's been a long time, but seem to recall my NR orbit simulator accumulating an radial error of a few percent per orbit. But it also breaks the conservation of energy and angular momentum. Us physics types find that *very* frustrating... – dmckee --- ex-moderator kitten Mar 17 '09 at 21:30
  • Oh I know, I'm a physics type myself! :) – Daniel Earwicker Mar 18 '09 at 01:16
  • Of course, a gradually changing orbit doesn't necessarily break conservation laws in the real world - for example, the Moon is much further away from the Earth than it was a few billion years ago (due to tidal effects rather than approximate integration). – Daniel Earwicker Mar 18 '09 at 01:21
  • Yeah, in the Earth-Moon case, the energy and angular momentum come from the Earth's spin. No problem there. – dmckee --- ex-moderator kitten Mar 18 '09 at 01:30
  • Runge-Kutta actually is not a consistent method either. It seems perfect, but upon deeper analysis you can show that it doesn't conserve fundamental quantities that much simpler codes will conserve if you simply use finer time/resolution steps. That being said, for most purpose it is a great choice. – Alex Aug 14 '09 at 20:51
  • @Alex: Correct, but the problem is pushed back by a couple of terms. – dmckee --- ex-moderator kitten Aug 14 '09 at 21:38
  • The leap-frog method I mention in another answer resolves the energy conservation problem. The phase (the position -along- the orbit) will gradually accumulate error, but the energy remains constant indefinitely. – James Apr 10 '13 at 21:49
5

The "leap frog" method is very efficient and stable, and works well for any dynamic particle/field system, including plasmas. For gravity, it's simple. Here is all you do for a single iteration on a single planet (1-body problem, single planet around stationary sun):

    public void Push()
    {
        Position += Gravity.dT * Velocity;
        Velocity += Gravity.dT * GravityAccelerationVector(Position);
    }

Where "Gravity.dT" is a uniform time step, in an arbitrary measure of time. I'm using System.Windows.Vector, but any custom Vector class will do, as long as it supports basic multiplication and addition. The trick is that the Position and Velocity aren't at the "same time", which is very common for most integration methods. Rather, they're staggered. The Position on iteration N is updated based on the Velocity from iteration N - 1/2, but then the Velocity at iteration N+1/2 is updated based on the Position at iteration N.

The N-body version looks like this:

    public static void PushPlanets(Planet[] planets)
    {
        // Position Push at iteration N + 0:
        foreach(var p in planets)
            p.Position += Gravity.dT * p.Velocity; // Velocity from N - 1/2

        // Velocity Push at iteration N + 1/2:
        foreach (var p in planets)
        {
            Vector TotalGravity = new Vector(0,0);
            foreach (var pN in planets)
            {
                if (pN == p) continue;
                TotalGravity += pN.Mass * p.Mass * GravityAccelerationVector(p.Position - pN.Position);
            }
            TotalGravity += Sun.Mass * p.Mass * GravityAccelerationVector(p.Position); // Solar acceleration
            p.Velocity += Gravity.dT * TotalGravity;
        }

Where

    public static Vector GravityAccelerationVector(Vector position)
    {
        return Vector.Multiply(-G / position.LengthSquared / position.Length, position);
    }

The N-body is only more complicated because instead of a single gravitational source, there are several. The code format is the same, though: each planet's position gets pushed by the N-1/2 Velocity, then we figure out the total gravity acceleration on each planet based on the new positions, then we push each planet's Velocity by that total acceleration.

Other methods, even high order methods, are often unstable because they linearly project the next step based on position and velocity at the same time. This will always err on the side of adding energy to the system, and the orbits will gradually move further and further outward. Other methods can overcompensate for this natural error and remove energy from the system. In general, one wants an energy neutral solution. The leap frog method will gradually err in terms of phase of the orbits, but not in overall energy.

James
  • 377
  • 4
  • 7
3

A passing object will not enter orbit. One characteristic of an orbit is that you will return to the same point (relative to the body being orbited) with the same velocity. If you started from effective infinity, you'll go back to effective infinity.

In order to enter orbit, you will need to change the velocity at some point in a way unrelated to gravity, or perhaps have additional large bodies. Similarly, you can't launch an object into orbit from the surface: you have to have something (like a last rocket burn) once the satellite reaches the desired altitude. Otherwise it will try to return to the launch point, which is on the surface.

Some of my worst debugging experiences were when the program was fine and my test data or calculations were off. Make sure you know what to look for.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
  • What's the difference between "a passing object" and "an orbiting object" if they are going the same velocity at the same distance from the other body? – Daniel Earwicker Mar 17 '09 at 21:25
  • My impression was that the "passing body" was coming from far away. The difference between that and an orbiting body is of course velocity. I could have been misinterpreting the OP, of course. – David Thornley Mar 17 '09 at 21:38
  • Pretty sure you're wrong about this, since Triton is believed to be a captured satellite—it was passing; now it's orbiting. If I understand correctly, no matter how far away an object comes when it nears a more massive body, it may enter orbit if the velocity and distance are right. – P Daddy Mar 17 '09 at 22:31
  • Simply put, if you take a string and tie the ends together, you have a loop, but if you tie one end to the middle of the string, you still have a loop. To orbit, you need not return to your point of origin. – P Daddy Mar 17 '09 at 22:34
  • @P Daddy: Gravitational interaction are fully time reversal invariant. For a "passing body" to be captures *requires* a thrust or an interaction with a third body. And all two-body gravitational interaction paths are conic sections (in the COM frame). – dmckee --- ex-moderator kitten Mar 17 '09 at 23:30
  • @P Daddy: If the velocity and position are right, the object will be in orbit. It won't be right if the object comes from effectively infinity. This is of course in the two-body case. It is possible to capture in more complex cases. – David Thornley Mar 18 '09 at 13:37
  • You guys are way over my head, with the COM stuff, and all (I hate COM!) :·) – P Daddy Mar 18 '09 at 15:13
1

A) We have no idea what your input values are.

B) You might want to use a better approximation than Newton-Raphson.

C) Passing objects do not generally fall into orbit IRL, gravity is extremely weak, it takes equally weak velocities or truly exceptional masses to get much more than curvature.

Svante
  • 50,694
  • 11
  • 78
  • 122
annakata
  • 74,572
  • 17
  • 113
  • 180