Advertisement
Whiplash141

Whip's Simple Missile Code

Dec 21st, 2017
3,163
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.55 KB | None | 0 0
  1. /*
  2. //Whip's Super Simple Missile Code for Rexxar v1 - 1/23/17
  3.  
  4. / //// /   SETUP    / //// /  
  5. You need at least:
  6. * A timer set to run this program and trigger now itself
  7. * A antenna
  8. * A thruster pointed forward
  9. * A remote
  10. * A program
  11. * A gyro
  12.  
  13. / //// /   FIRING INSTRUCTIONS  / //// /  
  14. Plug in a Vector3D or GPS coordinate into the argument and it will fly to that spot.
  15. */
  16.  
  17. //My magical PID constants
  18. const double proportionalConstant = 5;
  19. const double derivativeConstant = 2;
  20.  
  21. bool driftCompensation = true;
  22. //set this to false if u want the missiles to drift like ass
  23.  
  24.  
  25. // No touchey below
  26. IMyRemoteControl missileReference = null;
  27.  
  28. bool fireMissile = false;
  29. bool firstGuidance = true;
  30.  
  31. Vector3D targetPos = new Vector3D();
  32. Vector3D missilePos = new Vector3D();
  33. Vector3D gravVec = new Vector3D();
  34.  
  35. double lastYawAngle = 0;
  36. double lastPitchAngle = 0;
  37. double lastRollAngle = 0;
  38.  
  39. List<IMyThrust> thrust = new List<IMyThrust>();
  40. List<IMyThrust> forwardThrust = new List<IMyThrust>();
  41. List<IMyThrust> otherThrust = new List<IMyThrust>();
  42. List<IMyGyro> gyros = new List<IMyGyro>();
  43. List<IMyRemoteControl> remotes = new List<IMyRemoteControl>();
  44. List<IMyRadioAntenna> antennas = new List<IMyRadioAntenna>();
  45. List<IMyTimerBlock> timers = new List<IMyTimerBlock>();
  46.  
  47. void Main(string arg)
  48. {
  49.     var vector = new Vector3D();
  50.     var gps = new Vector3D();
  51.    
  52.    
  53.     bool isGPS = TryParseGPS(arg, out gps);
  54.  
  55.     if (isGPS)
  56.     {
  57.         Echo("GPS position recieved");
  58.         targetPos = gps;
  59.         if (!fireMissile)
  60.             fireMissile = true;
  61.        
  62.         Echo(targetPos.ToString());
  63.     }
  64.     else
  65.     {        
  66.         bool isVector = TryParseVector3D(arg, out vector);
  67.         if (isVector)
  68.         {
  69.             Echo("Vector position recieved");
  70.             targetPos = vector;
  71.             if (!fireMissile)
  72.                 fireMissile = true;
  73.            
  74.             Echo(targetPos.ToString());
  75.         }
  76.     }
  77.     if (fireMissile)
  78.     {        
  79.         bool isSetup = GetBlocks();
  80.  
  81.         if (isSetup)
  82.         {
  83.             GuideMissile(targetPos);
  84.             timers[0].ApplyAction("TriggerNow");
  85.         }
  86.     }
  87. }
  88.  
  89. bool TryParseGPS(string gpsString, out Vector3D vector)
  90. {
  91.     vector = new Vector3D(0,0,0);
  92.  
  93.     var gpsStringSplit = gpsString.Split(':');
  94.  
  95.     double x, y, z;
  96.    
  97.     if (gpsStringSplit.Length != 6)
  98.         return false;
  99.  
  100.     bool passX = double.TryParse(gpsStringSplit[2], out x);
  101.     bool passY  = double.TryParse(gpsStringSplit[3], out y);
  102.     bool passZ = double.TryParse(gpsStringSplit[4], out z);
  103.    
  104.     Echo($"{x},{y},{z}");
  105.  
  106.     if (passX && passY && passZ)
  107.     {
  108.         vector = new Vector3D(x, y, z);
  109.         return true;
  110.     }
  111.     else
  112.         return false;
  113. }
  114.  
  115. bool TryParseVector3D(string vectorString, out Vector3D vector)
  116. {
  117.     vector = new Vector3D(0, 0, 0);
  118.  
  119.     vectorString = vectorString.Replace(" ", "").Replace("{", "").Replace("}", "").Replace("X", "").Replace("Y", "").Replace("Z", "");
  120.     var vectorStringSplit = vectorString.Split(':');
  121.  
  122.     double x, y, z;
  123.  
  124.     if (vectorStringSplit.Length < 4)
  125.         return false;
  126.  
  127.     bool passX = double.TryParse(vectorStringSplit[1], out x);
  128.     bool passY = double.TryParse(vectorStringSplit[2], out y);
  129.     bool passZ = double.TryParse(vectorStringSplit[3], out z);
  130.  
  131.     if (passX && passY && passZ)
  132.     {
  133.         vector = new Vector3D(x, y, z);
  134.         return true;
  135.     }
  136.     else
  137.         return false;
  138. }
  139.  
  140. bool GetBlocks()
  141. {
  142.     bool successfulSetup = true;
  143.  
  144.     forwardThrust.Clear();
  145.     otherThrust.Clear();
  146.  
  147.     GridTerminalSystem.GetBlocksOfType(gyros);
  148.     GridTerminalSystem.GetBlocksOfType(thrust);
  149.     GridTerminalSystem.GetBlocksOfType(remotes);
  150.     GridTerminalSystem.GetBlocksOfType(antennas);
  151.     GridTerminalSystem.GetBlocksOfType(timers);
  152.  
  153.     if (gyros.Count == 0)
  154.     {
  155.         Echo($"Error: No gyros");
  156.         successfulSetup = false;
  157.     }
  158.  
  159.     if (thrust.Count == 0)
  160.     {
  161.         Echo($"Error: No thrust");
  162.         successfulSetup = false;
  163.     }
  164.  
  165.     if (remotes.Count == 0)
  166.     {
  167.         Echo($"Error: No remotes");
  168.         successfulSetup = false;
  169.     }
  170.  
  171.     if (antennas.Count == 0)
  172.     {
  173.         Echo($"Error: No antenna");
  174.         successfulSetup = false;
  175.     }
  176.  
  177.     if (timers.Count == 0)
  178.     {
  179.         Echo($"Error: No timers");
  180.         successfulSetup = false;
  181.     }
  182.  
  183.     if (successfulSetup)
  184.     {
  185.         missileReference = remotes[0];
  186.         GetThrusterOrientation(missileReference, thrust, out forwardThrust, out otherThrust);
  187.  
  188.        
  189.         var myID = Me.EntityId;
  190.         foreach (IMyRadioAntenna thisAntenna in antennas)
  191.         {
  192.             thisAntenna.SetValue("PBList", myID);
  193.             thisAntenna.SetValue("Radius", float.MaxValue);
  194.             thisAntenna.SetValue("EnableBroadCast", true);
  195.             thisAntenna.ApplyAction("OnOff_On");
  196.         }
  197.  
  198.         foreach(IMyThrust thisThrust in otherThrust)
  199.         {
  200.             thisThrust.ApplyAction("OnOff_On");
  201.         }
  202.  
  203.         foreach (IMyThrust thisThrust in forwardThrust)
  204.         {
  205.             thisThrust.ApplyAction("OnOff_On");
  206.             thisThrust.SetValue("Override", float.MaxValue);
  207.         }
  208.        
  209.     }
  210.  
  211.     return successfulSetup;
  212. }
  213.  
  214. void GetThrusterOrientation(IMyRemoteControl refBlock, List<IMyThrust> thrusters, out List<IMyThrust> _forwardThrust, out List<IMyThrust> _otherThrust)
  215. {
  216.     var forwardDirn = refBlock.WorldMatrix.Forward;
  217.  
  218.     _forwardThrust = new List<IMyThrust>();
  219.     _otherThrust = new List<IMyThrust>();
  220.  
  221.     foreach (IMyThrust thisThrust in thrusters)
  222.     {
  223.         var thrustDirn = thisThrust.WorldMatrix.Backward;
  224.         bool sameDirn = thrustDirn == forwardDirn;
  225.  
  226.         if (sameDirn)
  227.         {
  228.             _forwardThrust.Add(thisThrust);
  229.         }
  230.         else
  231.         {
  232.             _otherThrust.Add(thisThrust);
  233.         }
  234.     }
  235. }
  236.  
  237. void GuideMissile(Vector3D targetPos)
  238. {
  239.     missilePos = missileReference.GetPosition();
  240.  
  241.     //---Get orientation vectors of our missile
  242.     Vector3D missileFrontVec = missileReference.WorldMatrix.Forward;
  243.     Vector3D missileLeftVec = missileReference.WorldMatrix.Left;
  244.     Vector3D missileUpVec = missileReference.WorldMatrix.Up;
  245.  
  246.     //---Check if we have gravity
  247.     double rollAngle = 0; double rollSpeed = 0;
  248.  
  249.     var remote = remotes[0] as IMyRemoteControl;
  250.     bool inGravity = false;
  251.  
  252.     gravVec = missileReference.GetNaturalGravity();
  253.     double gravMagSquared = gravVec.LengthSquared();
  254.     if (gravMagSquared != 0)
  255.     {
  256.         if (gravVec.Dot(missileUpVec) < 0)
  257.         {
  258.             rollAngle = Math.PI / 2 - Math.Acos(MathHelper.Clamp(gravVec.Dot(missileLeftVec) / gravVec.Length(), -1, 1));
  259.         }
  260.         else
  261.         {
  262.             rollAngle = Math.PI + Math.Acos(MathHelper.Clamp(gravVec.Dot(missileLeftVec) / gravVec.Length(), -1, 1));
  263.         }
  264.  
  265.         if (firstGuidance) lastRollAngle = rollAngle;
  266.  
  267.         rollSpeed = Math.Round(proportionalConstant * rollAngle + derivativeConstant * (rollAngle - lastRollAngle) * 60, 2);
  268.  
  269.         inGravity = true;
  270.     }
  271.     else
  272.     {
  273.         rollSpeed = 0;
  274.     }
  275.  
  276.     //---Find vector from missile to destinationVec    
  277.     var missileToTargetVec = targetPos - missilePos;
  278.  
  279.     //---Get travel vector
  280.     var missileVelocityVec = missileReference.GetShipVelocities().LinearVelocity;
  281.  
  282.     //---Calc our new heading based upon our travel vector    
  283.  
  284.     var headingVec = CalculateHeadingVector(missileToTargetVec, missileVelocityVec, driftCompensation);
  285.    
  286.     //---Get pitch and yaw angles
  287.     double yawAngle; double pitchAngle;
  288.     GetRotationAngles(headingVec, missileFrontVec, missileLeftVec, missileUpVec, out yawAngle, out pitchAngle);
  289.  
  290.     if (firstGuidance)
  291.     {
  292.         lastPitchAngle = pitchAngle;
  293.         lastYawAngle = yawAngle;
  294.         firstGuidance = false;
  295.     }
  296.  
  297.     //---Angle controller
  298.     double yawSpeed = Math.Round(proportionalConstant * yawAngle + derivativeConstant * (yawAngle - lastYawAngle) * 60, 2);
  299.     double pitchSpeed = Math.Round(proportionalConstant * pitchAngle + derivativeConstant * (pitchAngle - lastPitchAngle) * 60, 2);
  300.  
  301.     //---Set appropriate gyro override
  302.     ApplyGyroOverride(pitchSpeed, yawSpeed, rollSpeed, gyros, missileReference);
  303.  
  304.     //---Store previous values
  305.     lastYawAngle = yawAngle;
  306.     lastPitchAngle = pitchAngle;
  307.     lastRollAngle = rollAngle;
  308.  
  309. }
  310.  
  311. Vector3D CalculateHeadingVector(Vector3D targetVec, Vector3D velocityVec, bool driftComp)
  312. {
  313.     if (!driftComp)
  314.     {
  315.         return targetVec;
  316.     }
  317.  
  318.     if (velocityVec.LengthSquared() < 100)
  319.     {
  320.         return targetVec;
  321.     }
  322.  
  323.     if (targetVec.Dot(velocityVec) > 0)
  324.     {
  325.         return VectorReflection(velocityVec, targetVec);
  326.     }
  327.     else
  328.     {
  329.         return -velocityVec;
  330.     }
  331. }
  332.  
  333. Vector3D VectorReflection(Vector3D a, Vector3D b) //reflect a over b    
  334. {
  335.     Vector3D project_a = VectorProjection(a, b);
  336.     Vector3D reject_a = a - project_a;
  337.     return project_a - reject_a;
  338. }
  339.  
  340. /*
  341. /// Whip's Get Rotation Angles Method v9 - 12/1/17 ///
  342. * Fix to solve for zero cases when a vertical target vector is input
  343. * Fixed straight up case
  344. */
  345. void GetRotationAngles(Vector3D v_target, Vector3D v_front, Vector3D v_left, Vector3D v_up, out double yaw, out double pitch)
  346. {
  347.     //Dependencies: VectorProjection() | VectorAngleBetween()
  348.     var projectTargetUp = VectorProjection(v_target, v_up);
  349.     var projTargetFrontLeft = v_target - projectTargetUp;
  350.  
  351.     yaw = VectorAngleBetween(v_front, projTargetFrontLeft);
  352.  
  353.     if (Vector3D.IsZero(projTargetFrontLeft) && !Vector3D.IsZero(projectTargetUp)) //check for straight up case
  354.         pitch = MathHelper.PiOver2;
  355.     else
  356.         pitch = VectorAngleBetween(v_target, projTargetFrontLeft); //pitch should not exceed 90 degrees by nature of this definition
  357.  
  358.     //---Check if yaw angle is left or right  
  359.     //multiplied by -1 to convert from right hand rule to left hand rule
  360.     yaw = -1 * Math.Sign(v_left.Dot(v_target)) * yaw;
  361.  
  362.     //---Check if pitch angle is up or down    
  363.     pitch = Math.Sign(v_up.Dot(v_target)) * pitch;
  364.  
  365.     //---Check if target vector is pointing opposite the front vector
  366.     if (Math.Abs(yaw) <= 1E-6 && v_target.Dot(v_front) < 0)
  367.     {
  368.         yaw = Math.PI;
  369.     }
  370. }
  371.  
  372. Vector3D VectorProjection(Vector3D a, Vector3D b)
  373. {
  374.     if (Vector3D.IsZero(b))
  375.         return Vector3D.Zero;
  376.  
  377.     return a.Dot(b) / b.LengthSquared() * b;  
  378. }
  379.  
  380. double VectorAngleBetween(Vector3D a, Vector3D b) //returns radians
  381. {
  382.     if (Vector3D.IsZero(a) || Vector3D.IsZero(b))
  383.         return 0;
  384.     else
  385.         return Math.Acos(MathHelper.Clamp(a.Dot(b) / Math.Sqrt(a.LengthSquared() * b.LengthSquared()), -1, 1));
  386. }
  387.  
  388. //Whip's ApplyGyroOverride Method v9 - 8/19/17
  389. void ApplyGyroOverride(double pitch_speed, double yaw_speed, double roll_speed, List<IMyGyro> gyro_list, IMyTerminalBlock reference)
  390. {
  391.     var rotationVec = new Vector3D(-pitch_speed, yaw_speed, roll_speed); //because keen does some weird stuff with signs
  392.     var shipMatrix = reference.WorldMatrix;
  393.     var relativeRotationVec = Vector3D.TransformNormal(rotationVec, shipMatrix);
  394.  
  395.     foreach (var thisGyro in gyro_list)
  396.     {
  397.         var gyroMatrix = thisGyro.WorldMatrix;
  398.         var transformedRotationVec = Vector3D.TransformNormal(relativeRotationVec, Matrix.Transpose(gyroMatrix));
  399.  
  400.         thisGyro.Pitch = (float)transformedRotationVec.X;
  401.         thisGyro.Yaw = (float)transformedRotationVec.Y;
  402.         thisGyro.Roll = (float)transformedRotationVec.Z;
  403.         thisGyro.GyroOverride = true;
  404.     }
  405. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement