Guest User

Untitled

a guest
Dec 17th, 2017
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.92 KB | None | 0 0
  1. #region pre-script
  2. using System;
  3. using System.Text;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using VRageMath;
  7. using VRage.Game;
  8. using Sandbox.ModAPI.Interfaces;
  9. using Sandbox.ModAPI.Ingame;
  10. using Sandbox.Game.EntityComponents;
  11. using VRage.Game.Components;
  12. using VRage.Collections;
  13. using VRage.Game.ObjectBuilders.Definitions;
  14. using VRage.Game.ModAPI.Ingame;
  15. using SpaceEngineers.Game.ModAPI.Ingame;
  16.  
  17. namespace IngameScript
  18. {
  19. public class Program : MyGridProgram
  20. {
  21. #endregion
  22.  
  23. static string reference_block = "Remote Control";
  24.  
  25. // GAINS
  26. static double proportionalGain = 5.0;
  27. static double integralGain = 0.1;
  28. static double derivativeGain = 0.1;
  29.  
  30. //OTHER PARAMETERS
  31. //static double integralLimit = 10; //limit the integral will be clamped to
  32. static double timeStep = 0.01; //time step between control inputs
  33. static double integralDecayFactor = 0.25; //Integral sum will reduce by this proportion each cycle
  34.  
  35. //Whip's PID controller class v4 - 8/27/17
  36. public class PID
  37. {
  38. double _kP = 0;
  39. double _kI = 0;
  40. double _kD = 0;
  41. double _integralDecayRatio = 0;
  42. double _lowerBound = 0;
  43. double _upperBound = 0;
  44. double _timeStep = 0;
  45. double _errorSum = 0;
  46. double _lastError = 0;
  47. bool _firstRun = true;
  48. bool _integralDecay = false;
  49. public double Value { get; private set; }
  50.  
  51. public PID(double kP, double kI, double kD, double lowerBound, double upperBound, double timeStep)
  52. {
  53. _kP = kP;
  54. _kI = kI;
  55. _kD = kD;
  56. _lowerBound = lowerBound;
  57. _upperBound = upperBound;
  58. _timeStep = timeStep;
  59. _integralDecay = false;
  60. }
  61.  
  62. public PID(double kP, double kI, double kD, double integralDecayRatio, double timeStep)
  63. {
  64. _kP = kP;
  65. _kI = kI;
  66. _kD = kD;
  67. _timeStep = timeStep;
  68. _integralDecayRatio = integralDecayRatio;
  69. _integralDecay = true;
  70. }
  71.  
  72. public double Control(double error)
  73. {
  74. //Compute derivative term
  75. var errorDerivative = (error - _lastError) / _timeStep;
  76.  
  77. if (_firstRun)
  78. {
  79. errorDerivative = 0;
  80. _firstRun = false;
  81. }
  82.  
  83. //Compute integral term
  84. if (!_integralDecay)
  85. {
  86. _errorSum += error * _timeStep;
  87.  
  88. //Clamp integral term
  89. if (_errorSum > _upperBound)
  90. _errorSum = _upperBound;
  91. else if (_errorSum < _lowerBound)
  92. _errorSum = _lowerBound;
  93. }
  94. else
  95. {
  96. _errorSum = _errorSum * (1.0 - _integralDecayRatio) + error * _timeStep;
  97. }
  98.  
  99. //Store this error as last error
  100. _lastError = error;
  101.  
  102. //Construct output
  103. this.Value = _kP * error + _kI * _errorSum + _kD * errorDerivative;
  104. return this.Value;
  105. }
  106.  
  107. public void Reset()
  108. {
  109. _errorSum = 0;
  110. _lastError = 0;
  111. _firstRun = true;
  112. }
  113. }
  114.  
  115. public class Gyroscope
  116. {
  117. //Hellothere_1's Fast Gyroscope Adjustment Code
  118. public IMyGyro gyro;
  119. public IMyTerminalBlock refer;
  120. private PID yaw_pid = new PID(proportionalGain, integralGain, derivativeGain, integralDecayFactor, timeStep);
  121. private PID pitch_pid = new PID(proportionalGain, integralGain, derivativeGain, integralDecayFactor, timeStep);
  122. private PID roll_pid = new PID(proportionalGain, integralGain, derivativeGain, integralDecayFactor, timeStep);
  123.  
  124. private int[] conversionVector = new int[3];
  125.  
  126. public Gyroscope(IMyGyro gyroscope, IMyTerminalBlock reference)
  127. {
  128. gyro = gyroscope;
  129. refer = reference;
  130.  
  131. for (int i = 0; i < 3; i++)
  132. {
  133. Vector3D vectorShip = GetAxis(i, reference);
  134.  
  135. for (int j = 0; j < 3; j++)
  136. {
  137. double dot = vectorShip.Dot(GetAxis(j, gyro));
  138.  
  139. if (dot > 0.9)
  140. {
  141. conversionVector[j] = i;
  142. break;
  143. }
  144. if (dot < -0.9)
  145. {
  146. conversionVector[j] = i + 3;
  147. break;
  148. }
  149. }
  150. }
  151. }
  152.  
  153. public void SetRotation(float[] rotationVector)
  154. {
  155. gyro.Pitch = rotationVector[conversionVector[0]];
  156. gyro.Yaw = rotationVector[conversionVector[1]];
  157. gyro.Roll = rotationVector[conversionVector[2]];
  158. }
  159.  
  160. private Vector3D GetAxis(int dimension, IMyTerminalBlock block)
  161. {
  162. switch (dimension)
  163. {
  164. case 0: return block.WorldMatrix.Right;
  165. case 1: return block.WorldMatrix.Up;
  166. default: return block.WorldMatrix.Backward;
  167. }
  168. }
  169.  
  170. public bool GotToOrientation(Matrix target)
  171. {
  172. Matrix current = remote.WorldMatrix;
  173.  
  174. const double half_pi = Math.PI / 2.0;
  175.  
  176. // Do product of normalized vector is cos between the vectors
  177. current.Forward.Normalize();
  178. current.Right.Normalize();
  179. current.Up.Normalize();
  180.  
  181. target.Forward.Normalize();
  182. target.Up.Normalize();
  183.  
  184. double cosx1x0 = current.Forward.Dot(target.Forward);
  185. double cosy1x0 = current.Right.Dot(target.Forward);
  186. double cosz1x0 = current.Up.Dot(target.Forward);
  187. double cosy1z0 = current.Right.Dot(target.Up);
  188. double cosz1z0 = current.Up.Dot(target.Up);
  189.  
  190. // Target angle between all those is 90 deg
  191. double yaw_rad_err = half_pi - Math.Acos(cosy1x0);
  192. double pitch_rad_err = half_pi - Math.Acos(cosz1x0);
  193. double roll_rad_err = Math.Acos(cosy1z0) - half_pi;
  194.  
  195. var yaw_ctrl = (float)yaw_pid.Control(yaw_rad_err);
  196. var pitch_ctrl = (float)pitch_pid.Control(pitch_rad_err);
  197. var roll_ctrl = (float)roll_pid.Control(roll_rad_err);
  198.  
  199. float[] controls = new float[] { -pitch_ctrl, yaw_ctrl, -roll_ctrl,
  200. pitch_ctrl, -yaw_ctrl, roll_ctrl };
  201.  
  202. SetRotation(controls);
  203.  
  204. double errx = Math.Abs(1.0 - cosx1x0);
  205. double errz = Math.Abs(1.0 - cosz1z0);
  206. const double epsilon = 0.0001; // below 1 deg
  207. if (errx < epsilon && errz < epsilon)
  208. {
  209. // Reached target, in case PID doesn't stop (0_0)
  210. gyro.GyroOverride = false;
  211. return true;
  212. }
  213.  
  214. gyro.GyroOverride = true;
  215. return false;
  216. }
  217. }
  218.  
  219. static List<Gyroscope> gyroscopes = new List<Gyroscope>();
  220. static int count = 0;
  221. static Matrix last_orientation = new Matrix();
  222. static IMyTerminalBlock remote;
  223. public Program()
  224. {
  225. //Runtime.UpdateFrequency = UpdateFrequency.Update1;
  226. List<IMyGyro> gyroblocks = new List<IMyGyro>();
  227. GridTerminalSystem.GetBlocksOfType<IMyGyro>(gyroblocks);
  228.  
  229. remote = GridTerminalSystem.GetBlockWithName(reference_block);
  230.  
  231. foreach (var gyroblock in gyroblocks)
  232. {
  233. gyroscopes.Add(new Gyroscope(gyroblock, remote));
  234. }
  235.  
  236. last_orientation = remote.WorldMatrix;
  237. Runtime.UpdateFrequency = UpdateFrequency.Once;
  238. }
  239.  
  240. static string Serialize(Matrix mat)
  241. {
  242. StringBuilder sb = new StringBuilder("[");
  243. for (int row = 0; row < 4; ++row)
  244. {
  245. for (int col = 0; col < 4; ++col)
  246. {
  247. sb.Append(mat[row, col]).Append(";");
  248. }
  249. }
  250. sb.Append("]");
  251. return sb.ToString();
  252. }
  253.  
  254. static Matrix Deserialize(string str)
  255. {
  256. Matrix mat = Matrix.Zero;
  257. // Remove the brackets and last semicolumn
  258. var substr = str.Substring(1, str.Length - 3);
  259.  
  260. // Separate the tokens
  261. var tokens = substr.Split(';');
  262. if (tokens.Length == 16)
  263. {
  264. for (int row = 0; row < 4; ++row)
  265. {
  266. for (int col = 0; col < 4; ++col)
  267. {
  268. mat[row, col] = Convert.ToSingle(tokens[row * 4 + col]);
  269. }
  270. }
  271. }
  272. return mat;
  273. }
  274.  
  275. public void Main(string argument, UpdateType updateSource)
  276. {
  277. Echo("Starting reorientation...");
  278. Matrix current_orientation = remote.WorldMatrix;
  279.  
  280. Echo("Current F: " + current_orientation.Forward.ToString());
  281. Echo("Target F: " + last_orientation.Forward.ToString());
  282.  
  283. Echo("Current U: " + current_orientation.Up.ToString());
  284. Echo("Target U: " + last_orientation.Up.ToString());
  285.  
  286. Echo("Iteration #" + count.ToString());
  287. foreach (var gyroscope in gyroscopes)
  288. {
  289. if (gyroscope.GotToOrientation(last_orientation))
  290. {
  291. Echo(gyroscope.gyro.DisplayName + " Reached destination");
  292. Runtime.UpdateFrequency = UpdateFrequency.None;
  293. }
  294. else
  295. {
  296. Runtime.UpdateFrequency = UpdateFrequency.Update1;
  297. }
  298. }
  299.  
  300. var str = Serialize(current_orientation);
  301. Echo("Sending: " + str.Replace(';','\n'));
  302. var antena = GridTerminalSystem.GetBlockWithName("Antenna") as IMyRadioAntenna;
  303. antena.TransmitMessage(str);
  304.  
  305. if (updateSource == UpdateType.Antenna)
  306. {
  307. var display = GridTerminalSystem.GetBlockWithName("Display") as IMyTextPanel;
  308. display.WritePublicText(argument);
  309. last_orientation = Deserialize(argument);
  310. display.ShowPublicTextOnScreen();
  311. }
  312. else
  313. {
  314. ++count;
  315. }
  316. }
  317.  
  318.  
  319. #region post-script
  320. }
  321. }
  322. #endregion
Add Comment
Please, Sign In to add comment