Advertisement
Guest User

SE Solar Script

a guest
Jan 10th, 2016
500
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.84 KB | None | 0 0
  1. /*
  2. Script for automatic rotor stop when a solar panel or oxygen farm has high output.
  3. Version: 1.03
  4. Sigurd Hansen
  5. */
  6. #region Configuration
  7. // HighPwrValue - Set this to your minimum power requirement in kW per panel. (Or oxygen L/min)
  8. const float HighPwrValue = 119f;
  9.  
  10. // NameOfSolar - Search for solar blocks or oxygen farms with this name.
  11. // Maximum one item per array should be returned. Multiple arrays supported.
  12. const string NameOfSolar = "Solar Panel Main";
  13.  
  14. // NameOfRotorX - Search for rotor blocks with this name. Maximum one item per array should be returned.
  15. // Multiple arrays supported.
  16. const string NameOfRotorX = "Solar Rotor X";
  17.  
  18. // rotorspeed - Maximum speed of rotor. Will be dynamically adjusted down when close to target.
  19. // Recommended value: Less than 1.8f. Dedicated servers and large arrays may work better with a lower speed setting.
  20. const float rotorspeed = 0.5f;
  21.  
  22. // EnableTimerMgmt - Enable dynamic timer trigger management for better accuracy and performance.
  23. // Recommended value: true
  24. const bool EnableTimerMgmt = true;
  25.  
  26. // NameOfTimer - Set this to the timer responsible for triggering this program.
  27. // Timer should start this programming block, then start itself.
  28. const string NameOfTimer = "Solar Timer";
  29.  
  30. // TimerIdleDelay - Delay of timer when idle. Do not remove "f".
  31. const float TimerIdleDelay = 8f;
  32.  
  33. // TimerActiveDelay - Delay of timer when active. Do not remove "f".
  34. // Recommended value: 2f. NEVER set below 2.
  35. const float TimerActiveDelay = 2f;
  36.  
  37. // EnableTwoAxisMode - Enable dual axis mode.
  38. // Recommended value: true
  39. const bool EnableTwoAxisMode = true;
  40.  
  41. // NameOfRotorY - Search for this name for Y axis. Must only find Y axis rotors.
  42. // Maximum one item per array should be returned. Multiple arrays supported.
  43. const string NameOfRotorY = "Solar Rotor Y";
  44.  
  45. // EnableOxygenMode - Enables oxygen mode.
  46. const bool EnableOxygenMode = false;
  47.  
  48. // Auto set torque and braking torque to best practice value.
  49. // Recommended value: true
  50. const bool ForceAutoTorque = true;
  51.  
  52. // Applying rotor values to other rotors as well if set to true.
  53. // NameOfDuplicateSource1/2/3 is the source and should only contain one rotor.
  54. // SearchForDuplicateDest1/2/3 is the destination and the search can contain multiple results.
  55. // Make sure the search for Dest1/2/3 results DO NOT FIND the same rotors as above.
  56. // The duplication process will only start when HighPwrValue is achieved on NameOfSolar
  57. const bool EnableDuplicateRotor1 = true;
  58. const bool EnableDuplicateRotor2 = true;
  59. const bool EnableDuplicateRotor3 = true;
  60. const bool InverseDuplicateRotor1 = false; // Other side of axis might need to be inverse.
  61. const bool InverseDuplicateRotor2 = false; // Other side of axis might need to be inverse.
  62. const bool InverseDuplicateRotor3 = true; // Other side of axis might need to be inverse.
  63. const string NameOfDuplicateSource1 = "Solar Rotor X";
  64. const string SearchForDuplicateDest1 = "Solar Rotor X 1";
  65. const string NameOfDuplicateSource2 = "Solar Rotor Y";
  66. const string SearchForDuplicateDest2 = "Solar Rotor Y 1";
  67. const string NameOfDuplicateSource3 = "Solar Rotor Y";
  68. const string SearchForDuplicateDest3 = "Solar Rotor Y 2";
  69.  
  70. // Auto night mode
  71. // Turns off rotors if night is detected
  72. const bool AutoNightMode = true;
  73.  
  74. // Changes below this line not recommended.
  75. //------------------------------------------------------------
  76. #endregion
  77. List<IMyTerminalBlock> solarBlocks = new List<IMyTerminalBlock>();
  78. List<IMyTerminalBlock> rotorBlocksX = new List<IMyTerminalBlock>();
  79. List<IMyTerminalBlock> rotorBlocksY = new List<IMyTerminalBlock>();
  80. List<IMyTerminalBlock> Rotors = new List<IMyTerminalBlock>();
  81. List<IMyTerminalBlock> SourceRotors = new List<IMyTerminalBlock>();
  82. IMyTimerBlock timer;
  83.  
  84. bool firstrun = true;
  85. bool nightmode = false; // TEST
  86.  
  87. #region Main
  88. void Main()
  89. {
  90. if (firstrun) {
  91. GridTerminalSystem.SearchBlocksOfName(NameOfSolar, solarBlocks); // Search for Solar Blocks
  92. GridTerminalSystem.SearchBlocksOfName(NameOfRotorX, rotorBlocksX); // Search for Rotor Blocks
  93. GridTerminalSystem.SearchBlocksOfName(NameOfRotorY, rotorBlocksY); // Search for RotorY Blocks
  94. timer = GridTerminalSystem.GetBlockWithName(NameOfTimer) as IMyTimerBlock;
  95. if (timer == null && EnableTimerMgmt) { throw new Exception("Cannot find timer. Check timer name and recompile."); }
  96. if (solarBlocks.Count == 0) { throw new Exception("Cannot find solar panel. Check name and recompile."); }
  97. if (rotorBlocksX.Count == 0) { throw new Exception("Cannot find x-axis rotor blocks. Check name and recompile."); }
  98. if (rotorBlocksY.Count == 0 && EnableTwoAxisMode) { throw new Exception("Cannot find y-axis rotor blocks. Check name and recompile."); }
  99. if (rotorBlocksY.Count < rotorBlocksX.Count && EnableTwoAxisMode) {
  100. int diff = rotorBlocksX.Count - rotorBlocksY.Count;
  101. throw new Exception(diff + " Y-axis rotors missing. Fix and recompile.");
  102. }
  103. if (solarBlocks.Count > rotorBlocksX.Count) { throw new Exception("Too many solar panels found. Check solar panel names."); }
  104. Echo ("Initializing core...\nX rotors: " + rotorBlocksX.Count.ToString() + "\nY rotors: " + rotorBlocksY.Count.ToString());
  105. Echo ("Solar panels/Oxygen farms: " + solarBlocks.Count.ToString());
  106. if (EnableTwoAxisMode) Echo ("Dual Axis mode enabled");
  107. if (EnableTimerMgmt) Echo ("Timer management enabled");
  108. if (EnableOxygenMode) Echo ("Oxygen Farm mode ON");
  109. firstrun = false;
  110. }
  111.  
  112. bool[] rotorOn = new bool[rotorBlocksX.Count]; // Stop or start rotor
  113. bool[] rotorLow = new bool[rotorBlocksX.Count]; // True when power is way to low
  114. bool[] rotorFineTune = new bool[rotorBlocksX.Count]; // Fine Tune, very slow rotor
  115. bool[] reverse = new bool[rotorBlocksX.Count]; // Reverse rotor
  116. bool[] rotorOnY = new bool[rotorBlocksY.Count]; // Stop or start rotor
  117.  
  118. bool containsFalse = false; // Dynamic timer management. Increase or decrease timer
  119. float pwr = 0f, lastPwr = 0f; // Current and last power reading
  120.  
  121. if (EnableOxygenMode) {
  122. for(int i = 0; i < solarBlocks.Count; i++) { // For each oxygen farm...
  123. var solar = solarBlocks[i] as IMyOxygenFarm; // Support for oxygen farm
  124. if(solar != null) { // Yes I am
  125. GetOxygen(solar, ref pwr); // Get oxygen level, return into existing pwr variable
  126. lastPwr = GetAndSetLastOxygen(solar, pwr); // Get and set last runs oxygen level
  127. reverse[i] = (lastPwr < pwr || pwr == 0) ? false : true; // Change rotor direction
  128. rotorOn[i] = (pwr <= HighPwrValue) ? true : false; // Turn on rotor
  129. rotorLow[i] = (pwr < HighPwrValue/2) ? true : false; // Slow or fast rotor
  130. rotorFineTune[i] = (pwr > HighPwrValue*10/11) ? true : false; // Fine tune rotor
  131. }
  132. }
  133. } else {
  134. for(int i = 0; i < solarBlocks.Count; i++) { // For each solar panel...
  135. var solar = solarBlocks[i] as IMySolarPanel; // I am a Solar Panel
  136. if(solar != null) { // Yes I am
  137. GetPower(solar, ref pwr); // Get Power from solar panel, return into existing pwr variable
  138. lastPwr = GetAndSetLastPwr(solar, pwr); // Get and set last runs power
  139. reverse[i] = (lastPwr < pwr || pwr == 0) ? false : true; // Change rotor direction
  140. rotorOn[i] = (pwr <= HighPwrValue) ? true : false; // Turn on rotor
  141. rotorLow[i] = (pwr < HighPwrValue/2) ? true : false; // Slow or fast rotor
  142. rotorFineTune[i] = (pwr > HighPwrValue*10/11) ? true : false; // Fine tune rotor
  143. if (lastPwr == 0 && pwr == 0 && AutoNightMode || Me.TerminalRunArgument == "Nightmode") { // TEST
  144. nightmode = true;
  145. } else {
  146. nightmode = false;
  147. }
  148. }
  149. }
  150. }
  151. if (nightmode) {
  152. Echo ("Night mode.");
  153. // Do other stuff
  154. }
  155.  
  156. for(int i = 0; i < rotorBlocksX.Count; i++) { // For each rotorX...
  157. IMyMotorStator rotor = rotorBlocksX[i] as IMyMotorStator; // I am a Rotor
  158. if(rotor != null) { // Yes I am
  159. if (ForceAutoTorque) {
  160. rotor.SetValueFloat("BrakingTorque",36000000); // Force torque.
  161. rotor.SetValueFloat("Torque",30000000); // Force torque.
  162. }
  163. if (nightmode) {
  164. TriggerRotor(rotor, false, false, ref containsFalse); // Stop rotor
  165. } else {
  166. SetRotorSpeed(rotor, rotorLow[i], rotorFineTune[i]); // Dynamic rotor speed
  167. if (!rotorOn[i]) { // Turn off...
  168. TriggerRotor(rotor, false, false, ref containsFalse); // Stop rotor
  169. } else if (rotorOn[i] && EnableTwoAxisMode && reverse[i]) { // Turn On, dual axis mode, and reverse
  170. rotorOnY[i] = CheckAndUpdateRotorName(rotor);
  171. if (rotorOnY[i]) {
  172. TriggerRotor(rotor, false, false, ref containsFalse); // Y on, therefore X off.
  173. }
  174.  
  175. if (!rotorOnY[i]) {
  176. TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Y off, therefore X on, and reverse.
  177. }
  178. } else if (rotorOn[i] && EnableTwoAxisMode && !reverse[i]) {
  179. rotorOnY[i] = CheckAndUpdateRotorName(rotor);
  180. if (!rotorOnY[i]) {
  181. TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Start rotor. Reverse if needed
  182. }
  183. } else {
  184. TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Start rotor. Reverse if needed
  185. }
  186. }
  187. }
  188. }
  189.  
  190. if (EnableTwoAxisMode) {
  191. for(int i = 0; i < rotorBlocksY.Count; i++) { // For each rotorY...
  192. IMyMotorStator rotor = rotorBlocksY[i] as IMyMotorStator; // I am a Rotor
  193. if(rotor != null) { // Yes I am
  194. if (ForceAutoTorque) {
  195. rotor.SetValueFloat("BrakingTorque",36000000); // Force torque. Causes too much support without it
  196. rotor.SetValueFloat("Torque",30000000); //
  197. }
  198. if (nightmode) {
  199. TriggerRotor(rotor, false, false, ref containsFalse); // Stop rotor
  200. } else {
  201. if (rotorOnY[i] == true) {
  202. SetRotorSpeed(rotor, rotorLow[i], rotorFineTune[i]); // Dynamic rotor speed
  203. TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Start rotor Y. Reverse if needed
  204. } else {
  205. TriggerRotor(rotor, false, false, ref containsFalse);
  206. }
  207. }
  208. }
  209. }
  210. }
  211.  
  212. if (containsFalse && EnableTimerMgmt) { // Dynamic timer
  213. if (timer.TriggerDelay > TimerActiveDelay) {
  214. AdjustTriggerDelay(timer, false); // Decrease Timer Delay
  215. }
  216. } else {
  217. if (timer.TriggerDelay < TimerIdleDelay && EnableTimerMgmt) {
  218. AdjustTriggerDelay(timer, true); // Increase Timer Delay
  219. }
  220. }
  221. // Duplicate stuff
  222. if (EnableDuplicateRotor3 && !containsFalse) { // Main rotors aligned, lets duplicate changes...
  223. RotorDuplicate(NameOfDuplicateSource3, SearchForDuplicateDest3, InverseDuplicateRotor3);
  224. }
  225. if (EnableDuplicateRotor2 && !containsFalse) { // Main rotors aligned, lets duplicate changes...
  226. RotorDuplicate(NameOfDuplicateSource2, SearchForDuplicateDest2, InverseDuplicateRotor2);
  227. }
  228. if (EnableDuplicateRotor1 && !containsFalse) { // Main rotors aligned, lets duplicate changes...
  229. RotorDuplicate(NameOfDuplicateSource1, SearchForDuplicateDest1, InverseDuplicateRotor1);
  230. }
  231. }
  232.  
  233. #endregion
  234.  
  235. #region Methods
  236.  
  237. void AdjustTriggerDelay(IMyTimerBlock timer, bool Increase) {
  238. if (Increase) { timer.SetValue("TriggerDelay", TimerIdleDelay); } // Increase Timer Trigger Delay
  239. else { timer.SetValue("TriggerDelay", TimerActiveDelay); } // Decrease Timer Trigger Delay
  240. }
  241.  
  242. void TriggerRotor(IMyMotorStator rotor, bool state, bool reverse, ref bool containsFalse) {
  243. if (!state) {
  244. rotor.GetActionWithName("OnOff_Off").Apply(rotor); // Stop rotor
  245. } else {
  246. rotor.GetActionWithName("OnOff_On").Apply(rotor); // Start rotor
  247. containsFalse = true; // Adjust timer for better accuracy
  248. if (reverse) { rotor.GetActionWithName("Reverse").Apply(rotor); }
  249. }
  250. }
  251.  
  252. void GetPower(IMySolarPanel solar, ref float pwr) {
  253. string value = "";
  254. string type = "";
  255. System.Text.RegularExpressions.Regex matchthis = new System.Text.RegularExpressions.Regex(@"^.+\n.+\:\s?([0-9\.]+)\s(.*)\n.+$");
  256. System.Text.RegularExpressions.Match match = matchthis.Match(solar.DetailedInfo);
  257. if (match.Success)
  258. {
  259. value = match.Groups[1].Value;
  260. type = match.Groups[2].Value;
  261. Echo (value + " " + type);
  262. } else throw new Exception("Can't parse DetailedInfo with regex");
  263. bool test = float.TryParse(value, out pwr); // Get power into variable
  264. if (type == "W") { pwr /= 1000; } // Make sure power is in kW
  265. if (type == "MW") { pwr *= 1000; } // Make sure power is in kW
  266. if (!test) { throw new Exception("Can't parse power reading from solar panel: " + value); }
  267. }
  268.  
  269. void GetOxygen(IMyOxygenFarm solar, ref float pwr) {
  270. string value = "";
  271. System.Text.RegularExpressions.Regex matchthis = new System.Text.RegularExpressions.Regex(@"^.+\n.+\n.+\:\s?([0-9\.]+)\s?L.*$");
  272. System.Text.RegularExpressions.Match match = matchthis.Match(solar.DetailedInfo);
  273. if (match.Success)
  274. {
  275. value = match.Groups[1].Value;
  276. Echo (value + " L/min");
  277. } else
  278. {
  279. Echo("Assuming 0; Can't parse DetailedInfo: " + value);
  280. value = "0";
  281. }
  282. bool test = float.TryParse(value, out pwr); // Get oxygen into variable
  283. if (!test) { throw new Exception("Can't parse reading from oxygen farm\n"); }
  284. }
  285.  
  286. float RotorPosition(IMyMotorStator Rotor) {
  287. if (Rotor == null) {
  288. Echo( "Rotor not found. Returning 0");
  289. return 0;
  290. }
  291. string value = "";
  292. System.Text.RegularExpressions.Regex matchthis = new System.Text.RegularExpressions.Regex(@"^.+\n.+\:\s?(-?[0-9]+).*[\s\S]*$");
  293. System.Text.RegularExpressions.Match match = matchthis.Match(Rotor.DetailedInfo);
  294. if (match.Success)
  295. {
  296. value = match.Groups[1].Value;
  297. } else
  298. {
  299. Echo("Assuming 0; Can't parse Rotor DetailedInfo: " + value);
  300. value = "0";
  301. }
  302. float RotorOutput = float.Parse(value);
  303. return RotorOutput;
  304. }
  305.  
  306. void RotorDuplicate(string SourceRotorName, string RotorName, bool Inverse) {
  307. //var SourceRotor = GridTerminalSystem.GetBlockWithName(SourceRotorName) as IMyMotorStator;
  308. GridTerminalSystem.SearchBlocksOfName(SourceRotorName, SourceRotors); // Search for Solar Source Blocks
  309. IMyMotorStator SourceRotor = SourceRotors[0] as IMyMotorStator; // I am a Rotor
  310. float SetPosition = RotorPosition(SourceRotor);
  311. GridTerminalSystem.SearchBlocksOfName(RotorName, Rotors); // Search for Solar Blocks
  312. if (Rotors.Count == 0) {
  313. Echo("Cannot find any duplicate destination rotors.");
  314. return;
  315. }
  316. if (Inverse) {
  317. SetPosition = -SetPosition;
  318. }
  319. for(int i = 0; i < Rotors.Count; i++) { // For each rotor...
  320. IMyMotorStator Rotor = Rotors[i] as IMyMotorStator; // I am a Rotor
  321. float DestPosition = RotorPosition(Rotor);
  322. if (ForceAutoTorque) {
  323. Rotor.SetValueFloat("BrakingTorque",36000000);
  324. Rotor.SetValueFloat("Torque",10000000);
  325. }
  326. Rotor.SetValueFloat("LowerLimit",SetPosition);
  327. Rotor.SetValueFloat("UpperLimit",SetPosition);
  328. if (SetPosition == DestPosition) {
  329. Rotor.SetValueFloat("Velocity",0f);
  330. Rotor.GetActionWithName("OnOff_Off").Apply(Rotor); // Stop rotor
  331. } else if (SetPosition < DestPosition) {
  332. Rotor.GetActionWithName("OnOff_On").Apply(Rotor); // Start rotor
  333. Rotor.SetValueFloat("Velocity",-rotorspeed);
  334. } else if (SetPosition > DestPosition) {
  335. Rotor.GetActionWithName("OnOff_On").Apply(Rotor); // Start rotor
  336. Rotor.SetValueFloat("Velocity",rotorspeed);
  337. }
  338. }
  339. }
  340.  
  341. void SetRotorSpeed(IMyMotorStator rotor, bool fast, bool FineTune) {
  342. float SetTo = 0f;
  343. bool VelocityPositive = (rotor.GetValueFloat("Velocity") > 0f) ? true : false; // True if positive velocity
  344. if (fast) { // Under half of required power from solar panel. Will increase speed
  345. SetTo = (VelocityPositive) ? rotorspeed : -rotorspeed;
  346. } else if (FineTune) { // Fine tune speed
  347. SetTo = (VelocityPositive) ? rotorspeed/3.7f : -rotorspeed/3.7f;
  348. } else { // Not far from required power. Lower speed for increased accuracy
  349. SetTo = (VelocityPositive) ? rotorspeed/1.7f : -rotorspeed/1.7f;
  350. }
  351. rotor.SetValue("Velocity", SetTo);
  352. }
  353.  
  354. float GetAndSetLastPwr(IMySolarPanel solar, float CurrentPower) {
  355. float OldPwr = 0f;
  356. string[] words = solar.CustomName.Split(':'); // Colon split words
  357. if (words.Length > 1) { // If there is data after colon
  358. if (!float.TryParse(words[1], out OldPwr)) { OldPwr = 0f;} // Try to get data into float variable
  359. }
  360. solar.SetCustomName(words[0] + ":" + CurrentPower); // Set current power in solar panel name
  361. return OldPwr;
  362. }
  363. float GetAndSetLastOxygen(IMyOxygenFarm solar, float CurrentPower) {
  364. float OldPwr = 0f;
  365. string[] words = solar.CustomName.Split(':'); // Colon split words
  366. if (words.Length > 1) { // If there is data after colon
  367. if (!float.TryParse(words[1], out OldPwr)) { OldPwr = 0f;} // Try to get data into float variable
  368. }
  369. solar.SetCustomName(words[0] + ":" + CurrentPower); // Set current power in solar panel name
  370. return OldPwr;
  371. }
  372.  
  373. bool CheckAndUpdateRotorName(IMyMotorStator rotor) {
  374. int OldCount = 0;
  375. string[] words = rotor.CustomName.Split(':'); // Colon split words
  376. if (words.Length > 1) { // If there is data after colon
  377. if (!int.TryParse(words[1], out OldCount)) { OldCount = 0;} // Try to get data into int variable
  378. }
  379. int NewCount = OldCount + 1;
  380. if (OldCount > 6) {
  381. rotor.SetCustomName(words[0] + ":0");
  382. return true;
  383. }
  384. else if (OldCount >= 3) {
  385. rotor.SetCustomName(words[0] + ":" + NewCount); // Set current count in rotor name
  386. return true;
  387. } else {
  388. rotor.SetCustomName(words[0] + ":" + NewCount); // Set current count in rotor name
  389. return false;
  390. }
  391. }
  392. #endregion
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement