Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate Torque Required To Align Two 3D Vectors with Constant Acceleration?

I'm currently building a simplified Reaction Control System for a Satellite game, and need a way to use the system to align the satellite to a given unit direction in world-space coordinates. Because this is a game simulation, I am faking the system and just applying a torque force around the objects epicenter.

This is difficult because in my case, the Torque cannot be varied in strength, it is either on or off. It's either full force or no force. Calculating the direction that the torque needs to be applied in is relatively easy, but I'm having trouble getting it to align perfectly without spinning out of control and getting stuck in a logical loop. it needs to apply the opposing force at precisely the right 'time' to land on the target orientation with zero angular velocity.

What I've determined so far is that I need to calculate the 'time' it will take to reach zero velocity based on my current angular velocity and the angle between the two vectors. If that exceeds the time until I reach angle zero, then it needs to apply the opposing torque. In theory this will also prevent it from 'bouncing' around the axis too much. I almost have it working, but in some cases it seems to get stuck applying force in one direction, so I'm hoping somebody can check the logic. My simulation does NOT take mass into account at the moment, so you can ignore the Inertia Tensor (unless it makes the calculation easier!)

For one axis, I'm currently doing it this way, but I figure someone will have a far more elegant solution that can actually compute both Yaw and Pitch axes at once (Roll is invalid).

Omega = Angular Velocity in Local-Space (Degrees Per Second)
Force = Strength of the Thrusters

// Calculate Time Variables
float Angle = AcosD(DotProduct(ForwardVector, DirectionVector));
float Time1 = Abs(Angle / Omega.Z); // Time taken to reach angle 0 at current velocity
float Time2 = Abs(DeltaTime * (Omega.Z / Force); // Time it will take to reach Zero velocity based on force strength.

// Calculate Direction we need to apply the force to rotate toward the target direction. Note that if we are at perfect opposites, this will be zero!
float AngleSign = Sign(DotProduct(RightVector, DirectionVector));

float Torque.Z = 0;
if (Time1 < Time2)
{
   Torque.Z = AngleSign * Force;
}
else
{
   Torque.Z = AngleSign * Force * -1.0f
}

// Torque is applied to object as a change in acceleration (no mass) and modified by DeltaSeconds for frame-rate independent force. 

This is far from elegant and there are definitely some sign issues. Do you folks know a better way to achieve this?

EDIT: If anybody understands Unreal Engine's Blueprint system, this is how I'm currently prototyping it before I move it to C++

enter image description here

like image 944
Jambax Avatar asked Nov 11 '15 10:11

Jambax


Video Answer


1 Answers

Beginning from the "Calculate Direction" line, you could instead directly compute the correction torque vector in 3D, then modify its sign if you know that the previous correction is about to overshoot:

// Calculate Direction we need to apply the force to rotate toward the target direction
Torque = CrossProduct(DirectionVector, ForwardVector)
Torque = Normalize(Torque) * Force
if (Time2 < Time1)
{
  Torque = -Torque
}

But you should handle the problematic cases:

// Calculate Direction we need to apply the force to rotate toward the target direction
Torque = CrossProduct(DirectionVector, ForwardVector)

if (Angle < 0.1 degrees)
{
  // Avoid divide by zero in Normalize
  Torque = {0, 0, 0}
}
else
{
  // Handle case of exactly opposite direction (where CrossProduct is zero)
  if (Angle > 179.9 degrees)
  {
    Torque = {0, 0, 1}
  }

  Torque = Normalize(Torque) * Force
  if (Time2 < Time1)
  {
    Torque = -Torque
  }
}
like image 169
Saul Avatar answered Oct 12 '22 05:10

Saul