From eae48a1fac55e2fe97b97824d3c27d12482ca2e3 Mon Sep 17 00:00:00 2001 From: Lamont Granquist Date: Sun, 21 Jun 2026 10:21:00 -0700 Subject: [PATCH] Fix some VesselState thrust calculations (probably fix diffthrottle) - Removes the double-cos-losses coming both from the cosineLosses variable and the vector addition by just dropping the cosineLosses variable. - Change the CoT calculations to no longer be based on current thrust but on max thrust. This ensures that ThrustForward is nonzero with zero thrust, and makes it a constant of the vessel geometry. This means that diff throttle will also no longer affect and chase its own setpoint. As I've been adding INERTIAL_COT to various controllers I've probably been breaking diffthrottle and this should fix that. - That latter change might in principle break some badly constructed vehicles which have considerably different thrust vectors for minthrottle vs. maxthrottle for times when they aren't being max throttled. As most things you want to do with rockets tend to be bang-bang control this shouldn't affect anyone, but to the extent it actually does affect anyone, those rockets and situations are just considered rocket design problems, and support is dropped. --- MechJeb2/MechJebModuleDebugArrows.cs | 4 +-- MechJeb2/VesselState.cs | 52 ++++++++++++++++------------ MechJebKos/VesselStateBinding.cs | 4 --- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/MechJeb2/MechJebModuleDebugArrows.cs b/MechJeb2/MechJebModuleDebugArrows.cs index 1a71f79e9..638b53e8d 100644 --- a/MechJeb2/MechJebModuleDebugArrows.cs +++ b/MechJeb2/MechJebModuleDebugArrows.cs @@ -166,14 +166,14 @@ public override void OnUpdate() comSphere.SetRadius((float)comSphereRadius.Val); } - colSphere.State(colSphereActive && VesselState.CoLMagnitude > 0 && Core.ShowGui); + colSphere.State(colSphereActive && VesselState.CoLWeightSum > 0 && Core.ShowGui); if (colSphereActive) { colSphere.Set(VesselState.CoL + frameVel); colSphere.SetRadius((float)comSphereRadius.Val); } - cotSphere.State(cotSphereActive && VesselState.CoTMagnitude > 0 && Core.ShowGui); + cotSphere.State(cotSphereActive && VesselState.CoTWeightSum > 0 && Core.ShowGui); if (cotSphereActive) { cotSphere.Set(VesselState.CoT + frameVel); diff --git a/MechJeb2/VesselState.cs b/MechJeb2/VesselState.cs index c535e1223..cefc39de8 100644 --- a/MechJeb2/VesselState.cs +++ b/MechJeb2/VesselState.cs @@ -126,12 +126,15 @@ public class VesselState public double CelestialLongitude; public Vector3d CoL; - public double CoLMagnitude; + // Sum of the per-part scalar lift weights used to form the CoL centroid (not a vector magnitude). + public double CoLWeightSum; public Vector3d CoM; public Vector3d CoT; - public double CoTMagnitude; + // Sum of the per-thrust-transform scalar thrust weights used to form the CoT centroid + // (equals total scalar thrust, i.e. before directional cancellation -- not the net thrust magnitude). + public double CoTWeightSum; public double DeltaT; //TimeWarp.fixedDeltaTime public Vector3d DoT; @@ -831,11 +834,11 @@ private void AnalyzeParts(EngineInfo einfo, IntakeInfo iinfo) } CoL = Vector3d.zero; - CoLMagnitude = 0; + CoLWeightSum = 0; CoT = Vector3d.zero; DoT = Vector3d.zero; - CoTMagnitude = 0; + CoTWeightSum = 0; ThrustForward = Vector3d.zero; foreach (Part p in _vessel.parts) @@ -997,7 +1000,7 @@ private void AnalyzeParts(EngineInfo einfo, IntakeInfo iinfo) foreach (KeyValuePair engine in _engines) { - einfo.AddNewEngine(engine.Key, engine.Value, EngineWrappers, ref CoT, ref DoT, ref CoTMagnitude); + einfo.AddNewEngine(engine.Key, engine.Value, EngineWrappers, ref CoT, ref DoT, ref CoTWeightSum); einfo.CheckUllageStatus(engine.Key); } @@ -1009,12 +1012,12 @@ private void AnalyzeParts(EngineInfo einfo, IntakeInfo iinfo) var partDrag = Vector3d.Project(partAeroForce, -SurfaceVelocity); Vector3d partLift = partAeroForce - partDrag; - double partLiftScalar = partLift.magnitude; + double partCoLWeight = partLift.magnitude; - if (p.rb != null && partLiftScalar > 0.01) + if (p.rb != null && partCoLWeight > 0.01) { - CoLMagnitude += partLiftScalar; - CoL += ((Vector3d)p.rb.worldCenterOfMass + (Vector3d)(p.partTransform.rotation * p.CoLOffset)) * partLiftScalar; + CoLWeightSum += partCoLWeight; + CoL += ((Vector3d)p.rb.worldCenterOfMass + (Vector3d)(p.partTransform.rotation * p.CoLOffset)) * partCoLWeight; } } @@ -1056,9 +1059,9 @@ private void AnalyzeParts(EngineInfo einfo, IntakeInfo iinfo) ThrustVectorMinThrottle = einfo.ThrustMin; ThrustVectorLastFrame = einfo.ThrustCurrent; - if (CoTMagnitude > 0) + if (CoTWeightSum > 0) { - CoT /= CoTMagnitude; + CoT /= CoTWeightSum; ThrustForward = (CoM - CoT).normalized; // In certain circumstances, like hotstaging, the CoM of the Vessel can be behind the CoT before // decoupling and while dragging the previous stage. In that case thrustForward can wind up pointing @@ -1069,8 +1072,8 @@ private void AnalyzeParts(EngineInfo einfo, IntakeInfo iinfo) DoT = DoT.normalized; - if (CoLMagnitude > 0) - CoL /= CoLMagnitude; + if (CoLWeightSum > 0) + CoL /= CoLWeightSum; Vector3d liftDir = -Vector3d.Cross(_vessel.transform.right, -SurfaceVelocity.normalized); @@ -1324,7 +1327,7 @@ public void CheckUllageStatus(ModuleEngines e) } public void AddNewEngine(ModuleEngines e, ModuleGimbal? gimbal, List enginesWrappers, ref Vector3d cot, ref Vector3d dot, - ref double coTScalar) + ref double coTWeightSum) { // FIXME: shouldn't we gather statistics on unignited engines??? if (!e.EngineIgnited || !e.isEnabled) @@ -1399,17 +1402,22 @@ public void AddNewEngine(ModuleEngines e, ModuleGimbal? gimbal, List(() => _vesselState.MaxEngineResponseTime, "Maximum engine spool-up response time in seconds.")); - AddSuffix("COTMAGNITUDE", new Suffix(() => _vesselState.CoTMagnitude, - "Magnitude of the center-of-thrust vector.")); - AddSuffix("COLMAGNITUDE", new Suffix(() => _vesselState.CoLMagnitude, - "Magnitude of the center-of-lift vector.")); // --- Booleans --- AddSuffix("PARACHUTEDEPLOYED", new Suffix(() => _vesselState.ParachuteDeployed,