forked from here-and-now/KRPC.MechJeb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
AscentAutopilot.cs
434 lines (376 loc) · 15.1 KB
/
AscentAutopilot.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
using System;
using System.Reflection;
using KRPC.MechJeb.ExtensionMethods;
using KRPC.Service.Attributes;
namespace KRPC.MechJeb {
internal static class AscentGuidance {
internal new const string MechJebType = "MuMech.MechJebModuleAscentGuidance";
// Fields and methods
internal static FieldInfo desiredInclination;
internal static FieldInfo launchingToPlane;
internal static FieldInfo launchingToRendezvous;
internal static void InitType(Type type) {
desiredInclination = type.GetField("desiredInclination");
launchingToPlane = type.GetField("launchingToPlane");
launchingToRendezvous = type.GetField("launchingToRendezvous");
}
}
/// <summary>
/// This module controls the Ascent Guidance in MechJeb 2.
/// </summary>
/// <remarks>
/// See <a href="https://github.com/MuMech/MechJeb2/wiki/Ascent-Guidance#initial-pitch-over-issues">MechJeb2 wiki</a> for more guidance on how to optimally set up this autopilot.
/// </remarks>
[KRPCClass(Service = "MechJeb")]
public class AscentAutopilot : KRPCComputerModule {
internal new const string MechJebType = "MuMech.MechJebModuleAscentAutopilot";
// Fields and methods
private static FieldInfo status;
private static PropertyInfo ascentPathIdx;
private static FieldInfo desiredOrbitAltitudeField;
private static FieldInfo autoThrottle;
private static FieldInfo correctiveSteering;
private static FieldInfo correctiveSteeringGainField;
private static FieldInfo forceRoll;
private static FieldInfo verticalRollField;
private static FieldInfo turnRollField;
private static FieldInfo autodeploySolarPanels;
private static FieldInfo autoDeployAntennas;
private static FieldInfo skipCircularization;
private static PropertyInfo autostage;
private static FieldInfo limitAoA;
private static FieldInfo maxAoAField;
private static FieldInfo aoALimitFadeoutPressureField;
private static FieldInfo launchPhaseAngleField;
private static FieldInfo launchLANDifferenceField;
private static FieldInfo warpCountDownField;
private static FieldInfo timedLaunch;
private static MethodInfo startCountdown;
// Instance objects
private object guiInstance;
private object desiredOrbitAltitude;
private object correctiveSteeringGain;
private object verticalRoll;
private object turnRoll;
private object maxAoA;
private object aoALimitFadeoutPressure;
private object launchPhaseAngle;
private object launchLANDifference;
private object warpCountDown;
internal static new void InitType(Type type) {
status = type.GetCheckedField("status");
ascentPathIdx = type.GetCheckedProperty("ascentPathIdxPublic");
desiredOrbitAltitudeField = type.GetCheckedField("desiredOrbitAltitude");
autoThrottle = type.GetCheckedField("autoThrottle");
correctiveSteering = type.GetCheckedField("correctiveSteering");
correctiveSteeringGainField = type.GetCheckedField("correctiveSteeringGain");
forceRoll = type.GetCheckedField("forceRoll");
verticalRollField = type.GetCheckedField("verticalRoll");
turnRollField = type.GetCheckedField("turnRoll");
autodeploySolarPanels = type.GetCheckedField("autodeploySolarPanels");
autoDeployAntennas = type.GetCheckedField("autoDeployAntennas");
skipCircularization = type.GetCheckedField("skipCircularization");
autostage = type.GetCheckedProperty("autostage");
limitAoA = type.GetCheckedField("limitAoA");
maxAoAField = type.GetCheckedField("maxAoA");
aoALimitFadeoutPressureField = type.GetCheckedField("aoALimitFadeoutPressure");
launchPhaseAngleField = type.GetCheckedField("launchPhaseAngle");
launchLANDifferenceField = type.GetCheckedField("launchLANDifference");
warpCountDownField = type.GetCheckedField("warpCountDown");
timedLaunch = type.GetCheckedField("timedLaunch");
startCountdown = type.GetCheckedMethod("StartCountdown");
}
protected internal override void InitInstance(object instance) {
base.InitInstance(instance);
this.guiInstance = MechJeb.GetComputerModule("AscentGuidance");
this.desiredOrbitAltitude = desiredOrbitAltitudeField.GetInstanceValue(instance);
this.correctiveSteeringGain = correctiveSteeringGainField.GetInstanceValue(instance);
this.verticalRoll = verticalRollField.GetInstanceValue(instance);
this.turnRoll = turnRollField.GetInstanceValue(instance);
this.maxAoA = maxAoAField.GetInstanceValue(instance);
this.aoALimitFadeoutPressure = aoALimitFadeoutPressureField.GetInstanceValue(instance);
this.launchPhaseAngle = launchPhaseAngleField.GetInstanceValue(instance);
this.launchLANDifference = launchLANDifferenceField.GetInstanceValue(instance);
this.warpCountDown = warpCountDownField.GetInstanceValue(instance);
this.AscentPathClassic.InitInstance(MechJeb.GetComputerModule("AscentClassic"));
this.AscentPathGT.InitInstance(MechJeb.GetComputerModule("AscentGT"));
this.AscentPathPVG.InitInstance(MechJeb.GetComputerModule("AscentPVG"));
// Retrieve the current path index set in mechjeb and enable the path representing that index.
// It fixes the issue with AscentAutopilot reporting empty status due to a disabled path.
if(instance != null)
this.AscentPathIndex = this.AscentPathIndex;
}
public AscentAutopilot() {
this.AscentPathClassic = new AscentClassic();
this.AscentPathGT = new AscentGT();
this.AscentPathPVG = new AscentPVG();
}
/// <summary>
/// The autopilot status; it depends on the selected ascent path.
/// </summary>
[KRPCProperty]
public string Status => status.GetValue(this.instance).ToString();
/// <summary>
/// The selected ascent path.
///
/// 0 = <see cref="AscentClassic" /> (Classic Ascent Profile)
///
/// 1 = <see cref="AscentGT" /> (Stock-style GravityTurn)
///
/// 2 = <see cref="AscentPVG" /> (Primer Vector Guidance (RSS/RO))
/// </summary>
[KRPCProperty]
public int AscentPathIndex {
get => (int)ascentPathIdx.GetValue(this.instance, null);
set {
if(value < 0 || value > 2)
return;
ascentPathIdx.SetValue(this.instance, value, null);
}
}
/// <summary>
/// Get Classic Ascent Profile settings.
/// </summary>
[KRPCProperty]
public AscentClassic AscentPathClassic { get; }
/// <summary>
/// Get Stock-style GravityTurn profile settings.
/// </summary>
[KRPCProperty]
public AscentGT AscentPathGT { get; }
/// <summary>
/// Get Powered Explicit Guidance (RSS/RO) profile settings.
/// </summary>
[KRPCProperty]
public AscentPVG AscentPathPVG { get; }
/// <summary>
/// The desired altitude in kilometres for the final circular orbit.
/// </summary>
[KRPCProperty]
public double DesiredOrbitAltitude {
get => EditableDouble.Get(this.desiredOrbitAltitude);
set => EditableDouble.Set(this.desiredOrbitAltitude, value);
}
/// <summary>
/// The desired inclination in degrees for the final circular orbit.
/// </summary>
[KRPCProperty]
public double DesiredInclination {
// We need to get desiredInclinationGUI value here because it may change over time.
get => EditableDouble.Get(AscentGuidance.desiredInclination, this.guiInstance);
set => EditableDouble.Set(AscentGuidance.desiredInclination, this.guiInstance, value);
}
/// <remarks>Equivalent to <see cref="MechJeb.ThrustController" />.</remarks>
[KRPCProperty]
public ThrustController ThrustController => MechJeb.ThrustController;
/// <summary>
/// Will cause the craft to steer based on the more accurate velocity vector rather than positional vector (large craft may actually perform better with this box unchecked).
/// </summary>
[KRPCProperty]
public bool CorrectiveSteering {
get => (bool)correctiveSteering.GetValue(this.instance);
set => correctiveSteering.SetValue(this.instance, value);
}
/// <summary>
/// The gain of corrective steering used by the autopilot.
/// </summary>
/// <remarks><see cref="CorrectiveSteering" /> needs to be enabled.</remarks>
[KRPCProperty]
public double CorrectiveSteeringGain {
get => EditableDouble.Get(this.correctiveSteeringGain);
set => EditableDouble.Set(this.correctiveSteeringGain, value);
}
/// <summary>
/// The state of force roll.
/// </summary>
[KRPCProperty]
public bool ForceRoll {
get => (bool)forceRoll.GetValue(this.instance);
set => forceRoll.SetValue(this.instance, value);
}
/// <summary>
/// The vertical/climb roll used by the autopilot.
/// </summary>
/// <remarks><see cref="ForceRoll" /> needs to be enabled.</remarks>
[KRPCProperty]
public double VerticalRoll {
get => EditableDouble.Get(this.verticalRoll);
set => EditableDouble.Set(this.verticalRoll, value);
}
/// <summary>
/// The turn roll used by the autopilot.
/// </summary>
/// <remarks><see cref="ForceRoll" /> needs to be enabled.</remarks>
[KRPCProperty]
public double TurnRoll {
get => EditableDouble.Get(this.turnRoll);
set => EditableDouble.Set(this.turnRoll, value);
}
/// <summary>
/// Whether to deploy solar panels automatically when the ascent finishes.
/// </summary>
[KRPCProperty]
public bool AutodeploySolarPanels {
get => (bool)autodeploySolarPanels.GetValue(this.instance);
set => autodeploySolarPanels.SetValue(this.instance, value);
}
/// <summary>
/// Whether to deploy antennas automatically when the ascent finishes.
/// </summary>
[KRPCProperty]
public bool AutoDeployAntennas {
get => (bool)autoDeployAntennas.GetValue(this.instance);
set => autoDeployAntennas.SetValue(this.instance, value);
}
/// <summary>
/// Whether to skip circularization burn and do only the ascent.
/// </summary>
[KRPCProperty]
public bool SkipCircularization {
get => (bool)skipCircularization.GetValue(this.instance);
set => skipCircularization.SetValue(this.instance, value);
}
/// <summary>
/// The autopilot will automatically stage when the current stage has run out of fuel.
/// Paramethers can be set in <see cref="KRPC.MechJeb.StagingController" />.
/// </summary>
[KRPCProperty]
public bool Autostage {
get => (bool)autostage.GetValue(this.instance, null);
set => autostage.SetValue(this.instance, value, null);
}
/// <remarks>Equivalent to <see cref="MechJeb.StagingController" />.</remarks>
[KRPCProperty]
public StagingController StagingController => MechJeb.StagingController;
/// <summary>
/// Whether to limit angle of attack.
/// </summary>
[KRPCProperty]
public bool LimitAoA {
get => (bool)limitAoA.GetValue(this.instance);
set => limitAoA.SetValue(this.instance, value);
}
/// <summary>
/// The maximal angle of attack used by the autopilot.
/// </summary>
/// <remarks><see cref="LimitAoA" /> needs to be enabled</remarks>
[KRPCProperty]
public double MaxAoA {
get => EditableDouble.Get(this.maxAoA);
set => EditableDouble.Set(this.maxAoA, value);
}
/// <summary>
/// The pressure value when AoA limit is automatically deactivated.
/// </summary>
/// <remarks><see cref="LimitAoA" /> needs to be enabled</remarks>
[KRPCProperty]
public double AoALimitFadeoutPressure {
get => EditableDouble.Get(this.aoALimitFadeoutPressure);
set => EditableDouble.Set(this.aoALimitFadeoutPressure, value);
}
[KRPCProperty]
public double LaunchPhaseAngle {
get => EditableDouble.Get(this.launchPhaseAngle);
set => EditableDouble.Set(this.launchPhaseAngle, value);
}
[KRPCProperty]
public double LaunchLANDifference {
get => EditableDouble.Get(this.launchLANDifference);
set => EditableDouble.Set(this.launchLANDifference, value);
}
[KRPCProperty]
public int WarpCountDown {
get => EditableInt.Get(this.warpCountDown);
set => EditableInt.Set(this.warpCountDown, value);
}
/// <summary>
/// Current autopilot mode. Useful for determining whether the autopilot is performing a timed launch or not.
/// </summary>
[KRPCProperty]
public AscentLaunchMode LaunchMode {
get {
if(!(bool)timedLaunch.GetValue(this.instance))
return AscentLaunchMode.Normal;
if((bool)AscentGuidance.launchingToRendezvous.GetValue(this.guiInstance))
return AscentLaunchMode.Rendezvous;
if((bool)AscentGuidance.launchingToPlane.GetValue(this.guiInstance))
return AscentLaunchMode.TargetPlane;
return AscentLaunchMode.Unknown;
}
}
/// <summary>
/// Abort a known timed launch when it has not started yet
/// </summary>
[KRPCMethod]
public void AbortTimedLaunch() {
if(this.LaunchMode == AscentLaunchMode.Unknown)
throw new InvalidOperationException("There is an unknown timed launch ongoing which can't be aborted");
AscentGuidance.launchingToPlane.SetValue(this.guiInstance, false);
AscentGuidance.launchingToRendezvous.SetValue(this.guiInstance, false);
timedLaunch.SetValue(this.instance, false);
}
/// <summary>
/// Launch to rendezvous with the selected target.
/// </summary>
[KRPCMethod]
public void LaunchToRendezvous() {
this.AbortTimedLaunch();
AscentGuidance.launchingToRendezvous.SetValue(this.guiInstance, true);
startCountdown.Invoke(this.instance, new object[] { Planetarium.GetUniversalTime() + LaunchTiming.TimeToPhaseAngle(this.LaunchPhaseAngle) });
}
/// <summary>
/// Launch into the plane of the selected target.
/// </summary>
[KRPCMethod]
public void LaunchToTargetPlane() {
this.AbortTimedLaunch();
AscentGuidance.launchingToPlane.SetValue(this.guiInstance, true);
startCountdown.Invoke(this.instance, new object[] { Planetarium.GetUniversalTime() + LaunchTiming.TimeToPhaseAngle(this.LaunchLANDifference) });
}
[KRPCEnum(Service = "MechJeb")]
public enum AscentLaunchMode {
/// <summary>
/// The autopilot is not performing a timed launch.
/// </summary>
Normal,
/// <summary>
/// The autopilot is performing a timed launch to rendezvous with the target vessel.
/// </summary>
Rendezvous,
/// <summary>
/// The autopilot is performing a timed launch to target plane.
/// </summary>
TargetPlane,
/// <summary>
/// The autopilot is performing an unknown timed launch.
/// </summary>
Unknown = 99
}
}
public abstract class AscentBase : ComputerModule { }
public static class LaunchTiming {
internal const string MechJebType = "MuMech.LaunchTiming";
// Fields and methods
private static MethodInfo timeToPhaseAngle;
private static MethodInfo timeToPlane;
internal static void InitType(Type type) {
timeToPhaseAngle = type.GetCheckedMethod("TimeToPhaseAngle");
timeToPlane = type.GetCheckedMethod("TimeToPlane");
}
public static double TimeToPhaseAngle(double launchPhaseAngle) {
return (double)timeToPhaseAngle.Invoke(null, new object[] { launchPhaseAngle, FlightGlobals.ActiveVessel.mainBody, GetLongtitude(), MechJeb.TargetController.TargetOrbit.InternalOrbit });
}
public static double TimeToPlane(double launchLANDifference) {
Vessel vessel = FlightGlobals.ActiveVessel;
CelestialBody body = vessel.mainBody;
return (double)timeToPlane.Invoke(null, new object[] { launchLANDifference, body, body.GetLatitude(vessel.CoMD), GetLongtitude(), MechJeb.TargetController.TargetOrbit.InternalOrbit });
}
private static double GetLongtitude() {
Vessel vessel = FlightGlobals.ActiveVessel;
double longtitude = vessel.mainBody.GetLongitude(vessel.CoMD) % 360;
if(longtitude > 180)
longtitude -= 360;
return longtitude;
}
}
}