@@ -176,110 +176,58 @@ public static void SteerShipToward(Quaternion target, FlightCtrlState c, FlightC
176176 // Add support for roll-less targets later -- Starstrider42
177177 bool fixedRoll = ! ignoreRoll ;
178178 Vessel vessel = fc . Vessel ;
179- Vector3d momentOfInertia = vessel . MOI ;
179+ Vector3d momentOfInertia = GetTrueMoI ( vessel ) ;
180180 Transform vesselReference = vessel . GetTransform ( ) ;
181- Vector3d torque = GetTorque ( vessel , c . mainThrottle ) ;
182-
183- // -----------------------------------------------
184- // Copied from MechJeb master on 18.04.2016 with some modifications to adapt to RemoteTech
185-
186- Vector3d _axisControl = new Vector3d ( ) ;
187- _axisControl . x = true ? 1 : 0 ;
188- _axisControl . y = true ? 1 : 0 ;
189- _axisControl . z = fixedRoll ? 1 : 0 ;
190-
191- Vector3d inertia = Vector3d . Scale (
192- new Vector3d ( vessel . angularMomentum . x , vessel . angularMomentum . y , vessel . angularMomentum . z ) . Sign ( ) ,
193- Vector3d . Scale (
194- Vector3d . Scale ( vessel . angularMomentum , vessel . angularMomentum ) ,
195- Vector3d . Scale ( torque , momentOfInertia ) . Invert ( )
196- )
197- ) ;
198181
199- Vector3d TfV = new Vector3d ( 0.3 , 0.3 , 0.3 ) ;
200-
201- double kpFactor = 3 ;
202- double kiFactor = 6 ;
203- double kdFactor = 0.5 ;
204- double kWlimit = 0.15 ;
205- double deadband = 0.0001 ;
182+ //---------------------------------------
183+ // Copied almost verbatim from MechJeb master on June 27, 2014 -- Starstrider42
206184
207185 Quaternion delta = Quaternion . Inverse ( Quaternion . Euler ( 90 , 0 , 0 ) * Quaternion . Inverse ( vesselReference . rotation ) * target ) ;
208186
209- Vector3d deltaEuler = delta . DeltaEuler ( ) ;
187+ Vector3d torque = GetTorque ( vessel , c . mainThrottle ) ;
188+ Vector3d spinMargin = GetStoppingAngle ( vessel , torque ) ;
210189
211- // ( MoI / available torque ) factor:
212- Vector3d NormFactor = Vector3d . Scale ( momentOfInertia , torque . Invert ( ) ) . Reorder ( 132 ) ;
190+ // Allow for zero torque around some but not all axes
191+ Vector3d normFactor ;
192+ normFactor . x = ( torque . x != 0 ? momentOfInertia . x / torque . x : 0.0 ) ;
193+ normFactor . y = ( torque . y != 0 ? momentOfInertia . y / torque . y : 0.0 ) ;
194+ normFactor . z = ( torque . z != 0 ? momentOfInertia . z / torque . z : 0.0 ) ;
195+ normFactor = SwapYZ ( normFactor ) ;
213196
214- // Find out the real shorter way to turn were we wan to.
197+ // Find out the real shorter way to turn were we want to.
215198 // Thanks to HoneyFox
216- Vector3d tgtLocalUp = vesselReference . rotation . Inverse ( ) * target * Vector3d . forward ;
199+
200+ Vector3d tgtLocalUp = vesselReference . transform . rotation . Inverse ( ) * target * Vector3d . forward ;
217201 Vector3d curLocalUp = Vector3d . up ;
218202
219203 double turnAngle = Math . Abs ( Vector3d . Angle ( curLocalUp , tgtLocalUp ) ) ;
220- Vector2d rotDirection = new Vector2d ( tgtLocalUp . x , tgtLocalUp . z ) ;
221- rotDirection = rotDirection . normalized * turnAngle / 180.0 ;
222-
223- // And the lowest roll
224- // Thanks to Crzyrndm
225- Vector3 normVec = Vector3 . Cross ( target * Vector3 . forward , vesselReference . up ) ;
226- Quaternion targetDeRotated = Quaternion . AngleAxis ( ( float ) turnAngle , normVec ) * target ;
227- float rollError = Vector3 . Angle ( vesselReference . right , targetDeRotated * Vector3 . right ) * Math . Sign ( Vector3 . Dot ( targetDeRotated * Vector3 . right , vesselReference . forward ) ) ;
204+ var rotDirection = new Vector2d ( tgtLocalUp . x , tgtLocalUp . z ) ;
205+ rotDirection = rotDirection . normalized * turnAngle / 180.0f ;
228206
229- var error = new Vector3d (
207+ var err = new Vector3d (
230208 - rotDirection . y * Math . PI ,
231209 rotDirection . x * Math . PI ,
232- rollError * Mathf . Deg2Rad
233- ) ;
234-
235- error . Scale ( _axisControl ) ;
236-
237- Vector3d err = error + inertia . Reorder ( 132 ) / 2d ;
238- err = new Vector3d (
239- Math . Max ( - Math . PI , Math . Min ( Math . PI , err . x ) ) ,
210+ fixedRoll ?
211+ ( ( delta . eulerAngles . z > 180 ) ?
212+ ( delta . eulerAngles . z - 360.0F ) :
213+ delta . eulerAngles . z ) * Math . PI / 180.0F
214+ : 0F
215+ ) ;
216+
217+ err += SwapYZ ( spinMargin ) ;
218+ err = new Vector3d ( Math . Max ( - Math . PI , Math . Min ( Math . PI , err . x ) ) ,
240219 Math . Max ( - Math . PI , Math . Min ( Math . PI , err . y ) ) ,
241220 Math . Max ( - Math . PI , Math . Min ( Math . PI , err . z ) ) ) ;
242-
243- err . Scale ( NormFactor ) ;
221+ err . Scale ( normFactor ) ;
244222
245223 // angular velocity:
246- Vector3d omega ;
247- omega . x = vessel . angularVelocity . x ;
248- omega . y = vessel . angularVelocity . z ; // y <=> z
249- omega . z = vessel . angularVelocity . y ; // z <=> y
250- omega . Scale ( NormFactor ) ;
251-
252- //if (Tf_autoTune)
253- // tuneTf(torque);
224+ Vector3d omega = SwapYZ ( vessel . GetComponent < Rigidbody > ( ) . angularVelocity ) ;
225+ omega . Scale ( normFactor ) ;
254226
255- Vector3d invTf = TfV . Invert ( ) ;
256- fc . pid . Kd = kdFactor * invTf ;
227+ Vector3d pidAction = fc . pid . Compute ( err , omega ) ;
257228
258- fc . pid . Kp = ( 1 / ( kpFactor * Math . Sqrt ( 2 ) ) ) * fc . pid . Kd ;
259- fc . pid . Kp . Scale ( invTf ) ;
260-
261- fc . pid . Ki = ( 1 / ( kiFactor * Math . Sqrt ( 2 ) ) ) * fc . pid . Kp ;
262- fc . pid . Ki . Scale ( invTf ) ;
263-
264- fc . pid . intAccum = fc . pid . intAccum . Clamp ( - 5 , 5 ) ;
265-
266- // angular velocity limit:
267- var Wlimit = new Vector3d ( Math . Sqrt ( NormFactor . x * Math . PI * kWlimit ) ,
268- Math . Sqrt ( NormFactor . y * Math . PI * kWlimit ) ,
269- Math . Sqrt ( NormFactor . z * Math . PI * kWlimit ) ) ;
270-
271- Vector3d pidAction = fc . pid . Compute ( err , omega , Wlimit ) ;
272-
273- // deadband
274- pidAction . x = Math . Abs ( pidAction . x ) >= deadband ? pidAction . x : 0.0 ;
275- pidAction . y = Math . Abs ( pidAction . y ) >= deadband ? pidAction . y : 0.0 ;
276- pidAction . z = Math . Abs ( pidAction . z ) >= deadband ? pidAction . z : 0.0 ;
277-
278- // low pass filter, wf = 1/Tf:
279- Vector3d act = fc . lastAct ;
280- act . x += ( pidAction . x - fc . lastAct . x ) * ( 1.0 / ( ( TfV . x / TimeWarp . fixedDeltaTime ) + 1.0 ) ) ;
281- act . y += ( pidAction . y - fc . lastAct . y ) * ( 1.0 / ( ( TfV . y / TimeWarp . fixedDeltaTime ) + 1.0 ) ) ;
282- act . z += ( pidAction . z - fc . lastAct . z ) * ( 1.0 / ( ( TfV . z / TimeWarp . fixedDeltaTime ) + 1.0 ) ) ;
229+ // low pass filter, wf = 1/Tf:
230+ Vector3d act = fc . lastAct + ( pidAction - fc . lastAct ) * ( 1 / ( ( fc . Tf / TimeWarp . fixedDeltaTime ) + 1 ) ) ;
283231 fc . lastAct = act ;
284232
285233 // end MechJeb import
@@ -333,6 +281,78 @@ private class Matrix3x3
333281 }
334282 }
335283
284+ /// <summary>
285+ /// Returns a more accurate moment of inertia than Vessel.findLocalMOI()
286+ /// </summary>
287+ // Copied from MechJeb master on June 27, 2014
288+ // TODO: cache moment if inertia and update only when ship mass changes?
289+ private static Vector3d GetTrueMoI ( Vessel vessel )
290+ {
291+ var inertiaTensor = new Matrix3x3 ( ) ;
292+ var centerOfMass = vessel . findWorldCenterOfMass ( ) ;
293+
294+ foreach ( Part p in vessel . parts )
295+ {
296+ if ( p . Rigidbody == null ) continue ;
297+
298+ //Compute the contributions to the vessel inertia tensor due to the part inertia tensor
299+ Vector3d principalMoments = p . Rigidbody . inertiaTensor ;
300+ Quaternion princAxesRot = Quaternion . Inverse ( vessel . GetTransform ( ) . rotation ) * p . transform . rotation * p . Rigidbody . inertiaTensorRotation ;
301+ Quaternion invPrincAxesRot = Quaternion . Inverse ( princAxesRot ) ;
302+
303+ for ( int i = 0 ; i < 3 ; i ++ )
304+ {
305+ Vector3d iHat = Vector3d . zero ;
306+ iHat [ i ] = 1 ;
307+ for ( int j = 0 ; j < 3 ; j ++ )
308+ {
309+ Vector3d jHat = Vector3d . zero ;
310+ jHat [ j ] = 1 ;
311+ inertiaTensor [ i , j ] += Vector3d . Dot ( iHat , princAxesRot * Vector3d . Scale ( principalMoments , invPrincAxesRot * jHat ) ) ;
312+ }
313+ }
314+
315+ //Compute the contributions to the vessel inertia tensor due to the part mass and position
316+ double partMass = p . mass + p . GetResourceMass ( ) ;
317+ Vector3 partPosition = vessel . GetTransform ( ) . InverseTransformDirection ( p . Rigidbody . worldCenterOfMass - centerOfMass ) ;
318+
319+ for ( int i = 0 ; i < 3 ; i ++ )
320+ {
321+ inertiaTensor [ i , i ] += partMass * partPosition . sqrMagnitude ;
322+
323+ for ( int j = 0 ; j < 3 ; j ++ )
324+ {
325+ inertiaTensor [ i , j ] += - partMass * partPosition [ i ] * partPosition [ j ] ;
326+ }
327+ }
328+ }
329+
330+ return new Vector3d ( inertiaTensor [ 0 , 0 ] , inertiaTensor [ 1 , 1 ] , inertiaTensor [ 2 , 2 ] ) ;
331+ }
332+
333+ /// <summary>
334+ /// Calculates how far a ship can rotate before its rotation stops.
335+ /// </summary>
336+ /// <returns>A vector equal to the stopping angle, in radians, around the (pitch, roll, yaw) axes.
337+ /// If it is impossible to stop the ship along one axis, returns 0 for that axis.</returns>
338+ /// <param name="vessel">The ship whose rotation needs to be stopped.</param>
339+ /// <param name="torque">The torque that can be applied to the ship.</param>
340+ public static Vector3d GetStoppingAngle ( Vessel vessel , Vector3d torque )
341+ {
342+ var momentOfInertia = GetTrueMoI ( vessel ) ;
343+ var angularVelocity = Quaternion . Inverse ( vessel . transform . rotation ) * vessel . GetComponent < Rigidbody > ( ) . angularVelocity ;
344+ var angularMomentum = Vector3d . Scale ( angularVelocity , momentOfInertia ) ;
345+
346+ // Adapted from MechJeb master on June 27, 2014
347+ Vector3d retVar ;
348+ retVar . x = ( torque . x != 0.0 ? angularMomentum . x * angularMomentum . x / ( torque . x * momentOfInertia . x ) : 0.0 ) ;
349+ retVar . y = ( torque . y != 0.0 ? angularMomentum . y * angularMomentum . y / ( torque . y * momentOfInertia . y ) : 0.0 ) ;
350+ retVar . z = ( torque . z != 0.0 ? angularMomentum . z * angularMomentum . z / ( torque . z * momentOfInertia . z ) : 0.0 ) ;
351+ retVar . Scale ( Sign ( angularMomentum ) ) ;
352+
353+ return retVar / 2 ;
354+ }
355+
336356 /// <summary>
337357 /// Returns the torque the ship can exert around its center of mass
338358 /// </summary>
0 commit comments