Guest User

Untitled

a guest
Sep 26th, 2019
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.29 KB | None | 0 0
  1. /*
  2. Script for automatic rotor stop when a solar panel or oxygen farm has high output.
  3. Version: 1.2
  4. Sigurd Hansen
  5.  
  6. This program vil autostart at compile. Use argument stop or start to manually override
  7.  
  8. */
  9. #region Configuration
  10.  
  11. // HighPwrValue - Set this to your minimum power requirement in kW per panel. (Or oxygen L/min)
  12. const float HighPwrValue = 119.4f;
  13.  
  14. // NameOfSolar - Search for solar blocks or oxygen farms with this name.
  15. // Maximum one item per array should be returned. Multiple arrays supported.
  16. const string NameOfSolar = "SolarV";
  17.  
  18. // NameOfRotorX - Search for rotor blocks with this name. Maximum one item per array should be returned.
  19. // Multiple arrays supported.
  20. const string NameOfRotorX = "motorV";
  21.  
  22. // rotorspeed - Maximum speed of rotor. Will be dynamically adjusted down when close to target.
  23. // Recommended value: Less that 1.0f due to ingame bug
  24. const float rotorspeed = 0.9f;
  25.  
  26. // EnableTwoAxisMode - Enable dual axis mode.
  27. // Recommended value: Depends on design.
  28. const bool EnableTwoAxisMode = false;
  29.  
  30. // NameOfRotorY - Search for this name for Y axis. Must only find Y axis rotors.
  31. // Maximum one item per array should be returned. Multiple arrays supported.
  32. const string NameOfRotorY = "RotorY";
  33.  
  34. // EnableOxygenMode - Enables oxygen mode.
  35. const bool EnableOxygenMode = false;
  36.  
  37. // Auto set torque and braking torque to best practice value.
  38. // Recommended value: true
  39. const bool ForceAutoTorque = true;
  40.  
  41. // Enable LCD Output
  42. const bool EnableLCD = true;
  43. const string NameOfLCD = "LCDSolarr";
  44.  
  45. // Duplication
  46. // Applying rotor values to other rotors as well if set to true.
  47. // If unsure, set all to false. Recommended value: Depends on design.
  48. const bool EnableDuplicateRotor1 = false;
  49. const bool EnableDuplicateRotor2 = false;
  50. const bool EnableDuplicateRotor3 = false;
  51.  
  52. // You might want to inverse some rotors, for example on the other side of the axis.
  53. // If so, set the value to true. If unsure change later if rotors lock at wrong angle.
  54. const bool InverseDuplicateRotor1 = false;
  55. const bool InverseDuplicateRotor2 = false;
  56. const bool InverseDuplicateRotor3 = false;
  57.  
  58. // Enter the name of the source rotors you want to duplicate.
  59. const string NameOfDuplicateSource1 = "RotorY";
  60. const string NameOfDuplicateSource2 = "RotorY";
  61. const string NameOfDuplicateSource3 = "RotorF";
  62.  
  63. // Enter the name of the destination rotors you want to duplicate.
  64. // The code will search for rotors. For example:
  65. // Entering RotorZ will duplicate changes to RotorZa, RotorZB, RotorZQ and so forth.
  66. const string SearchForDuplicateDest1 = "RotorZ";
  67. const string SearchForDuplicateDest2 = "RotorH";
  68. const string SearchForDuplicateDest3 = "RotorG";
  69.  
  70. // Auto night mode (Beta)
  71. // Turns off rotors if night is detected. Suboptimal axis towards sun might trigger night mode at daytime.
  72. // Use at your own risk. Not recommended for ships.
  73. const bool AutoNightMode = false;
  74.  
  75. // Trigger this timer at max power
  76. const bool ControlCustomTimerAtMaxPower = false;
  77. const string NameForCustomtriggerAtMaxPower = "Timer Lights On";
  78.  
  79. // Trigger this timer at low power
  80. const bool ControlCustomTimerAtLowPower = false;
  81. const string NameForCustomtriggerAtLowPower = "Timer Lights Off";
  82.  
  83. // Changes below this line not recommended.
  84. //------------------------------------------------------------
  85. #endregion
  86. List<IMyTerminalBlock> solarBlocks = new List<IMyTerminalBlock>();
  87. List<IMyTerminalBlock> rotorBlocksX = new List<IMyTerminalBlock>();
  88. List<IMyTerminalBlock> rotorBlocksY = new List<IMyTerminalBlock>();
  89. List<IMyTerminalBlock> Rotors = new List<IMyTerminalBlock>();
  90. List<IMyTerminalBlock> SourceRotors = new List<IMyTerminalBlock>();
  91. List<IMyTerminalBlock> LcdBlocks = new List<IMyTerminalBlock>();
  92. IMyTimerBlock timer2;
  93. IMyTimerBlock timer3;
  94. bool firstrun = true;
  95. bool nightmode = false;
  96. bool shortturn = false;
  97. long lCount = 0;
  98. int delayCount = 0;
  99. string textToLCD = "";
  100. float maxPwrValue;
  101.  
  102. public Program() {
  103. Runtime.UpdateFrequency |= UpdateFrequency.Update100;
  104. if (Storage.Length > 0) {
  105. string[] parts = Storage.Split(';');
  106. float.TryParse(parts[0], out maxPwrValue);
  107. }
  108. }
  109.  
  110. public void Save() {
  111. Storage = maxPwrValue + ";";
  112. //Echo("Saved: " + maxPwrValue.ToString());
  113. }
  114. #region Main
  115. void Main(string argument)
  116. {
  117. if (firstrun) {
  118. // Echo = text => {}; // Uncommenting this line might increase performance on servers. Will disable echo
  119. GridTerminalSystem.SearchBlocksOfName(NameOfSolar, solarBlocks); // Search for Solar Blocks
  120. GridTerminalSystem.SearchBlocksOfName(NameOfRotorX, rotorBlocksX); // Search for Rotor Blocks
  121. GridTerminalSystem.SearchBlocksOfName(NameOfRotorY, rotorBlocksY); // Search for RotorY Blocks
  122. if (EnableLCD) GridTerminalSystem.SearchBlocksOfName(NameOfLCD, LcdBlocks); // Search for LCD Blocks
  123. if (solarBlocks.Count == 0) { throw new Exception("Cannot find solar panel. Check name and recompile."); }
  124. if (rotorBlocksX.Count == 0) { throw new Exception("Cannot find x-axis rotor blocks. Check name and recompile."); }
  125. if (rotorBlocksY.Count == 0 && EnableTwoAxisMode) { throw new Exception("Cannot find y-axis rotor blocks. Check name and recompile."); }
  126. if (rotorBlocksY.Count < rotorBlocksX.Count && EnableTwoAxisMode) {
  127. int diff = rotorBlocksX.Count - rotorBlocksY.Count;
  128. throw new Exception(diff + " Y-axis rotors missing. Fix and recompile.");
  129. }
  130. if (solarBlocks.Count > rotorBlocksX.Count) { throw new Exception("Too many solar panels found. Check solar panel names."); }
  131. Echo ("Init...\nX rotors: " + rotorBlocksX.Count.ToString() + "\nY rotors: " + rotorBlocksY.Count.ToString());
  132. Echo ("Solar panels/Oxygen farms: " + solarBlocks.Count.ToString());
  133. if (EnableTwoAxisMode) Echo ("Dual Axis mode enabled");
  134. if (EnableOxygenMode) Echo ("Oxygen Farm mode ON");
  135. if (EnableDuplicateRotor1 || EnableDuplicateRotor2 || EnableDuplicateRotor3) Echo ("Duplication activated.");
  136. if (ControlCustomTimerAtMaxPower) timer2 = GridTerminalSystem.GetBlockWithName(NameForCustomtriggerAtMaxPower) as IMyTimerBlock;
  137. if (ControlCustomTimerAtLowPower) timer3 = GridTerminalSystem.GetBlockWithName(NameForCustomtriggerAtLowPower) as IMyTimerBlock;
  138.  
  139. firstrun = false;
  140. }
  141. if (argument == "start") Runtime.UpdateFrequency |= UpdateFrequency.Update100;
  142. else if (argument == "stop") Runtime.UpdateFrequency &= ~UpdateFrequency.Update100;
  143. lCount++;
  144. if (lCount == 3) {
  145. lCount = 0;
  146. shortturn = false;
  147. } else {
  148. shortturn = true;
  149. //return;
  150. }
  151. textToLCD = "Auto Optimize Solar Panels / Oxygen farm\n";
  152. bool[] rotorOn = new bool[rotorBlocksX.Count]; // Stop or start rotor
  153. bool[] rotorLow = new bool[rotorBlocksX.Count]; // True when power is way to low
  154. bool[] rotorFineTune = new bool[rotorBlocksX.Count]; // Fine Tune, very slow rotor
  155. bool[] reverse = new bool[rotorBlocksX.Count]; // Reverse rotor
  156. bool[] rotorOnY = new bool[rotorBlocksY.Count]; // Stop or start rotor
  157. bool containsFalse = false;
  158. float pwr = 0f, lastPwr = 0f; // Current and last power reading
  159.  
  160. if (EnableOxygenMode) {
  161. for(int i = 0; i < solarBlocks.Count; i++) { // For each oxygen farm...
  162. var solar = solarBlocks[i] as IMyOxygenFarm; // Support for oxygen farm
  163. if(solar != null) { // Yes I am
  164. GetOxygen(solar, ref pwr); // Get oxygen level, return into existing pwr variable
  165. lastPwr = GetAndSetLastOxygen(solar, pwr); // Get and set last runs oxygen level
  166. reverse[i] = (lastPwr < pwr || pwr == 0) ? false : true; // Change rotor direction
  167. rotorOn[i] = (pwr <= HighPwrValue) ? true : false; // Turn on rotor
  168. rotorLow[i] = (pwr < HighPwrValue/2) ? true : false; // Slow or fast rotor
  169. rotorFineTune[i] = (pwr > HighPwrValue*10/11) ? true : false; // Fine tune rotor
  170. }
  171. }
  172. } else {
  173. for(int i = 0; i < solarBlocks.Count; i++) { // For each solar panel...
  174. var solar = solarBlocks[i] as IMySolarPanel; // I am a Solar Panel
  175. if(solar != null) { // Yes I am
  176. GetPower(solar, ref pwr); // Get Power from solar panel, return into existing pwr variable
  177. lastPwr = GetAndSetLastPwr(solar, pwr); // Get and set last runs power
  178. reverse[i] = (lastPwr < pwr || pwr == 0) ? false : true; // Change rotor direction
  179. rotorOn[i] = (pwr <= HighPwrValue) ? true : false; // Turn on rotor
  180. rotorLow[i] = (pwr < HighPwrValue/2) ? true : false; // Slow or fast rotor
  181. rotorFineTune[i] = (pwr > HighPwrValue*10/11) ? true : false; // Fine tune rotor
  182. if (lastPwr == 0 && pwr == 0 && AutoNightMode || Me.TerminalRunArgument == "Nightmode") { // TEST
  183. nightmode = true;
  184. } else {
  185. nightmode = false;
  186. }
  187. }
  188. }
  189. }
  190. if (shortturn) return;
  191.  
  192. if (nightmode) {
  193. textToLCD += "Night mode\n";
  194. // TODO
  195. }
  196.  
  197. for(int i = 0; i < rotorBlocksX.Count; i++) { // For each rotorX...
  198. IMyMotorStator rotor = rotorBlocksX[i] as IMyMotorStator; // I am a Rotor
  199. if(rotor != null) { // Yes I am
  200. if (ForceAutoTorque) { // Force torque.
  201. rotor.BrakingTorque = float.MaxValue;
  202. rotor.Torque = 30000000f;
  203. }
  204. if (nightmode) {
  205. TriggerRotor(rotor, false, false, ref containsFalse); // Stop rotor
  206. } else {
  207. SetRotorSpeed(rotor, rotorLow[i], rotorFineTune[i]); // Dynamic rotor speed
  208. if (!rotorOn[i]) { // Turn off...
  209. TriggerRotor(rotor, false, false, ref containsFalse); // Stop rotor
  210. } else if (rotorOn[i] && EnableTwoAxisMode && reverse[i]) { // Turn On, dual axis mode, and reverse
  211. rotorOnY[i] = CheckAndUpdateRotorName(rotor);
  212. if (rotorOnY[i]) {
  213. TriggerRotor(rotor, false, false, ref containsFalse); // Y on, therefore X off.
  214. }
  215.  
  216. if (!rotorOnY[i]) {
  217. TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Y off, therefore X on, and reverse.
  218. }
  219. } else if (rotorOn[i] && EnableTwoAxisMode && !reverse[i]) {
  220. rotorOnY[i] = CheckAndUpdateRotorName(rotor);
  221. if (!rotorOnY[i]) {
  222. TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Start rotor. Reverse if needed
  223. }
  224. } else {
  225. TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Start rotor. Reverse if needed
  226. }
  227. }
  228. }
  229. }
  230.  
  231. if (EnableTwoAxisMode) {
  232. for(int i = 0; i < rotorBlocksY.Count; i++) { // For each rotorY...
  233. IMyMotorStator rotor = rotorBlocksY[i] as IMyMotorStator; // I am a Rotor
  234. if(rotor != null) { // Yes I am
  235. if (ForceAutoTorque) {
  236. rotor.BrakingTorque = float.MaxValue;
  237. rotor.Torque = 30000000f;
  238. }
  239. if (nightmode) {
  240. TriggerRotor(rotor, false, false, ref containsFalse); // Stop rotor
  241. } else {
  242. if (rotorOnY[i] == true) {
  243. SetRotorSpeed(rotor, rotorLow[i], rotorFineTune[i]); // Dynamic rotor speed
  244. TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Start rotor Y. Reverse if needed
  245. } else {
  246. TriggerRotor(rotor, false, false, ref containsFalse);
  247. }
  248. }
  249. }
  250. }
  251. }
  252. textToLCD += "Max Power detected: " + maxPwrValue.ToString() + "\n";
  253.  
  254. //textToLCD += "CurrentInstructionCount: " + Runtime.CurrentInstructionCount.ToString() + " / " + Runtime.MaxInstructionCount.ToString()+ "\n";
  255. //textToLCD += "TimeSinceLastRun: " + Runtime.TimeSinceLastRun.ToString() + "\n";
  256.  
  257.  
  258. // Duplicate stuff
  259. if (EnableDuplicateRotor3 && !containsFalse) { // Main rotors aligned, lets duplicate changes...
  260. RotorDuplicate(NameOfDuplicateSource3, SearchForDuplicateDest3, InverseDuplicateRotor3);
  261. }
  262. if (EnableDuplicateRotor2 && !containsFalse) { // Main rotors aligned, lets duplicate changes...
  263. RotorDuplicate(NameOfDuplicateSource2, SearchForDuplicateDest2, InverseDuplicateRotor2);
  264. }
  265. if (EnableDuplicateRotor1 && !containsFalse) { // Main rotors aligned, lets duplicate changes...
  266. RotorDuplicate(NameOfDuplicateSource1, SearchForDuplicateDest1, InverseDuplicateRotor1);
  267. }
  268. if (!containsFalse && ControlCustomTimerAtMaxPower) { // Main rotors aligned, lets control a timer
  269. delayCount = 0;
  270. ControlTimer(timer2);
  271. }
  272. if (containsFalse && ControlCustomTimerAtLowPower){
  273. delayCount++;
  274. if (delayCount == 5) {
  275. delayCount = 0;
  276. ControlTimer(timer3);
  277. }
  278. }
  279.  
  280. if (EnableLCD) PrintToLCD(textToLCD);
  281. }
  282.  
  283. #endregion
  284. #region Methods
  285.  
  286. void PrintToLCD(string text) {
  287. if (EnableLCD) {
  288. for(int i = 0; i < LcdBlocks.Count; i++) { // For each LCD...
  289. IMyTextPanel LCD = LcdBlocks[i] as IMyTextPanel;
  290. LCD.WriteText(text, false);
  291. LCD.SetValue("FontSize", 0.9f);
  292. LCD.ContentType = ContentType.TEXT_AND_IMAGE;
  293. //((IMyTextSurface)DisplayBlock).ContentType = ContentType.TEXT_AND_IMAGE; // instead of ShowPublicTextOnScreen()
  294. //LCD.ShowTextOnScreen();
  295. }
  296. }
  297. }
  298. void ControlTimer(IMyTimerBlock thistimer) {
  299. thistimer.ApplyAction("TriggerNow");
  300. }
  301.  
  302. void TriggerRotor(IMyMotorStator rotor, bool state, bool reverse, ref bool containsFalse) {
  303. if (!state) {
  304. rotor.ApplyAction("OnOff_Off"); // Stop rotor
  305. } else {
  306. rotor.ApplyAction("OnOff_On"); // Start rotor
  307. containsFalse = true;
  308. if (reverse) { rotor.ApplyAction("Reverse"); }
  309. }
  310. }
  311.  
  312. void GetPower(IMySolarPanel solar, ref float pwr) {
  313. pwr = solar.MaxOutput * 1000;
  314. float test = pwr / HighPwrValue * 100f;
  315. decimal test2 = Math.Round((decimal)test);
  316. textToLCD += "Current power: " + pwr.ToString() + " kWh (" + test2.ToString() + " %)\n";
  317. if (!EnableLCD) Echo(pwr.ToString() + " kWh");
  318. if ( pwr > maxPwrValue) {
  319. maxPwrValue = pwr;
  320. //HighPwrValue = maxPwrValue;
  321. }
  322. }
  323.  
  324. void GetOxygen(IMyOxygenFarm solar, ref float pwr) {
  325. pwr = solar.GetOutput()* 1.8f;
  326. if ( pwr > maxPwrValue) {
  327. maxPwrValue = pwr;
  328. }
  329. if (!EnableLCD) Echo(pwr.ToString() + " L/min");
  330. }
  331.  
  332. float RotorPosition(IMyMotorStator Rotor) {
  333. if (Rotor == null) {
  334. Echo( "Rotor not found. Returning 0");
  335. return 0;
  336. }
  337. return (float)Math.Round(Rotor.Angle * (180.0 / Math.PI), 0);
  338. }
  339.  
  340. void RotorDuplicate(string SourceRotorName, string RotorName, bool Inverse) {
  341. GridTerminalSystem.SearchBlocksOfName(SourceRotorName, SourceRotors); // Search for Solar Source Blocks
  342. IMyMotorStator SourceRotor = SourceRotors[0] as IMyMotorStator; // I am a Rotor
  343. float SetPosition = RotorPosition(SourceRotor);
  344. GridTerminalSystem.SearchBlocksOfName(RotorName, Rotors); // Search for Solar Blocks
  345. if (Rotors.Count == 0) {
  346. Echo("Cannot find any duplicate destination rotors.");
  347. return;
  348. }
  349. if (Inverse) {
  350. SetPosition = -SetPosition;
  351. }
  352. for(int i = 0; i < Rotors.Count; i++) { // For each rotor...
  353. IMyMotorStator Rotor = Rotors[i] as IMyMotorStator; // I am a Rotor
  354. float DestPosition = RotorPosition(Rotor);
  355. if (ForceAutoTorque) {
  356. Rotor.BrakingTorque = float.MaxValue;
  357. Rotor.Torque = 10000000f;
  358. }
  359. Rotor.SetValueFloat("LowerLimit",SetPosition);
  360. Rotor.SetValueFloat("UpperLimit",SetPosition);
  361. textToLCD += "Duplication #" + i + ": ";
  362. if (SetPosition == DestPosition) {
  363. Rotor.TargetVelocityRPM = 0f;
  364. Rotor.ApplyAction("OnOff_Off"); // Stop rotor
  365. textToLCD += "Locked\n";
  366. } else if (SetPosition < DestPosition) {
  367. Rotor.ApplyAction("OnOff_On"); // Start rotor
  368. Rotor.TargetVelocityRPM = -rotorspeed;
  369. textToLCD += "Running\n";
  370. } else if (SetPosition > DestPosition) {
  371. Rotor.ApplyAction("OnOff_On"); // Start rotor
  372. Rotor.TargetVelocityRPM = rotorspeed;
  373. textToLCD += "Running\n";
  374. }
  375. }
  376. }
  377.  
  378. void SetRotorSpeed(IMyMotorStator rotor, bool fast, bool FineTune) {
  379. float SetTo = 0f;
  380. bool VelocityPositive = (rotor.TargetVelocityRPM > 0f) ? true : false; // True if positive velocity
  381. if (fast) { // Under half of required power from solar panel. Will increase speed
  382. SetTo = (VelocityPositive) ? rotorspeed : -rotorspeed;
  383. } else if (FineTune) { // Fine tune speed
  384. SetTo = (VelocityPositive) ? rotorspeed/3.7f : -rotorspeed/3.7f;
  385. } else { // Not far from required power. Lower speed for increased accuracy
  386. SetTo = (VelocityPositive) ? rotorspeed/1.7f : -rotorspeed/1.7f;
  387. }
  388. rotor.TargetVelocityRPM = SetTo;
  389. }
  390.  
  391. float GetAndSetLastPwr(IMySolarPanel solar, float CurrentPower) {
  392. float OldPwr = 0f;
  393. string[] words = solar.CustomName.Split(':'); // Colon split words
  394. if (words.Length > 1) { // If there is data after colon
  395. if (!float.TryParse(words[1], out OldPwr)) { OldPwr = 0f;} // Try to get data into float variable
  396. }
  397. solar.CustomName = (words[0] + ":" + CurrentPower); // Set current power in solar panel name
  398. return OldPwr;
  399. }
  400. float GetAndSetLastOxygen(IMyOxygenFarm solar, float CurrentPower) {
  401. float OldPwr = 0f;
  402. string[] words = solar.CustomName.Split(':'); // Colon split words
  403. if (words.Length > 1) { // If there is data after colon
  404. if (!float.TryParse(words[1], out OldPwr)) { OldPwr = 0f;} // Try to get data into float variable
  405. }
  406. solar.CustomName = (words[0] + ":" + CurrentPower); // Set current power in solar panel name
  407. return OldPwr;
  408. }
  409.  
  410. bool CheckAndUpdateRotorName(IMyMotorStator rotor) {
  411. int OldCount = 0;
  412. string[] words = rotor.CustomName.Split(':'); // Colon split words
  413. if (words.Length > 1) { // If there is data after colon
  414. if (!int.TryParse(words[1], out OldCount)) { OldCount = 0;} // Try to get data into int variable
  415. }
  416. int NewCount = OldCount + 1;
  417. if (OldCount > 6) {
  418. rotor.CustomName = (words[0] + ":0");
  419. return true;
  420. }
  421. else if (OldCount >= 3) {
  422. rotor.CustomName = (words[0] + ":" + NewCount); // Set current count in rotor name
  423. return true;
  424. } else {
  425. rotor.CustomName = (words[0] + ":" + NewCount); // Set current count in rotor name
  426. return false;
  427. }
  428. }
  429. #endregion
Advertisement
Add Comment
Please, Sign In to add comment