3
\$\begingroup\$

I have a RigidBody in Bullet. Each frame, I want to apply torque to correct its orientation toward an upright position (i.e. near-zero pitch and roll). I know its angular velocity and orientation.

Bullet is not very well documented. I don't even know what the parameters to btRigidBody::applyTorque() mean.

How should I approach this?

\$\endgroup\$
2
  • \$\begingroup\$ Are you looking to prevent objects from rotating entirely, or do you want a "springy" effect where they automatically return to their original orientation over time? \$\endgroup\$
    – bcrist
    Commented Aug 4, 2014 at 8:03
  • 1
    \$\begingroup\$ I want them to be affected by external forces but return to their original orientation over time. Like there is always a force pulling them to the vertical position. \$\endgroup\$
    – Lighthink
    Commented Aug 4, 2014 at 8:35

3 Answers 3

4
\$\begingroup\$

This is a classical control problem. You want to create a feedback loop that takes the divergence from optimal position and applies the appropriate torque to nudge it back into position.

btQuaternion targetOrientation  = // whatever you need
btQuaternion currentOrientation = myObject->getOrientation();

Getting the delta orientation is quite simple, you need to find the "difference" between two the quaternions target and current orientation.

btQuaternion deltaOrientation = targetOrientation *  currentOrientation.inverse();

Unfortunately this quaterion does not say much about any divergence that we can use. But if you convert this delta orientation into euler angles.

btVector3 deltaEuler = QuaternionToEulerXYZ(deltaOrientation );

You basically get the scaled inverse of the torque you want to apply. Now you "just" need to find an appropriate amount to ease it in.

btVector torqueToApply = control(-deltaEuler);

The simple solution is to multiply it with a factor. You may need to play around with the factor until you find a good value.

// simple proportional controller
btVector control(btVector in) 
{
    // play around with the factor until you find a matching one
    static Kp = 0.5;
    return in * Kp;
}

You may also want to look into a PID-Controller to get a smoother more responsive easing.

\$\endgroup\$
6
  • \$\begingroup\$ Can you please be more specific? If I need to apply a torque force of 1000 to get to the targetOrientation, then torque = ( 1.0f / deltaEuler ) * 1000.0f ? \$\endgroup\$
    – Lighthink
    Commented Aug 6, 2014 at 10:31
  • \$\begingroup\$ Sorry for the confusion, with inverse I mean only the "vector pointing in the opposite direction", which is a simple negative. Also for almost all my gaming needs a simple proportional controller does the job, but if you think you need a more complex PID controller, here is a nice paper (with code) I found: mbed.org/cookbook/PID \$\endgroup\$
    – rioki
    Commented Aug 8, 2014 at 7:39
  • \$\begingroup\$ This is also under the assumption that Bullet's applyTorque still works like I remember. I have not used Bullet in a while and the documentation is sketchy. \$\endgroup\$
    – rioki
    Commented Aug 8, 2014 at 7:44
  • \$\begingroup\$ I tried implementing your method, but to no avail. It made my objects spin in seemingly random directions, but I'm not saying your method is wrong, but that it doesn't work for me, maybe because of an error in my implementation. Anyway, I solved it with a different approach: I computed the direction of the torque as equal to the negative of the orientation axis and it worked great. Thanks for you answer though, I think it should work under right implementation. \$\endgroup\$
    – Lighthink
    Commented Aug 10, 2014 at 17:16
  • \$\begingroup\$ Interesting aproach, I did not think of computing it this way. How are you preventing overshooting the target? \$\endgroup\$
    – rioki
    Commented Aug 10, 2014 at 18:34
1
\$\begingroup\$

I approached with a little Googlesearch ;)

From what I found bt:RigidBody::applyTorque(btVector3 & torque) takes a vector in WorldSpace and uses it as axis to apply a torque which has a strength of the length of the vector.
The LocalSpace-Torque seems to be solved in this answer, even though the provided code looks like there has to be an easier version. The author confirms this.

To actually compute the torque needed to be applied, think of the following:

  1. You have two phases:
    1. Acceleration - Apply Torque to increase rotation speed
    2. Decceleration - Apply Torque to decrease rotation speed (usually opposite of Acceleration-Torque)
  2. Do you want a maximum rotation speed (for example to not make it immediatly visible that a Bullet is rotating)?
    1. Set Torque to 0 inbetween (or simply don't apply it).

You have to carefully time these phases, if you for example have a maximum Torque you can/want apply, accelerating too long will result in overshooting. Ideally your acceleration- and decceleration-Torque are of the same length along the same axis.

Rest is up to you, and I hope I could help.

EDIT: Long live the related question: changing orientation by applying torques.

\$\endgroup\$
1
  • \$\begingroup\$ And here a nice GIF where you can see the (light blue) Torque at work. You can clearly see the different phases described above. \$\endgroup\$
    – JFBM
    Commented Aug 5, 2014 at 15:29
1
\$\begingroup\$

The accepted answer works for me and is a good starting point.

It might be helpful to have a complete example that works with the most recent Bullet version.

btRigidBody* rigid_body;

btQuaternion current_orientation = bt_rigid_body->getOrientation();

btVector3 axis(0, 0, 1);
btScalar angle = 0.1;
btQuaternion target_orientation(axis, angle);

btQuaternion delta = target_orientation * current_orientation.inverse();

// Get Euler angles
float x, y, z;
delta.getEulerZYX(z, y, x);

// Feed torque into control function (see accepted answer)
btVector3 local_torque = control(btVector3(x, y, z));

// Transform torque to world space
btVector3 world_torque = bt_rigid_body->getWorldTransform().getBasis() * local_torque;
bt_rigid_body->applyTorque(world_torque);
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .