centripetal / centrifugal forces, how could it be done?

Just for fun: Here is a demo showing the coriolis effect, using Bullet physics. You will need the standard misc/sphere modelwith comes with the Panda3D SDK on your model path, and of course a recent Panda3D SDK.

The observers frame of reference is a rotating frame, e. g. like on the surface of a planet. The planet rotates with 10 percent of the orbital velocity.

The observer looks tangetial towards a point of the surface of this planet, indicated by a white sphere. A ball if cast up into the air from this point. Gravity stops the upward movement, and makes the ball fall down again. I did not add a planetary surface, so the ball fall down below surface level. In order to see the coriolis effect better I have added a vertical white ray from the starting point up and down.

If there was no coriolis effect the ball would follow this ray. But it deviates.

The only force I apply each frame is gravity. It is computed by finding the unit vector from the current position of the ball (in global corrdinates!) to the center of the planet (0,0,0). The multiply with a proper magnitud. No extra forces for coriolis or centrifugal/petal forces are added.

Another nice configuration is the spacesphip setting: f=1 to set the rotation velocity of the reference frame to exactly the orbital velocity. And reduce vR to 1, or the object will quickly fly out of camera frustrum.

from pandac.PandaModules import loadPrcFileData
loadPrcFileData('', 'sync-video f')
#loadPrcFileData('', 'bullet-broadphase-algorithm sap')
#loadPrcFileData('', 'bullet-sap-extents 10000000')

import sys
import math

from direct.showbase.ShowBase import ShowBase

from panda3d.core import Vec3
from panda3d.core import Point3
from panda3d.core import LineSegs

from panda3d.bullet import BulletWorld
from panda3d.bullet import BulletRigidBodyNode
from panda3d.bullet import BulletDebugNode
from panda3d.bullet import BulletSphereShape

# Config
G = 10.                       # gravitational constant
M = 10000.                    # mass of earth
m = 10.                       # mass of satelite
R = 100.                      # radius of orbit
vR = 12.                      # initial radial velocity
f = 0.1                       # factor applied to orbital velocity

v1 = f * math.sqrt(G*M/R)     # orbital velocity, times factor
T = 2 * math.pi * R / v1      # period of rotation
omega = 360.0 / T             # angular velocity of reference frame

# Base
demo = ShowBase()
demo.setBackgroundColor(.0,.0,.6,1)
demo.setFrameRateMeter(True)

# Moving frame of reference
frameNP = render.attachNewNode('Helper')

segs = LineSegs()
segs.moveTo(0,0,0)
segs.drawTo(R+10,0,0)
frameNP.attachNewNode(segs.create())

dummyNP = loader.loadModel('misc/sphere')
dummyNP.reparentTo(frameNP)
dummyNP.setPos(R,0,0)
dummyNP.setScale(0.5)

demo.cam.reparentTo(frameNP)
demo.cam.setPos(R-10,100,0)
demo.cam.lookAt(R-10,0,0)
demo.cam.setR(-90)

#demo.cam.setPos(0,-400,0)
#demo.cam.lookAt(0,0,0)

# Physics
debugNP = render.attachNewNode(BulletDebugNode('Debug'))
debugNP.show()
debugNP.node().showWireframe(True)
debugNP.node().showConstraints(True)
debugNP.node().showBoundingBoxes(False)
debugNP.node().showNormals(True)

world = BulletWorld()
world.setGravity(Vec3(0,0,0))
world.setDebugNode(debugNP.node())

ballNP = render.attachNewNode(BulletRigidBodyNode('Sphere'))
ballNP.node().setMass(m)
ballNP.node().addShape(BulletSphereShape(.5))
ballNP.node().setLinearVelocity(Vec3(vR,0,-v1))
ballNP.setPos(R,0,0)
ballNP.node().setDeactivationEnabled(False)
world.attachRigidBody(ballNP.node())

# Task
roll = 0
running = True

def pause():
  global running
  running = not running

def update(task):
  global roll
  if running:
    dt = globalClock.getDt()

    # Move frame
    roll += (omega * dt)
    frameNP.setR(roll)

    # Apply gravity
    gravity = Point3.zero() - ballNP.getPos()
    gravity.normalize()
    gravity *= G * M * m / (R**2)
    ballNP.node().applyCentralForce(gravity)

    # Step simulation
    world.doPhysics(dt, 5, 1./180.)

  return task.cont

globalClock.setMaxDt(0.1)
taskMgr.add(update, 'update')

# Main
demo.accept('escape', sys.exit)
demo.accept('x', pause)
demo.run()