# Why do my satellites fall out of orbit?

I have set up Newtonian Gravity in my Game Engine, allowing me to simulate the gravitational attraction between celestial bodies.

I have the following variables defined:

btScalar whiteHoleMass = 5e+28;
btScalar sunMass = 5e+24;
btScalar sunOrbitTime = 1800; // Orbit time is in seconds
btScalar planetMass = 5e+21;
btScalar planetOrbitTime = 900;


    btScalar sunOrbitRadius = 0;
btScalar sunOrbitVelocity = 0;
btScalar planetOrbitVelocity = 0;
btScalar orbitalSatelliteOrbitVelocity = 0;
btScalar thisOrbitalHeight = 0;
calculateOrbit(currentOrbitalLength, planetMass, thisOrbitalHeight, orbitalSatelliteOrbitVelocity);


and the calculateOrbit function is defined as:

void calculateOrbit(const btScalar &orbitTimeSecs, const btScalar &centralMassKg, btScalar &orbitRadius, btScalar &orbitVelocity)
{
orbitRadius = std::cbrt((Common::G * centralMassKg * orbitTimeSecs * orbitTimeSecs) / (4 * Common::Pi * Common::Pi));
orbitVelocity = std::sqrt(Common::G * centralMassKg / orbitRadius);
};


I then set the Linear Velocity of the Sun, Planet and Satellites like so:

sunPointer->rigidBody->setLinearVelocity({0, 0, sunOrbitVelocity});
planetPointer->rigidBody->setLinearVelocity({0, 0, planetOrbitVelocity + sunOrbitVelocity});
orbitalPointer->rigidBody->setLinearVelocity({0, 0, orbitalSatelliteOrbitVelocity + planetOrbitVelocity + sunOrbitVelocity});


The linear velocity is added in the Z dimension.

I would have thought this was sufficient to keep Satellite/Planet/Sun in constant orbit, however 45 seconds into running the simulation the satellites fall out of orbit and crash into the planet.

How can I set up orbits of multiple bodies so they are stable?

I calculate gravity between objects like so:

for (uInteger64 i = 1; i <= entityMap._size; i++)
{
btVector3 accelerations(0, 0, 0);
auto &entityA = *entityMap._data[i]->value.pointer;
auto &bodyA = *entityA.rigidBody;
auto bodyAMass = bodyA.getMass();
auto &positionA = bodyA.getCenterOfMassPosition();
if (bodyA.getActivationState() == ACTIVE_TAG)
{
for (uInteger64 j = 1; j <= entityMap._size; j++)
{
if (i == j)
{
continue; // Skip self
}
auto &entityB = *entityMap._data[j]->value.pointer;
auto &bodyB = *entityB.rigidBody;
auto bodyBMass = bodyB.getMass();
auto &positionB = bodyB.getCenterOfMassPosition();
btVector3 vectorAB = positionB - positionA;
btScalar distanceAB = vectorAB.length();
btVector3 directionAB = vectorAB.normalized();
Floating128 forceMagnitude = (Floating128)Common::G * ((Floating128)bodyAMass * (Floating128)bodyBMass) / ((Floating128)distanceAB * (Floating128)distanceAB);
btVector3 forceAB = directionAB * forceMagnitude;
accelerations += forceAB / bodyAMass;
}
entityA.applyCustomAcceleration(accelerations);
}
}


and applyCustomAcceleration is defined as:

void IEntity::applyCustomAcceleration(const btVector3 &acceleration)
{
if (!rigidBody || rigidBody->isStaticOrKinematicObject())
{
return;
}
if (rigidBody)
{
btVector3 force = acceleration * rigidBody->getMass();
rigidBody->applyCentralForce(force);
}
};

• Could you perhaps write some equations describing how you are updating your position and velocity at each time step? That is much easier for readers to parse than game engine code. Feb 28 at 17:47
• Is the step size small enough that the satellite orbits are sufficiently sampled? If so, are the satellite orbits actually circular or narrow ellipses? If the periapsis is below the surface of the planet, you get a case of litho-braking. Feb 28 at 18:10
• Crossposted from physics.stackexchange.com/q/804284/2451 Feb 28 at 22:53