-
Notifications
You must be signed in to change notification settings - Fork 240
Description
The temporary MoI is represented in kOS convention vessel local reference frame (Z point to nose). But while updating measured torque (by multiply angular acceleration with MoI), the code assumes that MoI is in Unity vessel local reference frame (Y point to nose). The consequence is MoI in Y and Z axis are swapped.
Details:
In kOS\Control\SteeringManager.cs, line 779-812, function public Vector3 FindMoI(). Because vesselRotation is in kOS convention definition, MoI is in kOS convention vessel local reference frame too. But vessel.MOI gives vector represented in Unity convention.
/// <summary>
/// This is a replacement for the stock API Property "vessel.MOI", which seems buggy when used
/// with "control from here" on parts other than the default control part.
/// <br/>
/// Right now the stock Moment of Inertia Property returns values in inconsistent reference frames that
/// don't make sense when used with "control from here". (It doesn't merely rotate the reference frame, as one
/// would expect "control from here" to do.)
/// </summary>
/// TODO: Check this again after each KSP stock release to see if it's been changed or not.
public Vector3 FindMoI()
{
var tensor = Matrix4x4.zero;
Matrix4x4 partTensor = Matrix4x4.identity;
Matrix4x4 inertiaMatrix = Matrix4x4.identity;
Matrix4x4 productMatrix = Matrix4x4.identity;
foreach (var part in Vessel.Parts)
{
if (part.rb != null)
{
KSPUtil.ToDiagonalMatrix2(part.rb.inertiaTensor, ref partTensor);
Quaternion rot = Quaternion.Inverse(vesselRotation) * part.transform.rotation * part.rb.inertiaTensorRotation;
Quaternion inv = Quaternion.Inverse(rot);
Matrix4x4 rotMatrix = Matrix4x4.TRS(Vector3.zero, rot, Vector3.one);
Matrix4x4 invMatrix = Matrix4x4.TRS(Vector3.zero, inv, Vector3.one);
// add the part inertiaTensor to the ship inertiaTensor
KSPUtil.Add(ref tensor, rotMatrix * partTensor * invMatrix);
Vector3 position = vesselTransform.InverseTransformDirection(part.rb.position - centerOfMass);
// add the part mass to the ship inertiaTensor
KSPUtil.ToDiagonalMatrix2(part.rb.mass * position.sqrMagnitude, ref inertiaMatrix);
KSPUtil.Add(ref tensor, inertiaMatrix);
// add the part distance offset to the ship inertiaTensor
OuterProduct2(position, -part.rb.mass * position, ref productMatrix);
KSPUtil.Add(ref tensor, productMatrix);
}
}
return KSPUtil.Diag(tensor);
}
In kOS\Control\SteeringManager.cs, line 578-620, function public void UpdateStateVectors()
omega = Quaternion.Inverse(vesselRotation) * shared.Vessel.GetComponent<Rigidbody>().angularVelocity;
omega.x *= -1; //positive values pull the nose to the starboard.
//omega.y *= -1; // positive values pull the nose up.
omega.z *= -1; // positive values pull the starboard side up.
// TODO: Currently adjustments to MOI are only enabled in debug compiles. Using this feature seems to be buggy, but it has potential
// to be more resilient against random spikes in angular velocity.
if (sessionTime > lastSessionTime)
{
double dt = sessionTime - lastSessionTime;
angularAcceleration = (omega - oldOmega) / dt;
angularAcceleration = new Vector3d(angularAcceleration.x, angularAcceleration.z, angularAcceleration.y);
}
// TODO: If stock vessel.MOI stops being so weird, we might be able to change the following line
// into this instead. (See the comment on FindMOI()'s header):
// momentOfInertia = shared.Vessel.MOI;
momentOfInertia = FindMoI();
adjustTorque = Vector3d.zero;
measuredTorque = Vector3d.Scale(momentOfInertia, angularAcceleration);
if (sessionTime > lastSessionTime && EnableTorqueAdjust)
{
if (Math.Abs(accPitch) > CONTROLEPSILON)
{
adjustTorque.x = Math.Min(Math.Abs(pitchTorqueCalc.Update(measuredTorque.x / accPitch)) - rawTorque.x, 0);
//adjustTorque.x = Math.Abs(pitchTorqueCalc.Update(measuredTorque.x / accPitch) / rawTorque.x);
}
else adjustTorque.x = Math.Abs(pitchTorqueCalc.Update(pitchTorqueCalc.Mean));
if (Math.Abs(accYaw) > CONTROLEPSILON)
{
adjustTorque.z = Math.Min(Math.Abs(yawTorqueCalc.Update(measuredTorque.z / accYaw)) - rawTorque.z, 0);
//adjustTorque.z = Math.Abs(yawTorqueCalc.Update(measuredTorque.z / accYaw) / rawTorque.z);
}
else adjustTorque.z = Math.Abs(yawTorqueCalc.Update(yawTorqueCalc.Mean));
if (Math.Abs(accRoll) > CONTROLEPSILON)
{
adjustTorque.y = Math.Min(Math.Abs(rollTorqueCalc.Update(measuredTorque.y / accRoll)) - rawTorque.y, 0);
//adjustTorque.y = Math.Abs(rollTorqueCalc.Update(measuredTorque.y / accRoll) / rawTorque.y);
}
else adjustTorque.y = Math.Abs(rollTorqueCalc.Update(rollTorqueCalc.Mean));
}
Apparently here we assume momentOfInertia is represented in Unity convention. This is a mistake