Quaternions, torque, and direction

Hello Everyone,

I finally decided to register on this board as I have become stuck when attempting to solve an issue. Usually I can search the documentation, java docs, or forum and find whatever I am looking for. Anyway, I am attempting to make an physicsRigidBody rotate to face a specific direction using applyTorque() and could use some help. I have attempted creating a Quaternion and using lookAt. If I just set the rotation this of course works fine. I have also used slerp and multiplied the new Quat by the old one, used to angles, and used that as a torque vector. Anyway, just a small sample but I have tried everything I can think of…

Currently trying:

[java]
Quaternion q = physicsRigidBody.getPhysicsRotation().clone();
q.lookAt(target, Vector3f.UNIT_Y);
Vector3f location = physicsRigidBody.getPhysicsLocation();
Quaternion rotError = physicsRigidBody.getPhysicsRotation().mult(q);
float[] angles = new float[3];
rotError.toAngles(angles);
Vector3f torqueVector = new Vector3f(angles[0] * (FastMath.DEG_TO_RAD), angles[1] * (FastMath.DEG_TO_RAD), angles[2] * (FastMath.DEG_TO_RAD));
torqueVector.normalizeLocal().multLocal(physicsRigidBody.getMass());
physicsRigidBody.applyTorque(torqueVector);

[/java]

In addition I have tried something similiar to:
http://hub.jmonkeyengine.org/forum/topic/jme-simple-examples-project/page/3/
http://hub.jmonkeyengine.org/forum/topic/problems-working-out-an-auto-leveling-routine/

IF anyone has any ideas of how to get an object to rotate towards a specific vector and stop using torque please let me know.

David

1 Like

Look at the HoverTankControl example in the JmeTests examples, it shows how to control uncontrolled movement by applying forces.

I came up with something which semi works using that example. It still always misses the target rotation and backtracks but oh well. How would you improve upon his?
Nevermind, some reason the browser is not letting me paste the entire method.

Tweaking ^^

Well. I may be wrong, but I think your vision of torque is false. Torque is a rotational force. It does imply a rotation but not set it.

I mean :
Torque => Angular speed => Rotation

If you want to stop the rotation, you have to apply reversed torque.

Thus, if you run your method each update, you will constantly overshoot as you apply reversed torque only when you have gone past your target… building angular speed all the way in. This reversed torque first consume angular speed and then start going to your target again… just to go past again.

Maybe you should look into some king of anticipation like PID controllers ?

1 Like

@Yang71 - Nah, I understand the concept just how to get the correct vector to apply in order to rotate towards the proper direction. Honestly, I was and still am very tempted to simply use slerp and just set the rotation on the physicsRigidBody but I have read that is bad on this forum. Anyone know why not to do that? It would make things much easier :wink:

Cause it messes with your collision results. Its as if you beam objects around instead of moving them.

In essence you just cross product the direction you want your object to face, and the direction it’s currently facing. This gives you the axis (vector) to rotate around. Then you need to develop something as @yang71 suggests to prevent overshooting, and as suggested apply a reverse torque based on the current torque and the angle between the current direction and destination direction. Its never gonna be perfect, so you may have to decrease the tolerance to where its “close enough” to the destination vector that it won’t make a significant difference.

a bit late, but i’ve implemented pid controller into my space ship game right now

[java]
/**
*

  • @author Ascaria Quynn
    */
    public class PidController {

    /* Some hi-tech factors */
    private float p, i, d;

    private Vector3f integral = new Vector3f();
    private Vector3f derivate = new Vector3f();
    private Vector3f lastError = new Vector3f();

    /**

    • Initialize PID controller.
    • @param p
    • @param i
    • @param d
      */
      public PidController(float p, float i, float d) {
      this.p = p;
      this.i = i;
      this.d = d;
      }

    /**

    • Returns something hi-tech :slight_smile:
    • @param tpf
    • @param currentError
    • @return
      */
      public Vector3f getCorrection(float tpf, Vector3f currentError) {
      integral.addLocal(currentError.mult(tpf));
      derivate.set(currentError.subtract(lastError).divide(tpf));
      lastError.set(currentError);
      return currentError.mult§
      .add(integral.mult(i))
      .add(derivate.mult(d));
      }
      }
      [/java]

usage:
[java]
private PidController angVelController = new PidController(10f, 0f, 1f);
private PidController headingController = new PidController(10f, 0f, 0.05f);

   /**
 * Rotate entity towards target.
 * @param tpf
 * @param steeringEntity can be replaced with rigidbodycontrol
 * @param rotationPower
 * @return heading error length squared
 */
private float rotateTowardsTarget(float tpf, SteeringEntity steeringEntity, float rotationPower) {
    Vector3f angVelError = steeringEntity.getAngularVelocity().negate();
    Vector3f angVelCorrection = angVelController.getCorrection(tpf, angVelError);

    steeringEntity.applyTorque(angVelCorrection.mult(rotationPower * tpf));

    // loc is target location vector3f
    Vector3f desiredHeading = loc.subtract(steeringEntity.getPhysicsLocation()).normalize();
    Vector3f currentHeading = steeringEntity.getPhysicsRotation().mult(Vector3f.UNIT_Z).normalize();

    Vector3f headingError = currentHeading.cross(desiredHeading);
    Vector3f headingCorrection = headingController.getCorrection(tpf, headingError);

    steeringEntity.applyTorque(headingCorrection.mult(rotationPower * tpf));
    return headingError.lengthSquared();
}

[/java]

1 Like