-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprobefc.ks
More file actions
315 lines (268 loc) · 8.4 KB
/
probefc.ks
File metadata and controls
315 lines (268 loc) · 8.4 KB
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
@LAZYGLOBAL OFF.
// Clear ship controls
SAS OFF.
// Load libraries
RUN lib_pid.
// Ship profiles
LOCAL profileAscending IS "Ascending".
LOCAL profileDescending IS "Descending".
LOCAL profileOrbiting IS "Orbiting".
LOCAL profileStationary IS "Stationary".
// Mission modes
LOCAL modeIdle IS "Idle".
LOCAL modePreSuicideBurn IS "Pre suicide burn".
LOCAL modeSuicideBurn IS "Suicide burn".
LOCAL modePreAdjustAoA IS "Pre Adjust AoA".
LOCAL modeAdjustAoA IS "Adjust AoA".
LOCAL modeDescent IS "Descent".
LOCAL modeFreeFall IS "Free fall".
// Locks
LOCK surfacePrograde TO R(0,0,0) * V(0-VELOCITY:SURFACE:X, 0-VELOCITY:SURFACE:Y, 0-VELOCITY:SURFACE:Z).
// PID Controllers
LOCAL velocity_pid IS PID_Init(0.1, 0.2, 0.005, 0, 1).
LOCAL altitude_pid IS PID_Init(0.2, 0.0, 0.050, -10, 10).
LOCAL pitch_pid IS PID_Init(2, 0.05, 0.05, -45, 45).
LOCAL yaw_pid IS PID_Init(2, 0.05, 0.05, -45, 45).
// Mission Settings
LOCAL programActive IS FALSE.
LOCAL mode IS modeIdle.
LOCAL targetBodyName IS "Mun".
LOCAL targetBodyMaxAltitude IS 5600.
LOCAL targetDescentVelocity IS -3.
LOCAL maxGroundSlope IS 5.
LOCAL currentThrottle IS 0.
LOCAL currentSteering IS surfacePrograde.
LOCAL geoAngleOffset IS 0.001.
LOCAL geoOffsetDistance IS 5.25.
// UI
LOCAL labelList IS LIST(
"Active:",
"Status:",
"Profile:",
"Mode:",
"Alt:",
"SB Alt:",
"SB Time:",
"GrndAngle:",
"UpAngle:"
).
// Main Program
CLEARSCREEN.
DrawLabelList(labelList, 0, 0).
UNTIL FALSE {
// Check if program should take control.
IF STAGE:NUMBER = 0 AND GetProfile() = profileDescending {
SET programActive TO TRUE.
}
IF STATUS = "LANDED" OR STATUS = "SPLASHED" {
SET programActive TO FALSE.
}
IF programActive = TRUE {
LOCK STEERING TO currentSteering.
LOCK THROTTLE TO currentThrottle.
IF GetTrueAltitude() < GetSuicideBurnAltitude() * 1.5
AND mode <> modeSuicideBurn {
// First thing we need to check is if we're within
// suicide burn altitude range.
SET mode TO modePreSuicideBurn.
} ELSE IF GetTrueAltitude() < targetBodyMaxAltitude
AND GetTrueAltitude() > 1000
AND VANG(UP:VECTOR, surfacePrograde) > 45 {
// We're at risk of hitting the side of a mountain.
// Adjust angle of attack until we're coming in
// at a better angle.
SET mode TO modePreAdjustAoA.
} ELSE IF GetTrueAltitude() < 1000 {
SET mode TO modeDescent.
}
} ELSE {
SET mode TO modeIdle.
UNLOCK STEERING.
UNLOCK THROTTLE.
}
IF mode = modePreSuicideBurn {
SET currentSteering TO surfacePrograde.
// Start aligning ship facing to surface prograde.
IF CalculateDelta(SHIP:FACING, surfacePrograde:DIRECTION) < 0.1 { // TODO: See if VANG works better here.
// We're lined up, wait for burn time.
IF GetTimeToSuicideBurn() < 0.5 {
SET currentThrottle TO 1.
SET mode TO modeSuicideBurn.
}
} ELSE {
// Kill throttle before starting the turn.
// Don't want to start burning in some crazy direction.
SET currentThrottle TO 0.
}
} ELSE IF mode = modeSuicideBurn {
SET currentSteering TO surfacePrograde.
// Keep burning until velocity is very low.
// 15 m/s is a good number to stop at.
// Any lower and the thrust might spin the ship
// around because we're locked to surface prograde.
IF VELOCITY:SURFACE:MAG < 15 {
// We're slow enough, kill engines.
SET currentThrottle TO 0.
SET mode TO modeFreeFall.
}
} ELSE IF mode = modePreAdjustAoA {
SET currentSteering TO surfacePrograde.
// Wait until we're lined up with surface prograde.
IF CalculateDelta(SHIP:FACING, surfacePrograde:DIRECTION) < 0.1 { // TODO: See if VANG works better here.
// Start adjustments.
SET currentThrottle TO 1.
SET mode TO modeAdjustAoA.
} ELSE {
// Kill throttle while we wait for alignment.
SET currentThrottle TO 0.
}
} ELSE IF mode = modeAdjustAoA {
IF VANG(UP:VECTOR, surfacePrograde) < 45 {
// We're now at a better AoA, kill throttle.
SET currentThrottle TO 0.
SET mode TO modeFreeFall.
}
} ELSE IF mode = modeDescent {
// Setup starting descent velocities.
IF GetTrueAltitude() < 1000 {
SET targetDescentVelocity TO -50.
}
IF GetTrueAltitude() < 500 {
SET targetDescentVelocity TO -25.
}
IF GetTrueAltitude() < 250 {
SET targetDescentVelocity TO -12.
}
IF GetTrueAltitude() < 100 {
SET targetDescentVelocity TO -6.
}
IF GetTrueAltitude() < 50 {
// We're low enough now to start checking ground slope.
// Lock ship up-right.
SET currentSteering TO UP + R(0,0,0).
} ELSE {
LOCAL descentPrograde IS (surfacePrograde:NORMALIZED + (UP + R(0,0,0)):VECTOR:NORMALIZED):NORMALIZED.
// Still descending, keep trying to reduce horizontal movement.
// Check if we're way off from up-right, if so, lock to vector mid-way between up and surface.
IF VANG(descentPrograde, (UP + R(0,0,0)):VECTOR) < 5 {
// Let PID keep track of alignment.
LOCAL pitchOffset IS -1 * PID_Seek(pitch_pid, 0, SHIP:VELOCITY:SURFACE * SHIP:FACING:TOPVECTOR).
LOCAL yawOffset IS PID_Seek(yaw_pid, 0, SHIP:VELOCITY:SURFACE * SHIP:FACING:STARVECTOR).
SET currentSteering TO UP + R(pitchOffset, yawOffset, 0).
} ELSE {
// We're way off, use mid-way vector.
SET currentSteering TO descentPrograde.
}
}
SET currentThrottle TO PID_Seek(velocity_pid, targetDescentVelocity, VERTICALSPEED).
} ELSE IF mode = modeFreeFall {
SET currentThrottle TO 0.
SET currentSteering TO surfacePrograde.
}
// Update UI data.
LOCAL dataList IS LIST(
programActive,
STATUS,
GetProfile(),
mode,
ROUND(GetTrueAltitude(), 2),
ROUND(GetSuicideBurnAltitude(), 2),
ROUND(GetTimeToSuicideBurn(), 2),
ROUND(GetGroundSlope(), 2),
ROUND(VANG(UP:VECTOR, surfacePrograde), 2),
GetPitchAngleOffset(),
GetYawAngleOffset()
).
DrawDataList(dataList, 15, 0).
WAIT 0.01.
}
// Helper Functions
FUNCTION GetGroundSlope {
LOCAL cPos IS SHIP:GEOPOSITION.
LOCAL nPos IS LATLNG(cPos:LAT + geoAngleOffset, cPos:LNG).
LOCAL ePos IS LATLNG(cPos:LAT, cPos:LNG + geoAngleOffset).
LOCAL vecCN IS nPos:POSITION - cPos:POSITION.
LOCAL vecCE IS ePos:POSITION - cPos:POSITION.
LOCAL groundVector IS VCRS(vecCN, vecCE).
RETURN VANG(UP:VECTOR, groundVector).
}
FUNCTION GetPitchAngleOffset {
LOCAL offset IS 0.001.
LOCAL cPos IS SHIP:GEOPOSITION.
LOCAL nPos IS LATLNG(cPos:LAT + geoAngleOffset, cPos:LNG).
LOCAL sPos IS LATLNG(cPos:LAT - geoAngleOffset, cPos:LNG).
LOCAL angleNS IS ARCTAN((nPos:TERRAINHEIGHT - sPos:TERRAINHEIGHT) / geoOffsetDistance).
IF angleNS > maxGroundSlope {
RETURN 5.
} ELSE {
RETURN 0.
}
}
FUNCTION GetYawAngleOffset {
LOCAL offset IS 0.001.
LOCAL cPos IS SHIP:GEOPOSITION.
LOCAL ePos IS LATLNG(cPos:LAT, cPos:LNG + geoAngleOffset).
LOCAL wPos IS LATLNG(cPos:LAT, cPos:LNG - geoAngleOffset).
LOCAL angleEW IS ARCTAN((ePos:TERRAINHEIGHT - wPos:TERRAINHEIGHT) / geoOffsetDistance).
IF angleEW > maxGroundSlope {
RETURN 5.
} ELSE {
RETURN 0.
}
}
FUNCTION CalculateDelta { PARAMETER directionA, directionB.
LOCAL pitchDelta IS ABS(COS(directionA:PITCH)-COS(directionB:PITCH))+ABS(SIN(directionA:PITCH)-SIN(directionB:PITCH)).
LOCAL yawDelta IS ABS(COS(directionA:YAW)-COS(directionB:YAW))+ABS(SIN(directionA:YAW)-SIN(directionB:YAW)).
RETURN pitchDelta+yawDelta.
}
FUNCTION GetSuicideBurnAltitude {
IF SHIP:AVAILABLETHRUST = 0 {
RETURN -1.
}
// TODO: Use constant gravity formula instead of ship sensors.
RETURN (VELOCITY:SURFACE:MAG^2)/(2*(SHIP:AVAILABLETHRUST/(SHIP:MASS*SHIP:SENSORS:GRAV:MAG))).
}
FUNCTION GetTimeToSuicideBurn {
LOCAL burnAltitude IS GetSuicideBurnAltitude().
IF burnAltitude < 0 {
RETURN -1.
}
RETURN (GetTrueAltitude()-burnAltitude)/VELOCITY:SURFACE:MAG.
}
FUNCTION GetProfile {
IF STATUS = "PRELAUNCH" OR STATUS = "LANDED" OR STATUS = "SPLASHED" {
RETURN profileStationary.
}
IF APOAPSIS > 0 and PERIAPSIS > 0 {
RETURN profileOrbiting.
}
IF ETA:APOAPSIS < ETA:PERIAPSIS {
RETURN profileAscending.
} ELSE {
RETURN profileDescending.
}
}
FUNCTION GetTrueAltitude {
LOCAL terrainHeight IS SHIP:GEOPOSITION:TERRAINHEIGHT.
IF ALT:RADAR = ALTITUDE {
RETURN ALTITUDE.
} ELSE {
IF terrainHeight <= 0 {
SET terrainHeight TO 0.
}
RETURN ALTITUDE - terrainHeight.
}
}
FUNCTION DrawLabelList { PARAMETER labelList, xPos, yPos.
FOR label IN labelList {
PRINT label AT (xPos, yPos).
SET yPos TO yPos + 1.
}
}
FUNCTION DrawDataList { PARAMETER dataList, xPos, yPos.
LOCAL spaces IS " ".
FOR data in dataList {
PRINT data + spaces AT (xPos, yPos).
SET yPos TO yPos + 1.
}
}