View difference between Paste ID: y5p0sz5S and q7zRG2V6
SHOW: | | - or go back to the newest paste.
1
	/*   
2
	Script for automatic rotor stop when a solar panel or oxygen farm has high output.   
3
	Version: 1.11
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 = "SolarMain";  
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 = "RotorX";  
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.8f;  
25
26
	// EnableTwoAxisMode - Enable dual axis mode.  
27
	//  Recommended value: Depends on design.  
28
	const bool EnableTwoAxisMode = true;   
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 = "LCDSolar";
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 = true;  
49
	const bool EnableDuplicateRotor2 = true;  
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 = true;  
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 = "Timertest1"; 
78
	 
79
	// Trigger this timer at low power 
80
	const bool ControlCustomTimerAtLowPower = false; 
81
	const string NameForCustomtriggerAtLowPower = "Timertest2"; 
82
	
83
	// Changes below this line not recommended.  
84
	//------------------------------------------------------------   
85
	#endregion 
86
	// Quick fix to disable useless warnings 
87
	#pragma warning disable 0162 
88
	List<IMyTerminalBlock> solarBlocks = new List<IMyTerminalBlock>();  
89
	List<IMyTerminalBlock> rotorBlocksX = new List<IMyTerminalBlock>();  
90
	List<IMyTerminalBlock> rotorBlocksY = new List<IMyTerminalBlock>();  
91
	List<IMyTerminalBlock> Rotors = new List<IMyTerminalBlock>();  
92
	List<IMyTerminalBlock> SourceRotors = new List<IMyTerminalBlock>();  
93
	List<IMyTerminalBlock> LcdBlocks = new List<IMyTerminalBlock>();
94
	IMyTimerBlock timer2; 
95
	IMyTimerBlock timer3; 
96
	bool firstrun = true;  
97
	bool nightmode = false;  
98
	long lCount = 0;
99
	int delayCount = 0;
100
	string textToLCD = "";
101
102
public Program() { 
103
	Runtime.UpdateFrequency |= UpdateFrequency.Update100;
104
}
105
	
106
	#region Main  
107
	void Main(string argument)  
108
	{  
109
		if (firstrun) {
110
			// Echo = text => {}; // Uncommenting this line might increase performance on servers. Will disable echo
111
			GridTerminalSystem.SearchBlocksOfName(NameOfSolar, solarBlocks); // Search for Solar Blocks   
112
			GridTerminalSystem.SearchBlocksOfName(NameOfRotorX, rotorBlocksX); // Search for Rotor Blocks   
113
			GridTerminalSystem.SearchBlocksOfName(NameOfRotorY, rotorBlocksY); // Search for RotorY Blocks
114
			if (EnableLCD) GridTerminalSystem.SearchBlocksOfName(NameOfLCD, LcdBlocks); // Search for LCD Blocks
115
			if (solarBlocks.Count == 0) { throw new Exception("Cannot find solar panel. Check name and recompile."); }  
116
			if (rotorBlocksX.Count == 0) { throw new Exception("Cannot find x-axis rotor blocks. Check name and recompile."); }  
117
			if (rotorBlocksY.Count == 0 && EnableTwoAxisMode) { throw new Exception("Cannot find y-axis rotor blocks. Check name and recompile."); }  
118
			if (rotorBlocksY.Count < rotorBlocksX.Count && EnableTwoAxisMode) {  
119
				int diff = rotorBlocksX.Count - rotorBlocksY.Count;  
120
				throw new Exception(diff + " Y-axis rotors missing. Fix and recompile.");  
121
			}  
122
			if (solarBlocks.Count > rotorBlocksX.Count) { throw new Exception("Too many solar panels found. Check solar panel names."); }  
123
			Echo ("Init...\nX rotors: " + rotorBlocksX.Count.ToString() + "\nY rotors: " + rotorBlocksY.Count.ToString());  
124
			Echo ("Solar panels/Oxygen farms: " + solarBlocks.Count.ToString());  
125
			if (EnableTwoAxisMode) Echo ("Dual Axis mode enabled");  
126
			if (EnableOxygenMode) Echo ("Oxygen Farm mode ON");  
127
			if (EnableDuplicateRotor1 || EnableDuplicateRotor2 || EnableDuplicateRotor3) Echo ("Duplication activated."); 
128
			if (ControlCustomTimerAtMaxPower) timer2 = GridTerminalSystem.GetBlockWithName(NameForCustomtriggerAtMaxPower) as IMyTimerBlock; 
129
			if (ControlCustomTimerAtLowPower) timer3 = GridTerminalSystem.GetBlockWithName(NameForCustomtriggerAtLowPower) as IMyTimerBlock; 
130
131
			firstrun = false;	
132
		}
133
			if (argument == "start") Runtime.UpdateFrequency |= UpdateFrequency.Update100; 
134
			else if (argument == "stop") Runtime.UpdateFrequency &= ~UpdateFrequency.Update100;
135
			lCount++;
136
			if (lCount == 3) {
137
				lCount = 0;
138
			} else return;
139
	    textToLCD = "Auto aligning solar panels\n"; 
140
		bool[] rotorOn = new bool[rotorBlocksX.Count]; // Stop or start rotor   
141
		bool[] rotorLow = new bool[rotorBlocksX.Count]; // True when power is way to low   
142
		bool[] rotorFineTune = new bool[rotorBlocksX.Count]; // Fine Tune, very slow rotor   
143
		bool[] reverse = new bool[rotorBlocksX.Count]; // Reverse rotor	   
144
		bool[] rotorOnY = new bool[rotorBlocksY.Count]; // Stop or start rotor   
145
		
146
		bool containsFalse = false; // Dynamic timer management. Increase or decrease timer  
147
		float pwr = 0f, lastPwr = 0f; // Current and last power reading   
148
	  
149
		if (EnableOxygenMode) {  
150
			for(int i = 0; i < solarBlocks.Count; i++) { // For each oxygen farm...   
151
			var solar = solarBlocks[i] as IMyOxygenFarm; // Support for oxygen farm   
152
			if(solar != null) { // Yes I am   
153
				GetOxygen(solar, ref pwr); // Get oxygen level, return into existing pwr variable   
154
				lastPwr = GetAndSetLastOxygen(solar, pwr); // Get and set last runs oxygen level   
155
				reverse[i] = (lastPwr < pwr || pwr == 0) ? false : true; // Change rotor direction   
156
				rotorOn[i] = (pwr <= HighPwrValue) ? true : false; // Turn on rotor   
157
				rotorLow[i] = (pwr < HighPwrValue/2) ? true : false; // Slow or fast rotor   
158
				rotorFineTune[i] = (pwr > HighPwrValue*10/11) ? true : false; // Fine tune rotor   
159
				}  
160
			}  
161
		}	else {  
162
			for(int i = 0; i < solarBlocks.Count; i++) { // For each solar panel...   
163
			var solar = solarBlocks[i] as IMySolarPanel; // I am a Solar Panel   
164
			if(solar != null) { // Yes I am   
165
				GetPower(solar, ref pwr); // Get Power from solar panel, return into existing pwr variable   
166
				lastPwr = GetAndSetLastPwr(solar, pwr); // Get and set last runs power   
167
				reverse[i] = (lastPwr < pwr || pwr == 0) ? false : true; // Change rotor direction   
168
				rotorOn[i] = (pwr <= HighPwrValue) ? true : false; // Turn on rotor   
169
				rotorLow[i] = (pwr < HighPwrValue/2) ? true : false; // Slow or fast rotor   
170
				rotorFineTune[i] = (pwr > HighPwrValue*10/11) ? true : false; // Fine tune rotor  
171
				if (lastPwr == 0 && pwr == 0 && AutoNightMode || Me.TerminalRunArgument == "Nightmode") { // TEST  
172
					nightmode = true;  
173
				} else {  
174
					nightmode = false;  
175
				}  
176
				}  
177
			}  
178
		}  
179
		if (nightmode) {  
180
			Echo ("Night mode.");  
181
			// Do other stuff  
182
		}  
183
		  
184
		for(int i = 0; i < rotorBlocksX.Count; i++) { // For each rotorX...   
185
			IMyMotorStator rotor = rotorBlocksX[i] as IMyMotorStator; // I am a Rotor   
186
			if(rotor != null) { // Yes I am  
187
				if (ForceAutoTorque) { // Force torque. 
188
					rotor.BrakingTorque = float.MaxValue;
189
					rotor.Torque = 30000000f;  
190
				}  
191
				if (nightmode) {  
192
					TriggerRotor(rotor, false, false, ref containsFalse); // Stop rotor   
193
				} else {  
194
					SetRotorSpeed(rotor, rotorLow[i], rotorFineTune[i]); // Dynamic rotor speed   
195
					if (!rotorOn[i]) { // Turn off...   
196
						TriggerRotor(rotor, false, false, ref containsFalse); // Stop rotor   
197
					}			else if (rotorOn[i] && EnableTwoAxisMode && reverse[i]) { // Turn On, dual axis mode, and reverse   
198
						rotorOnY[i] = CheckAndUpdateRotorName(rotor);  
199
						if (rotorOnY[i]) {  
200
							TriggerRotor(rotor, false, false, ref containsFalse); // Y on, therefore X off.   
201
						}  
202
203
						if (!rotorOnY[i]) {  
204
							TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Y off, therefore X on, and reverse.   
205
						}  
206
					}	else if (rotorOn[i] && EnableTwoAxisMode && !reverse[i]) {  
207
						rotorOnY[i] = CheckAndUpdateRotorName(rotor);  
208
						if (!rotorOnY[i]) {  
209
							TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Start rotor. Reverse if needed   
210
						}  
211
					}	else {  
212
						TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Start rotor. Reverse if needed   
213
					}  
214
				}  
215
			}  
216
		}  
217
	  
218
		if (EnableTwoAxisMode) {  
219
			for(int i = 0; i < rotorBlocksY.Count; i++) { // For each rotorY...   
220
				IMyMotorStator rotor = rotorBlocksY[i] as IMyMotorStator; // I am a Rotor   
221
				if(rotor != null) { // Yes I am  
222
					if (ForceAutoTorque) {  
223
					rotor.BrakingTorque = float.MaxValue;
224
					rotor.Torque = 30000000f;
225
					}  
226
					if (nightmode) {  
227
						TriggerRotor(rotor, false, false, ref containsFalse); // Stop rotor   
228
					} else {  
229
						if (rotorOnY[i] == true) {  
230
							SetRotorSpeed(rotor, rotorLow[i], rotorFineTune[i]); // Dynamic rotor speed   
231
							TriggerRotor(rotor, true, reverse[i], ref containsFalse); // Start rotor Y. Reverse if needed   
232
						} else {  
233
							TriggerRotor(rotor, false, false, ref containsFalse);  
234
						}  
235
					}  
236
				}  
237
			}  
238
		}  
239
	 
240
		// Duplicate stuff  
241
	if (EnableDuplicateRotor3 && !containsFalse) { // Main rotors aligned, lets duplicate changes...    
242
			RotorDuplicate(NameOfDuplicateSource3, SearchForDuplicateDest3, InverseDuplicateRotor3);    
243
		}  
244
		if (EnableDuplicateRotor2 && !containsFalse) { // Main rotors aligned, lets duplicate changes...  
245
			RotorDuplicate(NameOfDuplicateSource2, SearchForDuplicateDest2, InverseDuplicateRotor2);  
246
		}  
247
		if (EnableDuplicateRotor1 && !containsFalse) { // Main rotors aligned, lets duplicate changes...  
248
			RotorDuplicate(NameOfDuplicateSource1, SearchForDuplicateDest1, InverseDuplicateRotor1);  
249
		} 
250
	if (!containsFalse && ControlCustomTimerAtMaxPower) { // Main rotors aligned, lets control a timer
251
		delayCount = 0;
252
		ControlTimer(timer2); 
253
		} 
254
	if (containsFalse && ControlCustomTimerAtLowPower){ 
255
			delayCount++;
256
			if (delayCount == 5) {
257
				delayCount = 0;
258
				ControlTimer(timer3);
259
			}		 
260
		} 
261
	if (EnableLCD) PrintToLCD(textToLCD);
262
	} 
263
264
	#endregion  	  
265
	#region Methods  
266
267
	void PrintToLCD(string text) {
268
		if (EnableLCD) {
269
			for(int i = 0; i < LcdBlocks.Count; i++) { // For each LCD...   
270
				IMyTextPanel LCD = LcdBlocks[i] as IMyTextPanel;
271
				LCD.WritePublicText(text, false); 
272
				LCD.SetValue("FontSize", 0.9f); 
273
				LCD.ShowPublicTextOnScreen();
274
			}
275
		}
276
	}
277
	void ControlTimer(IMyTimerBlock thistimer) { 
278
		thistimer.ApplyAction("TriggerNow");  
279
	}
280
	  
281
	void TriggerRotor(IMyMotorStator rotor, bool state, bool reverse, ref bool containsFalse) {  
282
		if (!state) {  
283
			rotor.ApplyAction("OnOff_Off"); // Stop rotor   
284
		}	else {  
285
			rotor.ApplyAction("OnOff_On"); // Start rotor   
286
			containsFalse = true; 
287
			if (reverse) { rotor.ApplyAction("Reverse"); }  
288
		}  
289
	}  
290
	  
291
	void GetPower(IMySolarPanel solar, ref float pwr) {  
292
		pwr = solar.MaxOutput * 1000;
293
		float test = pwr / HighPwrValue * 100f;
294
		decimal test2 = Math.Round((decimal)test);
295
		textToLCD += pwr.ToString() + " kWh (" + test2.ToString() + " %)\n";
296
		Echo(pwr.ToString() + " kWh");  
297
	}  
298
299
	void GetOxygen(IMyOxygenFarm solar, ref float pwr) {  
300
		pwr = solar.GetOutput()* 1.8f;
301
		Echo(pwr.ToString() + " L/min");
302
	}  
303
	  
304
	float RotorPosition(IMyMotorStator Rotor) {  
305
		if (Rotor == null) {  
306
			Echo( "Rotor not found. Returning 0");  
307
			return 0;  
308
		}  
309
		return (float)Math.Round(Rotor.Angle * (180.0 / Math.PI), 0);
310
	}
311
	  
312
	void RotorDuplicate(string SourceRotorName, string RotorName, bool Inverse) {   
313
		GridTerminalSystem.SearchBlocksOfName(SourceRotorName, SourceRotors); // Search for Solar Source Blocks  
314
		IMyMotorStator SourceRotor = SourceRotors[0] as IMyMotorStator; // I am a Rotor  
315
		float SetPosition = RotorPosition(SourceRotor);  
316
		GridTerminalSystem.SearchBlocksOfName(RotorName, Rotors); // Search for Solar Blocks   
317
		if (Rotors.Count == 0) {   
318
			Echo("Cannot find any duplicate destination rotors.");  
319
			return;  
320
		}  
321
		if (Inverse) {  
322
			SetPosition = -SetPosition;  
323
		}  
324
		for(int i = 0; i < Rotors.Count; i++) { // For each rotor...  
325
			IMyMotorStator Rotor = Rotors[i] as IMyMotorStator; // I am a Rotor  
326
			float DestPosition = RotorPosition(Rotor);	  
327
			if (ForceAutoTorque) {  
328
				Rotor.BrakingTorque = float.MaxValue; 	  
329
				Rotor.Torque = 10000000f;   
330
			}  
331
			Rotor.SetValueFloat("LowerLimit",SetPosition);   
332
			Rotor.SetValueFloat("UpperLimit",SetPosition);
333
			textToLCD += "Duplication #" + i + ": ";
334
			if (SetPosition == DestPosition) {  
335
				Rotor.TargetVelocityRPM = 0f;  
336
				Rotor.ApplyAction("OnOff_Off"); // Stop rotor
337
				textToLCD += "Locked\n";
338
			} else if (SetPosition < DestPosition)  {  
339
				Rotor.ApplyAction("OnOff_On"); // Start rotor   
340
				Rotor.TargetVelocityRPM = -rotorspeed;
341
				textToLCD += "Running\n";
342
			} else if (SetPosition > DestPosition)  {  
343
				Rotor.ApplyAction("OnOff_On"); // Start rotor   
344
				Rotor.TargetVelocityRPM = rotorspeed;
345
				textToLCD += "Running\n";
346
			}  
347
		}  
348
	}  
349
	   
350
	void SetRotorSpeed(IMyMotorStator rotor, bool fast, bool FineTune) {   
351
		float SetTo = 0f;   
352
		bool VelocityPositive = (rotor.TargetVelocityRPM > 0f) ? true : false; // True if positive velocity   
353
		if (fast) { // Under half of required power from solar panel. Will increase speed   
354
			SetTo = (VelocityPositive) ? rotorspeed : -rotorspeed;   
355
		} else if (FineTune) { // Fine tune speed   
356
				SetTo = (VelocityPositive) ? rotorspeed/3.7f : -rotorspeed/3.7f;   
357
		} else { // Not far from required power. Lower speed for increased accuracy   
358
			SetTo = (VelocityPositive) ? rotorspeed/1.7f : -rotorspeed/1.7f;   
359
		}   
360
		rotor.TargetVelocityRPM = SetTo;   
361
	}   
362
	   
363
	float GetAndSetLastPwr(IMySolarPanel 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.CustomName = (words[0] + ":" + CurrentPower); // Set current power in solar panel name   
370
		return OldPwr;   
371
	}   
372
	float GetAndSetLastOxygen(IMyOxygenFarm solar, float CurrentPower) {   
373
		float OldPwr = 0f;   
374
		string[] words = solar.CustomName.Split(':'); // Colon split words   
375
		if (words.Length > 1) {	// If there is data after colon   
376
			if (!float.TryParse(words[1], out OldPwr)) { OldPwr = 0f;} // Try to get data into float variable   
377
		}   
378
		solar.CustomName = (words[0] + ":" + CurrentPower); // Set current power in solar panel name   
379
		return OldPwr;   
380
	}   
381
	  
382
	bool CheckAndUpdateRotorName(IMyMotorStator rotor) {   
383
		int OldCount = 0;   
384
		string[] words = rotor.CustomName.Split(':'); // Colon split words   
385
		 if (words.Length > 1) {	// If there is data after colon   
386
			if (!int.TryParse(words[1], out OldCount)) { OldCount = 0;} // Try to get data into int variable   
387
		}   
388
		int NewCount = OldCount + 1;   
389
		if (OldCount > 6) {   
390
			rotor.CustomName = (words[0] + ":0");   
391
			return true;   
392
			}   
393
		else if (OldCount >= 3) {   
394
			rotor.CustomName = (words[0] + ":" + NewCount); // Set current count in rotor name   
395
			return true;   
396
		} else {   
397
			rotor.CustomName = (words[0] + ":" + NewCount); // Set current count in rotor name   
398
			return false;   
399
		}	   
400
	}  
401
	#endregion