Advertisement
Whiplash141

Legacy Missile Guidance Code

Jun 15th, 2016
541
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 16.17 KB | None | 0 0
  1.  
  2. /*  
  3. Whip's GASP Missile Guidance Script - Revision 3 - 11/11/15
  4. /// PUBLIC RELEASE ///
  5. HOWDY!
  6. ___________________________________________________________________
  7. Video Instructions:
  8. https://www.youtube.com/watch?v=B4cLBJ-D0YQ
  9. ___________________________________________________________________
  10. Setup Instructions:  
  11.  
  12. The missile must be attached to the same grid as your firing
  13. platform via merge block, connector, or rotor.
  14.      
  15.   Missile Setup
  16.     1) Name all forward thrusters "Main Thruster 1"
  17.     2) Name all side thrusters "Side Thruster 1"
  18.     3) Name all missile batteries "Missile Battery 1"
  19.     4) Name all missile merges "Missile Merge 1"
  20.     5) Make a remote with name "Missile Reference 1" facing forward
  21.     6) Make a gyro(s) with name "Control 1" facing forward
  22.     7) Place this program on the missile
  23.     8) Place a timer on the missile
  24.        DO NOT TRIGGER IT YET!!!
  25.         - Make its runtime 1 second
  26.         - Set to trigger now itself
  27.         - Set to start itself (yes this is necessary)
  28.         - Set to run this program
  29.      
  30.   Shooter Ship Setup
  31.     1) Make a remote with name "Shooter Reference" facing forward
  32. ___________________________________________________________________
  33. Firing Instructions:
  34.      
  35. Trigger the timer you made in Step 8 and aim where you want  
  36. the missile to go! :)
  37. ___________________________________________________________________
  38. Setting Up Multiple Missiles:
  39.  
  40. To make additional missiles change the string "missile_number" on
  41. line 60 of the code to a different number. Now repeat the missile
  42. setup, replacing the number "1" with the new number you have set in
  43. the "missile_number" variable.
  44.  
  45. ___________________________________________________________________
  46. Author's Notes:
  47.  
  48. If you have any questions, comments, or concerns, feel free to leave a comment on          
  49. the workshop page: http://steamcommunity.com/sharedfiles/filedetails/?id=416932930          
  50.  
  51. - Whiplash141 :)  
  52. */  
  53.  
  54. /*
  55. ___________________________________________________________________
  56.  
  57. ========== You can edit these variables to your liking ============
  58. ___________________________________________________________________
  59. */
  60.     static string missile_number = "1"; //unique number id of the missile
  61.     string shooterReferenceName = "Shooter Reference"; //notice how this has no number
  62.     string missileReferenceName = "Missile Reference " + missile_number;
  63.     string gyroName = "Control " + missile_number;
  64.     string forwardThrustName = "Main Thruster " + missile_number;        
  65.     string maneuveringThrustersName = "Side Thruster " + missile_number;
  66.     string mergeName = "Missile Merge " + missile_number;  
  67.     string batteryName = "Missile Battery " + missile_number;
  68.    
  69.     double guidance_delay = 2; //time (in seconds) that the missile will delay guidance activation by
  70.     double max_rotation_degrees = 180; //in degrees per second (360 max for small ships, 180 max for large ships)  
  71.     double max_distance = 10000; //maximum guidance distance in meters; don't enlarge it lol, 10km is super far  
  72.     int tick_limit = 1; //change to higher for less precision (I do not reccomend this)
  73.  
  74. /*
  75. ___________________________________________________________________
  76.  
  77. ============= Don't touch anything below this :) ==================
  78. ___________________________________________________________________
  79. */
  80.     List<IMyTerminalBlock> remotes = new List<IMyTerminalBlock>();  
  81.     List<IMyTerminalBlock> shooterRefrenceList = new List<IMyTerminalBlock>();  
  82.     List<IMyTerminalBlock> missileRefrenceList = new List<IMyTerminalBlock>();  
  83.     List<IMyTerminalBlock> gyroList = new List<IMyTerminalBlock>();
  84.     List<IMyTerminalBlock> forwardThrusters = new List<IMyTerminalBlock>();                
  85.     List<IMyTerminalBlock> mergeBlocks = new List<IMyTerminalBlock>();          
  86.     List<IMyTerminalBlock> maneuveringThrusters = new List<IMyTerminalBlock>();      
  87.     List<IMyTerminalBlock> batteries = new List<IMyTerminalBlock>();      
  88.     IMyRemoteControl shooterRefrence;  
  89.     IMyRemoteControl missileRefrence;  
  90.     bool hasRun = false;  
  91.     double delta_origin;  
  92.     int current_tick = 0;  
  93.     int duration = 0;      
  94.     int timeElapsed = 0;      
  95.  
  96. void Main()  
  97. {    
  98.     Echo("Tick: " + current_tick.ToString());  
  99.     MissileSystems();
  100.      
  101.     if (!hasRun)  
  102.         GrabRemotes();  
  103.      
  104.     if (duration < Math.Ceiling(guidance_delay * 60))
  105.     {  
  106.         duration++;  
  107.         return;  
  108.     }  
  109.     else  
  110.     {  
  111.         if((current_tick % tick_limit) == 0)
  112.         {
  113.             Echo("Guidance Active");  
  114.             GuideMissile();  
  115.             current_tick = 0;  
  116.         }
  117.          
  118.     }        
  119.     current_tick++;  
  120.     Echo("Has run?: " + hasRun);
  121. }      
  122.  
  123. void GrabRemotes()  
  124. {  
  125.     GridTerminalSystem.SearchBlocksOfName(gyroName, gyroList);  
  126.     GridTerminalSystem.GetBlocksOfType<IMyRemoteControl>(remotes);  
  127.     for(int i = 0 ; i < remotes.Count ; i++)  
  128.         {  
  129.             var thisRemote = remotes[i] as IMyRemoteControl;  
  130.             if(thisRemote.CustomName.Contains(shooterReferenceName))  
  131.             {    
  132.                 shooterRefrenceList.Add(thisRemote as IMyRemoteControl);  
  133.                 Echo("Found Shooter");  
  134.             }  
  135.  
  136.             if(thisRemote.CustomName.Contains(missileReferenceName))  
  137.             {  
  138.                 missileRefrenceList.Add(thisRemote as IMyRemoteControl);  
  139.                 Echo("Found Missile");  
  140.             }  
  141.         }  
  142.  
  143. //---Check if we do not have an shooter remote  
  144.     if(shooterRefrenceList.Count == 0)  
  145.     {  
  146.         Echo("No shooter refrence block found");  
  147.         hasRun = false;  
  148.         return;  
  149.     }  
  150. //---Check if we do not have a missile remote  
  151.     else if(missileRefrenceList.Count == 0)  
  152.     {  
  153.         Echo("No missile refrence block found");  
  154.         hasRun = false;  
  155.         return;  
  156.     }  
  157.     else if(gyroList.Count == 0)  
  158.     {  
  159.         Echo("No control gyro found");  
  160.         hasRun = false;  
  161.         return;  
  162.     }  
  163.     else  
  164.     {    
  165.         Echo("Ready to run");  
  166.         shooterRefrence = shooterRefrenceList[0] as IMyRemoteControl;  
  167.         missileRefrence = missileRefrenceList[0] as IMyRemoteControl;  
  168.         hasRun = true;  
  169.     }  
  170. }  
  171.  
  172. void GuideMissile()    
  173. {    
  174. //---Get positions of our blocks with relation to world center  
  175.     var originPos = shooterRefrence.GetPosition();  
  176.     var missilePos = missileRefrence.GetPosition();  
  177.  
  178. //---Find current distance from shooter to missile  
  179.     delta_origin = Vector3D.Distance(originPos, missilePos);  
  180.  
  181. //---Check if we are in range      
  182.     if(delta_origin < max_distance) //change this later to be larger  
  183.     {  
  184.     //---Get forward vector from our shooter vessel  
  185.         var shooterForward = shooterRefrence.Position + Base6Directions.GetIntVector(shooterRefrence.Orientation.TransformDirection(Base6Directions.Direction.Forward));    
  186.         var targetVector = shooterRefrence.CubeGrid.GridIntegerToWorld(shooterForward);    
  187.         var targetVectorNorm = Vector3D.Normalize(targetVector - shooterRefrence.GetPosition());  
  188.  
  189.     //---Find vector from shooter to missile  
  190.         var missileVector = Vector3D.Subtract(missilePos, originPos);  
  191.  
  192.     //---Calculate angle between shooter vector and missile vector  
  193.         double dotProduct; Vector3D.Dot(ref targetVectorNorm, ref missileVector, out dotProduct);  
  194.         double x = dotProduct / missileVector.Length();      
  195.         double rawDevAngle = Math.Acos(x) * 180f / Math.PI; //angle between shooter vector and missile  
  196.  
  197.     //---Calculate perpendicular distance from shooter vector  
  198.         var projectionVector = dotProduct * targetVectorNorm;  
  199.         double deviationDistance = Vector3D.Distance(projectionVector,missileVector);  
  200.         Echo("Angular Dev: " + rawDevAngle.ToString());  
  201.  
  202.     //---Determine scaling factor
  203.         double scalingFactor;  
  204.         if(rawDevAngle < 90)  
  205.         {  
  206.             if(deviationDistance > 200)  
  207.             {  
  208.                 scalingFactor = delta_origin; //if we are too far from the beam, dont add any more distance till we are closer  
  209.             }  
  210.             else  
  211.             {  
  212.                 scalingFactor = (delta_origin + 200); //travel approx. 200m from current position in direction of target vector  
  213.             }  
  214.         }  
  215.         else  
  216.         {  
  217.             scalingFactor = 200; //if missile is behind the shooter, goes 200m directly infront of shooter for better accuracy  
  218.         }  
  219.         var destination = shooterRefrence.GetPosition() + scalingFactor * targetVectorNorm;  
  220.         Echo(destination.ToString()); //debug  
  221.  
  222.     //---Find front left and top vectors of our missileVector  
  223.         var missileGridX = missileRefrence.Position + Base6Directions.GetIntVector(missileRefrence.Orientation.TransformDirection(Base6Directions.Direction.Forward));  
  224.         var missileWorldX = missileRefrence.CubeGrid.GridIntegerToWorld(missileGridX) - missilePos;  
  225.  
  226.         var missileGridY = missileRefrence.Position + Base6Directions.GetIntVector(missileRefrence.Orientation.TransformDirection(Base6Directions.Direction.Left));  
  227.         var missileWorldY = missileRefrence.CubeGrid.GridIntegerToWorld(missileGridY) - missilePos;  
  228.  
  229.         var missileGridZ = missileRefrence.Position + Base6Directions.GetIntVector(missileRefrence.Orientation.TransformDirection(Base6Directions.Direction.Up));  
  230.         var missileWorldZ = missileRefrence.CubeGrid.GridIntegerToWorld(missileGridZ) - missilePos;  
  231.  
  232.     //---Find vector from missile to destination  
  233.         var shipToTarget = Vector3D.Subtract(destination, missilePos);  
  234.  
  235.     //---Project target vector onto our top left and up vectors  
  236.         double dotX; Vector3D.Dot(ref shipToTarget, ref missileWorldX, out dotX);  
  237.         double dotY; Vector3D.Dot(ref shipToTarget, ref missileWorldY, out dotY);  
  238.         double dotZ; Vector3D.Dot(ref shipToTarget, ref missileWorldZ, out dotZ);  
  239.         var projTargetX = dotX / (missileWorldX.Length() * missileWorldX.Length()) * missileWorldX;  
  240.         var projTargetY = dotY / (missileWorldY.Length() * missileWorldY.Length()) * missileWorldY;  
  241.         var projTargetZ = dotZ / (missileWorldZ.Length() * missileWorldZ.Length()) * missileWorldZ;  
  242.  
  243.     //---Get Yaw and Pitch Angles  
  244.         double angleYaw = Math.Atan(projTargetY.Length() / projTargetX.Length());  
  245.         double anglePitch = Math.Atan(projTargetZ.Length() / projTargetX.Length());  
  246.  
  247.     //---Check if x is positive or negative  
  248.         double checkPositiveX; Vector3D.Dot(ref missileWorldX, ref projTargetX, out checkPositiveX); Echo("check x:" + checkPositiveX.ToString());  
  249.         if(checkPositiveX < 0)  
  250.         {  
  251.             angleYaw += Math.PI/2; //we only change one value so it doesnt spaz  
  252.         }  
  253.  
  254.     //---Check if yaw angle is left or right  
  255.         double checkYaw; Vector3D.Dot(ref missileWorldY, ref projTargetY, out checkYaw); Echo("check yaw:" + checkYaw.ToString());  
  256.         if(checkYaw > 0) //yaw is backwards for what ever reason  
  257.             angleYaw = -angleYaw;  
  258.         Echo("yaw angle:" + angleYaw.ToString());  
  259.  
  260.     //---Check if pitch angle is up or down  
  261.         double checkPitch; Vector3D.Dot(ref missileWorldZ, ref projTargetZ, out checkPitch); Echo("check pitch:" + checkPitch.ToString());  
  262.         if(checkPitch < 0)  
  263.             anglePitch = -anglePitch;  
  264.         Echo("pitch angle:" + anglePitch.ToString());  
  265.  
  266.     //---Angle controller  
  267.         double max_rotation_radians = max_rotation_degrees * (Math.PI / 180);
  268.         double yawSpeed = max_rotation_radians * angleYaw / Math.Abs(angleYaw);
  269.         double pitchSpeed = max_rotation_radians * anglePitch / Math.Abs(anglePitch);
  270.  
  271.         //Alt method 1: Proportional Control
  272.         //(small ship gyros too weak for this to be effective)
  273.         /*
  274.             double yawSpeed = angleYaw / Math.PI * max_rotation_radians;  
  275.             double pitchSpeed = anglePitch / Math.PI * max_rotation_radians;
  276.         */
  277.          
  278.         //Alt method 2: Proportional Control with bounds
  279.         //(Small gyros still too weak :/)
  280.             /*if (angleYaw < Math.PI/4)  
  281.             {  
  282.                 yawSpeed = angleYaw * max_rotation_radians / (Math.PI/4);  
  283.             }  
  284.             else  
  285.             {  
  286.                 yawSpeed = max_rotation_radians;  
  287.             }  
  288.              
  289.             if (anglePitch < Math.PI/4)  
  290.             {  
  291.                 pitchSpeed = anglePitch * max_rotation_radians / (Math.PI/4);  
  292.             }  
  293.             else  
  294.             {  
  295.                 pitchSpeed = max_rotation_radians;  
  296.             }*/  
  297.  
  298.     //---Set appropriate gyro override
  299.         for(int i = 0; i < gyroList.Count; i++)  
  300.         {  
  301.             var thisGyro = gyroList[i] as IMyGyro;  
  302.             thisGyro.SetValue<float>("Yaw", (float)yawSpeed);  
  303.             thisGyro.SetValue<float>("Pitch", (float)pitchSpeed);  
  304.             thisGyro.SetValue("Override", true);  
  305.         }  
  306.     }  
  307.     else  
  308.     {  
  309.         Echo("Out of range");  
  310.         for(int i = 0; i < gyroList.Count; i++)  
  311.         {  
  312.             var thisGyro = gyroList[i] as IMyGyro;  
  313.             thisGyro.SetValue<float>("Yaw", 0f);  
  314.             thisGyro.SetValue<float>("Pitch", 0f);  
  315.             thisGyro.SetValue("Override", true);  
  316.         }  
  317.     }  
  318. }  
  319.  
  320. void MissileSystems()              
  321. {            
  322.     GridTerminalSystem.SearchBlocksOfName(mergeName,mergeBlocks);      
  323.     GridTerminalSystem.SearchBlocksOfName(batteryName,batteries);
  324.     GridTerminalSystem.SearchBlocksOfName(forwardThrustName,forwardThrusters);
  325.     GridTerminalSystem.SearchBlocksOfName(maneuveringThrustersName,maneuveringThrusters);
  326.  
  327. //---Check if we have merges  
  328.     if(mergeBlocks.Count == 0)
  329.     {
  330.         Echo("No missile merges found");
  331.         return;
  332.     }        
  333.  
  334. //---Check if we have batteries
  335.     if(batteries.Count == 0)
  336.     {
  337.         Echo("No missile batteries found");  
  338.         return;
  339.     }  
  340.  
  341. //---Check if we have main thrust
  342.     if(forwardThrusters.Count == 0)
  343.     {
  344.         Echo("No forward thrust found");
  345.         return;
  346.     }
  347.  
  348. //---Check if we have side thrust    
  349.     if(maneuveringThrusters.Count == 0)
  350.         Echo("No side thrust found");
  351.         //note how we do not stop the code for this one
  352.         //as side thrust is optional ( but highly reccomended )
  353.    
  354.  
  355. //---Activate battery, detach merge, and activate thrust
  356.     if (timeElapsed == 0)          
  357.     {          
  358.         for(int i = 0 ; i < batteries.Count ; i++)    
  359.         {    
  360.             var thisBattery = batteries[i] as IMyBatteryBlock;    
  361.             thisBattery.ApplyAction("OnOff_On");
  362.             thisBattery.SetValue("Recharge", false);  
  363.             thisBattery.SetValue("Discharge", true);
  364.         }          
  365.     }    
  366.     else if(timeElapsed == 60) //delay release by 1 second so power systems activate  
  367.     {      
  368.         for(int i = 0 ; i < mergeBlocks.Count ; i++)    
  369.         {    
  370.             var thisMerge = mergeBlocks[i] as IMyShipMergeBlock;    
  371.             thisMerge.ApplyAction("OnOff_Off");    
  372.         }  
  373.         ThrusterOverride();          
  374.         ManeuveringThrust();        
  375.         Echo("Detach Thrust Off");          
  376.         Echo("Thruster Override On");        
  377.     }          
  378.  
  379.     if (timeElapsed < 60)
  380.         timeElapsed++;          
  381. }
  382.  
  383. void ManeuveringThrust()        
  384. {              
  385.     for(int i = 0 ; i < maneuveringThrusters.Count ; i++)        
  386.     {        
  387.         IMyThrust Thrust = maneuveringThrusters[i] as IMyThrust;
  388.         Thrust.ApplyAction("OnOff_On");          
  389.     }        
  390. }        
  391.              
  392. void ThrusterOverride()          
  393. {                        
  394.     for(int i = 0; i < forwardThrusters.Count;i++)              
  395.     {                
  396.         IMyThrust Thrust = forwardThrusters[i] as IMyThrust;
  397.         Thrust.ApplyAction("OnOff_On");
  398.         Thrust.SetValue<float>("Override", float.MaxValue);              
  399.     }          
  400. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement