Control a spaceship

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
grobi
Posts: 34
Joined: Wed Sep 23, 2009 5:47 pm

Control a spaceship

Post by grobi »

Hi, still got some problems controlling my model (a litle spaceship) with impulse.
I got a method which is called by the Xna.Game.Update method with values for
Throttle (main thruster which shall make the spaceship move along its z axis)
Yaw (makes the spaceship strafe along its x axis)
Roll (makes the spaceship roll along its z axis)
Pitch (makes the spaceship roll along its x axis)
Lift (makes the spaceship move along its Y axis)
the ship has a mass of 100
gravity is -9.81 (ok i know, a spaceship on earth...)
if there is no lift, the spaceship shall "hover".
I feed it with values about 500 - 2500 * duration
duration = (gameTime.ElapsedGameTime.Milliseconds / 1000.0f)
But unfortunatly its not working very nice, it become uncontrolable very quick.
Is there anybody who maybe has a clue how to get the right values to control the spaceship like a pilot could do?

thx Grobi

Code: Select all

public void Update(float Throttle, float Yaw, float Roll, float Pitch, float Lift)
        {
            Vector3 direction = Vector3.Normalize(new Vector3(worldMatrix.M31, worldMatrix.M32, worldMatrix.M33));
            Vector3 trust = (direction * -Throttle);
            Vector3 yaw = worldMatrix.Left * Yaw;
            Vector3 roll = worldMatrix.Up * Roll;
            Vector3 pitch = worldMatrix.Up * Pitch;
            Vector3 lift = worldMatrix.Up * (Lift);
            Vector3 p = Vector3.Zero;
            if (Yaw != 0)
            {
                p = Vector3.Transform(new Vector3(0, 0, boundingBox.Max.Z - boundingBox.Min.Z), Matrix.CreateFromQuaternion(body.orientationQuaternion));
                p += body.centerOfMass;
                body.applyImpulse(p, yaw);
            }
            if (Roll != 0)
            {
                p = Vector3.Transform(new Vector3(-(boundingBox.Max.X - boundingBox.Min.X), 0, 0), Matrix.CreateFromQuaternion(body.orientationQuaternion));
                p += body.centerOfMass;
                body.applyImpulse(p, roll);
            }
            if (Pitch != 0)
            {
                p = Vector3.Transform(new Vector3(0, 0, (boundingBox.Max.Z - boundingBox.Min.Z) / 2), Matrix.CreateFromQuaternion(body.orientationQuaternion));
                p += body.centerOfMass;
                body.applyImpulse(p, pitch);
            }
            if (Lift != 0)
            {
                p = body.centerOfMass;
                body.applyImpulse(p, lift);
            }
            else
            {
                Vector3 slidingVelocity = -body.internalLinearVelocity;
                slidingVelocity.X = 0;
                slidingVelocity.Z = 0;
                body.internalLinearVelocity += slidingVelocity;
            }
            p = Vector3.Transform(new Vector3(0, 0, boundingBox.Max.Z - boundingBox.Min.Z), Matrix.CreateFromQuaternion(body.orientationQuaternion));
            p += body.centerOfMass;
            body.applyImpulse(p, trust);
        }
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Control a spaceship

Post by Norbo »

Could you describe what the desired behavior you want is, versus the current inappropriate behavior?

By the way, here's some general notes about the code:
-Entities have an orientationMatrix field you can use instead of converting the orientationQuaternion to a matrix
-The timing will probably be a little more accurate if you use duration = gameTime.ElapsedGameTime.TotalSeconds since it returns a fractional value, while the milliseconds property returns an integer.
-Applying impulses always affects the linear velocity. Modeling angular thrusters by applying impulses at certain points can be more 'physically correct,' but getting a controllable setup can be hard. It may be easier to just change the angular velocity directly (or apply angular impulses).
grobi
Posts: 34
Joined: Wed Sep 23, 2009 5:47 pm

Re: Control a spaceship

Post by grobi »

what makes it inappropriate is that sometimes the impulse is to weak or to strong to make it really stearable and have some sort of finecontrol,
i want to achive something like this... e.g the pitch.. a small impulse shall make the ship pitch slowly, a bigger impulse make it pitch faster, no impulse shall make the pitching stop, same as jaw, roll and lift, the main thruster shall behave like a (reverseable) rocket so its almost the same as a helicopter control.
pushing the pilotstick a lil to the left shall make the ship turn a lil to the left..., pushing it all the way to the right shall make the ship turn fast to the right and so on...
I am sorry, its a lil hard to describe what i really want, english is not my native language, actually I am from germany, but i try :-)

Grobi
grobi
Posts: 34
Joined: Wed Sep 23, 2009 5:47 pm

Re: Control a spaceship

Post by grobi »

so far i came up with a way which is a bit more controllable...

Code: Select all

public void Update(float Throttle, float Yaw, float Roll, float Pitch, float Lift)
        {
            Vector3 p = Vector3.Zero;
            Vector3 _p = Vector3.Zero;
            Vector3 direction = Vector3.Normalize(new Vector3(worldMatrix.M31, worldMatrix.M32, worldMatrix.M33));
            p = body.internalAngularVelocity;
            // Yaw
            p += (worldMatrix.Up * Yaw);
            // Pitch
            p += (worldMatrix.Left * Pitch);
            // Roll
            p += (direction * Roll);
            // apply
            body.internalAngularVelocity = p;
            _p = body.internalLinearVelocity;
            // Thrust
            _p += (direction * Throttle);
            // apply
            body.internalLinearVelocity = _p;
        }
i fed it with values of (-1.0f..1.0f) * duration;
float duration = (float)gameTime.ElapsedGameTime.TotalSeconds;

but i want to apply some sort of manual angular damping on the pitch, yaw and roll axis if there is no steering input for it.
And if pitch, yaw or roll speed is higher than a maximum value it should not go higher by user input like if ship is pitching with speed > +10 and i pull the stick into pitch+ direction, it shall not go faster, only by outside interference e.g being hit by a rocket or another ship.
But how do i get a single float value of the pitch, yaw and roll speed to check its condition and manipulate the internalAngularvelocity of the body?

Grobi
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Control a spaceship

Post by Norbo »

If you take the dot product of the entity's angular velocity and some arbitrary length-1 axis, you will get a scalar representing the angular speed around that axis.

So, for example:

Code: Select all

float yawSpeed = Vector3.Dot(entity.internalAngularVelocity, entity.worldTransform.Up)
You can then compare this against your 'goal' yaw speed. If the current speed is smaller than the goal velocity, you can accelerate it by some amount:

Code: Select all

if(yawSpeed < goalYawSpeed)
    entity.internalAngularVelocity += entity.worldTransform.Up * (acceleration * dt);
You probably would want to add in clamping as well to ensure that accelerating by (acceleration * dt) does not cause the velocity to exceed the goalYawSpeed. That way, if your acceleration is 1000 (quite fast), and you're only 0.1f away from the goal speed currently, the next frame velocity won't be ~16.56 too high (which would probably cause unsightly jigging).


If the entity already exceeds the goal velocity, you could either similarly apply a deceleration or ignore it.


You could also use a 'springy' method, where the corrective velocity applied is proportional to how far away the current velocity is from the desired velocity.

Code: Select all

float speedDifference = goalYawSpeed - yawSpeed
entity.internalAngularVelocity += entity.worldTransform.Up * (speedDifference * correctionConstant / dt)
BrianL
Posts: 54
Joined: Wed Jun 25, 2008 4:41 pm
Location: Panama City Beach, FL

Re: Control a spaceship

Post by BrianL »

I'm gonna hop in here since I'm also trying to do something (loosely) similar, except it's with roll. However, I'm trying to do it with torque instead. I need to figure out how much torque to apply to an entity considering its moment of inertia around the desired axis of rotation and a pre-determined amount (desired angle) of rotation.

For example, say I want to roll an entity that's currently at rest, 30 degrees to the left. We have its mass and moment of inertia as well as the desired angle (amount) of total rotation. But I'm still having trouble computing the amount of torque required to rotate it through the desired angle.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Control a spaceship

Post by Norbo »

It sounds like you're going to need more information to find a solution.

Torque is inertia times angular acceleration (equivalent to F = ma). Applying a single torque, or 'angular impulse,' will change the angular momentum (and by extension, angular velocity). With no further interference, that angular momentum will stick around and it will never stop.

If you have a desired timeframe in which to reach the angle goal, then you can just work at the velocity level. Velocity change = (Angle change / time to perform that change) * axis of change. When the goal is achieved/the time to perform that change elapses, you can 'turn off' that velocity. This is pretty similar to the velocity-style system grobi is moving toward.

If you want to smoothly accelerate up and then down to reach the goal in some time limit, you'll need to decide on a rate of acceleration/deceleration (maybe a maximum velocity too). You could also allot time to an 'acceleration' period, followed by a 'steady velocity' period, and finally by a 'deceleration' period and compute accelerations/decelerations accordingly. These accelerations could then be converted to torques using the inertia of the object, or you could incrementally change the velocity each frame to 'simulate' the acceleration.
Post Reply