How to create a homing missile?

Post Reply
Hotshot5000
Posts: 2
Joined: Sun Aug 12, 2018 11:30 am

How to create a homing missile?

Post by Hotshot5000 » Sun Aug 12, 2018 3:52 pm

I have a rocket that moves with constant velocity. The linear velocity is always applied to the -Z axis(moving it forward). I want to be able to generate torque impulses that nudge the orientation of the rocket towards the enemy ship. I have searched these (and other forums) for the answer and there are things that are still unclear to me. I've read about calculateVelocity in src/LinearMath/btTransformUtil.cpp (https://pybullet.org/Bullet/phpBB3/view ... ate#p22997) but it doesn't seem to to what I need it to do. The linear velocity is constant and the returned angular velocity does not help me with the needed impulse.

What I would like is a function that gets called every frame and adjusts the course. Right now I have the following (java code from libgdx using a bullet wrapper):

Code: Select all

ENG_Vector4D entityPos = entityProperties.getNode().getPosition();
        ENG_Quaternion entityOrientation = entityProperties.getNode().getOrientation();
        ENG_Vector4D othEntityPosition = otherEntityProperties.getNode().getPosition();
        ENG_Quaternion othEntityOrientation = otherEntityProperties.getNode().getOrientation();
        ENG_Vector4D diff = otherEntityProperties.getNode().getPosition().subAsVec(entityProperties.getNode().getPosition());
        diff.normalize();

        ENG_Quaternion rotationTo = entityProperties.getNode().getLocalInverseZAxis().getRotationTo(diff);
        btTransformUtil.calculateVelocityQuaternion(new Vector3(entityPos.x, entityPos.y, entityPos.z),
                new Vector3(othEntityPosition.x, othEntityPosition.y, othEntityPosition.z),
                new Quaternion(entityOrientation.x, entityOrientation.y, entityOrientation.z, entityOrientation.w),
                new Quaternion(rotationTo.x, rotationTo.y, rotationTo.z, rotationTo.w),
                MainApp.getMainThread().getCurrentElapsedTime(), linearVelocity, angularVelocity);
        
        entityProperties.getRigidBody().applyTorqueImpulse(angularVelocity * some scaling); //This makes no sense, I know
What I do is I take the missile position with its front vector and find the quaternion that represents the rotation needed to get from the front to pointing in the enemy direction. Then I find the angular velocity using the calculateVelocityQuaternion() function. I then use (in code not shown here) the angular velocity as a sort of direction in which to apply the torque and scale it to some values until it mostly follows the enemy ship. The problem with this (wrong) approach is that sometimes the missile is almost properly aligned but still gets an impulse to fully align, but instead of aligning it overshoots. After that, the impulse gets bigger so it overshoots even more in the other direction, completely missing the target spinning around like an idiot.

Any idea on how I can gently slow down correctly when the missile is almost on target?

Another constraint that I forgot about is that the missile has a maximum angular velocity, so the impulse must not make the missile rotate more distance per second than allowed. If that limit is reached then the missile should simply fly around the target, missing it.

[EDIT]: The game takes place in space and there is no gravity. But there is angular and linear damping so things don't spin and move endlessly. I also checked the first answer from https://answers.unity.com/questions/488 ... sort=votes but I am not able to find the equivalent values from PhysX in Bullet. Namely the inertiaTensorRotation and the inertiaTensor. It seems bullet only uses inverse values for these things.

User avatar
drleviathan
Posts: 451
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: How to create a homing missile?

Post by drleviathan » Mon Aug 13, 2018 11:47 pm

Here's an idea: slam the velocity rather than applying impulse. I would do it something like below. Note: I don't know java so consider the example to be pseudocode. Dunno if it is bug-free: I didn't test.

Code: Select all

ENG_Vector4D newMissileDirection = targetProperties.getNode().getPosition().subAsVec(missileProperties.getNode().getPosition());
newMissileDirection.normalize();

ENG_Vector4D missileDirection = missileProperties.getNode().getLocalInverseZAxis();
float cosAngle = missileDirection.dot(newMissileDirection);
if (cosAngle > 0.99) {
    // properly aligned so we zero angularVelocity
    missileProperties.getRigidBody().setAngularVelocity(Vector3(0.0, 0.0, 0.0));
} else {
    // need to change orientation
    if (cosAngle <= -1.0) {
        // need to flip all the way around
        // ignore this case
    } else {
        float angle = acosf(cosAngle);
        ENG_Vector axis = missileDirection.cross(newMissileDirection);
        axis.normalize();
        Vector3 angularVelocity(axis.x, axis.y, axis.z);

        // exponentially decay the angular velocity toward the new direction
        // this is easy because when we assume the motion has exponential form the velocity is a scaled version of the displacement
        //     x(t) = Xo * exp(-t / tau)
        //     v(t) = (-1/tau) x(t)
        // for our case we've already computed the correct direction so we don't need the extra negative sign

        // tune the angular response by adjusting EXPONENTIAL_TIMESCALE which represents the time it takes for the rotation
        // to reduce its offset by 1/e.  After only three timescales the orientation should be very close.
        // Larger timescales are slower, smaller timescales are faster.
        float EXPONENTIAL_TIMESCALE = 0.5;

        // but if you go too small because you risk instability (never use timescales smaller than the substep).
        float deltaTime = MainApp.getMainThread().getCurrentElapsedTime();
        if (deltaTime > EXPONENTIAL_TIMESCALE) {
            EXPONENTIAL_TIMESCALE = 1.5 * deltaTime;
        }

        // compute angularVelocity
        float angularSpeed = angle / EXPONENTIAL_TIMESCALE;
        if (angularSpeed > MAX_ANGULAR_SPEED) {
            angularSpeed = MAX_ANGULAR_SPEED;
        }
        angularVelocity *= angularSpeed;

        missileProperties.getRigidBody().setAngularVelocity(angularVelocity);
    }
}

Hotshot5000
Posts: 2
Joined: Sun Aug 12, 2018 11:30 am

Re: How to create a homing missile?

Post by Hotshot5000 » Wed Aug 15, 2018 5:12 pm

Thank you very much. Initially I did it using angular velocity but didn't take into account the EXPONENTIAL_TIMESCALE so I was seeing instability. I though about solving it by going the torque route. Turns out it wasn't needed and I only made things harder for myself. Again, thank you! Now it's working correctly.

PcChip
Posts: 19
Joined: Sun May 20, 2018 3:09 pm

Re: How to create a homing missile?

Post by PcChip » Sun Aug 19, 2018 9:19 pm

is that sometimes the missile is almost properly aligned but still gets an impulse to fully align, but instead of aligning it overshoots. After that, the impulse gets bigger so it overshoots even more in the other direction
sounds like you could solve this by using a simple PID controller, there are two good ones easily found on github

I used one to stabilize an (extremely simplified) quadrotor - https://www.youtube.com/watch?v=_W4QTdgoy8g

Post Reply