Advertisement
klassekatze

GyroECU5

Nov 14th, 2023
620
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.46 KB | None | 0 0
  1. using Sandbox.ModAPI.Ingame;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Data.Common;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using VRageMath;
  9.  
  10. namespace IngameScript
  11. {
  12.     partial class Program : MyGridProgram
  13.     {
  14.         public class GyroECU5
  15.         {
  16.             public static double gyroMaxRPM = Math.PI;
  17.  
  18.             public double angleMultiplier = 1;
  19.  
  20.             public GyroECU5() : base()
  21.             {
  22.                 angleMultiplier = gProgram.Me.CubeGrid.GridSizeEnum == VRage.Game.MyCubeSize.Small ? 2 : 1;
  23.                 gyroMaxRPM *= angleMultiplier;
  24.                 lastAngleRoll = lastAnglePitch = lastAngleYaw = 0;
  25.                 lMPTRoll = lMPTPitch = lMPTYaw = 0;
  26.             }
  27.             double lastAngleRoll, lastAnglePitch, lastAngleYaw;
  28.             double lMPTRoll, lMPTPitch, lMPTYaw;
  29.  
  30.             public bool active = false;
  31.             Vector3D targetPosition;
  32.             Vector3D targetVelocity;//currently unused
  33.  
  34.             Vector3D targetHeading;
  35.             Vector3D targetUp;
  36.  
  37.             public int startTick;
  38.             public int ticksOnTarget = 0;
  39.             private void flush()
  40.             {
  41.                 if (!active)
  42.                 {
  43.                     active = true;
  44.                     foreach (var g in gyros) g.GyroOverride = false;
  45.                     lG = null;
  46.                     startTick = tick;
  47.                     lastAngleRoll = lastAnglePitch = lastAngleYaw = 0;
  48.                     lMPTRoll = lMPTPitch = lMPTYaw = 0;
  49.                     ticksOnTarget = 0;
  50.                 }
  51.             }
  52.  
  53.             public void rotateToPosition(Vector3D tp, Vector3D tv = new Vector3D())
  54.             {
  55.                 if (!active) log("GECU test init rtp", LT.LOG_N);
  56.                 flush();
  57.                 targetPosition = tp;
  58.                 targetVelocity = tv;
  59.                 targetUp = getCtrl().WorldMatrix.Up;
  60.             }
  61.             public void rotateToHeading(Vector3D forward, Vector3D up = new Vector3D())
  62.             {
  63.                 if (up == Vector3D.Zero) up = getCtrl().WorldMatrix.Up;
  64.                 if (!active)
  65.                 {
  66.                     log("GECU test init rth", LT.LOG_N);
  67.                     log("forward:" + v2ss(forward), LT.LOG_N);
  68.                     log("up:" + v2ss(up), LT.LOG_N);
  69.                 }
  70.                 flush();
  71.                 targetPosition = targetVelocity = Vector3D.Zero;
  72.                 targetHeading = forward;
  73.                 targetUp = up;
  74.             }
  75.  
  76.             double error_thresholdLocked = ConvertDegreesToRadians(1);//we must be within this much on each axis
  77.             double minVelThresholdLocked = ConvertDegreesToRadians(1d);
  78.             //these only set qualifiers for ticksOnTarget.
  79.            
  80.             private void calculateAxisSpecificData(double now, ref double prior, ref double lastMPT, out bool braking, out double lastMPTActual, string p = "")//, out double ticksToStop, out double ticksToTarget)
  81.             {
  82.  
  83.                 var radMovedPerTick = Math.Abs(prior - now);
  84.                 var ticksToTarget = Math.Abs(now) / radMovedPerTick;
  85.                 var initVel = radMovedPerTick;
  86.                 var rateOfDecel = Math.Abs(lastMPT - radMovedPerTick);
  87.                 //if (rateOfDecel > mod) mod = rateOfDecel;
  88.  
  89.                 //if (Math.Abs(now) > nobrake_threshold) rateOfDecel *= 1.5;//overestimating here did not improve timings
  90.                 var ticksToStop = initVel / rateOfDecel;
  91.                 //mod - maximum observed decel - saved 0.1s on large sluggish ship but lost .3s on sg snappy ship.
  92.                 //sticking to the conservative metric
  93.  
  94.                 bool closing = Math.Abs(now) < Math.Abs(prior);
  95.                 lastMPTActual = radMovedPerTick;
  96.                 if (!closing)
  97.                 {
  98.                     lastMPT = 0.0001;
  99.                 }
  100.                 else lastMPT = radMovedPerTick;
  101.  
  102.                 if (closing)
  103.                 {
  104.                     if (ticksToStop > ticksToTarget + 1) braking = true;
  105.                     else braking = false;
  106.                 }
  107.                 else braking = false;
  108.                
  109.                 prior = now;
  110.             }
  111.  
  112.             //for distances under 90 degrees, it returns a value between 0 and gyromaxRPM, sharpened with sine so it levels off a bit in a nice way at the end.
  113.             //slightly black magic, but if it works, it works
  114.             static double amp_threshold = ConvertDegreesToRadians(100);//125.0d);
  115.             static double deAmp(double i)//, double spd)
  116.             {
  117.                 if (i == 0) return i;
  118.                 var abs = Math.Abs(i);
  119.                 var ig = i / abs * gyroMaxRPM;
  120.                 //spd = 0;
  121.                 if (abs > amp_threshold) return ig;
  122.                
  123.                 i = i / (amp_threshold);
  124.                 i = Math.Abs(i);
  125.                 i = Math.Sin(i);
  126.                 return i * ig;
  127.             }
  128.  
  129.             public static void setUpdateRate(int ups)
  130.             {
  131.                 updateRate = ups;
  132.                 updr_mult = 60 / updateRate;
  133.                 updr_mult_div = updr_mult / 60.0d;
  134.             }
  135.  
  136.             static int updateRate = 60;
  137.             static int updr_mult = 60 / updateRate;
  138.             static double updr_mult_div = 60.0d / updateRate / 60.0d;
  139.             int ltick = -1;
  140.             public void update()
  141.             {
  142.  
  143.                 if (active && tick - ltick > updr_mult)// && tick % 2 == 0)
  144.                 {
  145.                     ltick = tick;
  146.  
  147.                     if (!targetPosition.IsZero()) targetHeading = Vector3D.Normalize(targetPosition - getPosition());
  148.  
  149.                     double pitch, yaw, roll;
  150.                     GetRotationAnglesSimultaneous(targetHeading, targetUp, getCtrl().WorldMatrix, out yaw, out pitch, out roll);
  151.  
  152.                     double rA, pA, yA;
  153.  
  154.                     bool yB, pB, rB;
  155.                     calculateAxisSpecificData(roll, ref lastAngleRoll, ref lMPTRoll, out rB, out rA);
  156.                     calculateAxisSpecificData(pitch, ref lastAnglePitch, ref lMPTPitch, out pB, out pA);
  157.                     calculateAxisSpecificData(yaw, ref lastAngleYaw, ref lMPTYaw, out yB, out yA);
  158.  
  159.                     //Vector3D a_act = new Vector3D(pA, yA,rA);
  160.                     //var amax = a_act.AbsMax();
  161.                    
  162.                     Vector3D a_impulse = new Vector3D(pB ? 0 : pitch, yB ? 0 : yaw, rB ? 0 : roll);
  163.  
  164.                     //black magic everywhere
  165.                     a_impulse.X = deAmp(a_impulse.X);//, amax * updr_mult);
  166.                     a_impulse.Y = deAmp(a_impulse.Y);//, amax * updr_mult);
  167.                     a_impulse.Z = deAmp(a_impulse.Z);//, amax * updr_mult);
  168.                     if (Math.Abs(pA) / 60* updateRate > Math.Abs(a_impulse.X)) a_impulse.X = 0;
  169.                     if (Math.Abs(yA) / 60 * updateRate > Math.Abs(a_impulse.Y)) a_impulse.Y = 0;
  170.                     if (Math.Abs(rA) / 60 * updateRate > Math.Abs(a_impulse.Z)) a_impulse.Z = 0;
  171.  
  172.  
  173.                     GyroOverride(getCtrl().WorldMatrix, a_impulse.X, a_impulse.Y, a_impulse.Z);
  174.  
  175.                     if (Math.Abs(roll) < error_thresholdLocked && Math.Abs(pitch) < error_thresholdLocked && Math.Abs(yaw) < error_thresholdLocked)
  176.                     {
  177.                         if (rA < minVelThresholdLocked * updr_mult_div && pA < minVelThresholdLocked * updr_mult_div && yA < minVelThresholdLocked * updr_mult_div)
  178.                         {
  179.                             ticksOnTarget += 1;
  180.                         }
  181.                         else ticksOnTarget = 0;
  182.                     }
  183.                     else ticksOnTarget = 0;
  184.                 }
  185.             }
  186.  
  187.             IMyGyro lG = null;
  188.             static Vector3D state = new Vector3D(9, 9, 9);
  189.             const double E = MathHelper.EPSILON;
  190.             void GyroOverride(MatrixD shipRef, double pitch_speed, double yaw_speed, double roll_speed)
  191.             {
  192.                 IMyGyro g = null;
  193.                 foreach(var c in gyros)
  194.                 {
  195.                     if(c.Enabled && c.IsFunctional && !c.Closed)
  196.                     {
  197.                         g = c;
  198.                         break;
  199.                     }
  200.                 }
  201.                 if (g == null) return;
  202.  
  203.                 if(g != lG)
  204.                 {
  205.                     lG = g;
  206.                     state = new Vector3D(9, 9, 9);
  207.                     g.GyroOverride = true;
  208.                 }
  209.  
  210.                 var rotationVec = new Vector3D(-pitch_speed, yaw_speed, roll_speed); //because keen does some weird stuff with signs
  211.                 var relativeRotationVec = Vector3D.TransformNormal(rotationVec, shipRef);
  212.                 var trv = Vector3D.TransformNormal(relativeRotationVec, Matrix.Transpose(g.WorldMatrix));
  213.                
  214.                 if (trv.X != state.X)// && Math.Abs(trv.X - state.X) > E)
  215.                 {
  216.                     state.X = trv.X;
  217.                     g.Pitch = (float)(state.X);
  218.                 }
  219.                 if (trv.Y != state.Y)// && Math.Abs(trv.Y - state.Y) > E)
  220.                 {
  221.                     state.Y = trv.Y;
  222.                     g.Yaw = (float)(state.Y);
  223.                 }
  224.                 if (trv.Z != state.Z)// && Math.Abs(trv.Z - state.Z) > E)
  225.                 {
  226.                     state.Z = trv.Z;
  227.                     g.Roll = (float)(state.Z);
  228.                 }
  229.             }
  230.  
  231.             public void shutdown()
  232.             {
  233.                 if (active)
  234.                 {
  235.                     active = false;
  236.                     if(lG != null)lG.GyroOverride = false;
  237.                     log("GECU shutdown", LT.LOG_N);
  238.                     log("time: " + (tick - startTick) + "t (" + ((double)(tick - startTick) / 60).ToString("0.0") + "s)", LT.LOG_N);
  239.                 }
  240.             }
  241.         }
  242.     }
  243. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement