View difference between Paste ID: N8eMd50c and xeNy4xmv
SHOW: | | - or go back to the newest paste.
1
//VTOL hover script with side translation - Ozin
2-
// !runscript xeNy4xmv
2+
//hacked and likely broken - sumguy
3
// !runscript N8eMd50c
4-
core:doaction("open terminal",true).
4+
switch to 0.
5
clearvecdraws().
6
HUDTEXT("Running script: VTOL hover for props",20,2,22,white,false).
7-
sas off.
7+
8-
HUDTEXT("Running script: VTOL hover for jets & propellers",20,2,22,white,false).
8+
9
10
11-
if not(defined places) and exists("0:/json/" + body:name + ".json") set places to readjson("0:/json/" + body:name + ".json").
11+
12
set steeringmanager:rollcontrolanglerange to 180.
13
set steeringmanager:rollpid:kp to 0.4.
14
set steeringmanager:rollpid:ki to 0.04.
15-
set props to false.
15+
16-
if ship:partsnamedpattern("blade"):length >= 4 {
16+
17-
	//toggle ag3.
17+
18-
	set props to true.
18+
set st to  lookdirup(up:vector, facing:topvector).
19-
	print "Detected propellers. Throttle will control blade authority, with a fixed RPM.".
19+
20-
	set rotors to list(). 
20+
lock hdg to 90. 
21-
	for m in ship:modulesnamed("ModuleRoboticServoRotor") {
21+
lock sl to 0.
22-
		set rotorList to list(m:part). //index 0: part, 1: bool for flipped, 2+: individual blade partmodules
22+
23-
		for p in m:part:children {
23+
24-
			if p:hasmodule("ModuleControlSurface") {
24+
25-
				if rotorList:length = 1 rotorList:add(choose -1 if vang(m:part:facing:vector, p:facing:topvector) > 92 else 1).
25+
26-
				rotorList:add(p:getmodule("ModuleControlSurface")).
26+
27-
			}
27+
28-
		}
28+
29-
		rotors:add(rotorList).
29+
30-
	}.
30+
31-
	//set rotor1 to ship:modulesnamed("ModuleRoboticServoRotor")[0]:part.
31+
32-
	//set ship:control:pilotmainthrottle to 0.5.
32+
33-
	for s in ship:modulesnamed("ModuleRoboticServoRotor") s:setfield("torque limit(%)", 1).
33+
34
set tiltOutwards to 0.
35
lock vsOverride to 0.
36-
set estNeutral to 0.
36+
37-
set tarAOA to 0.
37+
38
set vs to 0.
39-
set mathThingy to 2 * constant:pi * 5.8 * 460/60.
39+
40-
function bladeAOA { parameter ang.
40+
set stTopVector to facing:topvector.
41-
	set tarAOA to ang.
41+
42-
	for rotor in rotors {
42+
43-
		set relSpd to vdot(rotor[0]:facing:vector * rotor[1], vel).
43+
44-
		set estNeutral to arctan(abs(relSpd)/mathThingy) * relSpd/abs(relSpd). 
44+
45-
		for i in range(2,rotor:length) {
45+
46-
			rotor[i]:setfield("deploy angle",estNeutral + ang).
46+
set mul to 1.
47-
		}
47+
lock tv to heading(hdg,0):vector * sl.
48
set tvCopy to tv.
49
50
lock deploy to max(3,airspeed^0.7). 
51
lock rpmlimit to max(0,(-2*verticalspeed - altitude + talt -altErr*0.6)*4.6*2).
52
set blades to ship:partsdubbedpattern("blade"). 
53
54
set rotors to ship:partsdubbedpattern("rotor").
55
 
56
for rotor in rotors rotor:getmodulebyindex(1):setfield("torque limit(%)",100).
57-
set steeringmanager:maxstoppingtime to 6.
57+
58
if ship:partsnamedpattern("grap"):length > 0 { 
59-
set flipSteering to false.
59+
60-
set face to facing.
60+
61
	set localport to ship:dockingports[0]. 
62-
set st to lookdirup(up:vector, face:topvector).
62+
63-
lock hdg to 90. lock sl to 0.
63+
64
}
65
set mode to "Heading".
66
set tgt to false.
67-
set twr to 1.
67+
68
69
70
//===[Functions]===
71
72
function norm {
73-
set velOld to vel.
73+
74
	set u to (p0-body:position):normalized.
75
	set p1 to vxcl(u,facing:vector):normalized * (bnds:size:mag + 5).
76
	set g2 to body:geopositionof(angleaxis(120, u) * p1 + p0). set p2 to choose g2:position if g2:terrainheight > 0 else g2:altitudeposition(0).
77
	set g3 to body:geopositionof(angleaxis(-120, u) * p1 + p0). set p3 to choose g3:position if g3:terrainheight > 0 else g3:altitudeposition(0).
78
	set g1 to body:geopositionof(p1 + p0). set p1 to choose g1:position if g1:terrainheight > 0 else g1:altitudeposition(0).
79
	return vcrs(p1-p2,p1-p3):normalized.
80
}
81
function getSlope {
82
	parameter pos, vec.
83-
set stTopVector to face:topvector.
83+
84
	local g2 is body:geopositionof(pos+vec). local p2 is choose g2:position if g2:terrainheight > 0 else g2:altitudeposition(0).
85
	return 90 - vang(up:vector, p2-p1).
86
}
87
function showVD { toggle terDisplay. set vdTer to vecdraw(v(0,0,0), up:vector * 1, red, "", 1, true, 0.9, false). set vdSlope to vecdraw(v(0,0,0), up:vector * 1, yellow, "", 1, true, 0.4, true). set vdVel to vecdraw(v(0,0,0), up:vector * 1, blue, "", 1, true, 0.4, true). }
88
set terDisplay to false.
89-
set mul to 0.
89+
90-
set followDist to 0.
90+
91-
set hdgLag to hdg.
91+
92-
lock tv to heading(hdgLag,0):vector * sl.
92+
	set vdTer:width to 1 + (pi:mag^0.9) / 80.
93
	
94-
set tvCopyMag to 0.
94+
95-
set pitchoffset to 0.
95+
96
}
97
function tiltStar { 
98
	parameter tlt is 0. 
99
	if vsErr < -1 set tlt to tlt + tlt * max(-1, vsErr / 15). 
100
	set tlt to tlt + vang(up:vector,  facing:starvector) - 90.  
101
	set rollError to steeringmanager:rollpid:output.
102
	for hinge in allHinges hinge["s"]:setfield("target angle", tlt * hinge["right"] + tiltOutwards + min(15, max(-15,rollError * 40 * hinge["front"] * hinge["right"])) ).
103
}
104
function tilt { 
105
	parameter tlt is 0. if vsErr < -1  and (vdot(hvel:normalized, relVelVec) > -2 or vdot(tvCopy, hvel) < 0) set tlt to tlt + tlt * max(-1, vsErr / 20).
106
	set tlt to tlt + vang(up:vector,  facing:topvector) - 90. 
107-
set race to false.
107+
	for s in servos s:setfield("target angle", tlt). 
108-
when alt:radar > 10 then gear off.
108+
109
function goToTarget {
110
	if localport:istype("part") {
111-
set menu to gui(260, 30). Set menu:x to -30. set menu:y to 300. menu:show. 
111+
		lock tv to choose (vxcl(up:vector,target:position - localport:position):normalized * min(sl,(vxcl(up:vector,target:position - localport:position):mag/3)^0.70) + (choose target:velocity:surface if target:loaded else v(0,0,0))) if hastarget else v(0,0,0).
112
		
113
	} else {
114
		lock tv to choose (vxcl(up:vector,target:position):normalized * min(sl,(vxcl(up:vector,target:position):mag/3)^0.70) + (choose target:velocity:surface if target:loaded else v(0,0,0))) if hastarget else v(0,0,0).
115
	}
116
	set mode to "Target".
117
	if sl < 1 { set sl to 5. HUDTEXT("SL (speedlimit) is low, setting SL to 5..",16,2,20,yellow,false). }
118
}
119
function goToPosition {
120
	parameter pos.
121
	if pos:typename = "Vector" set pos to body:geopositionof(pos).
122
	set tgt to pos.
123
	lock tv to vxcl(up:vector,tgt:position):normalized * min(sl,(vxcl(up:vector,tgt:position):mag/3)^0.70) - (choose localport:position if localport:istype("part") else v(0,0,0)).
124-
set mLast to menu:addlabel("Functions: <color=white>goToTarget(), goToPosition(<geopos or position>), goTo(<Name>), resetSteering()</color>").
124+
125
	if sl < 1 { set sl to 5. HUDTEXT("SL (speedlimit) is low, setting SL to 5..",16,2,20,yellow,false). }
126-
set mIPU to menu:addlabel("IPU: ").
126+
127-
set mLast3 to menu:addlabel(".").
127+
function resetSteering { lock tv to heading(hdg,0):vector * sl. lock steering to st. set mode to "Heading". }
128-
set mLast4 to menu:addlabel(".").
128+
 
129-
set mAOA to menu:addlabel(".").
129+
130
//===[engine & servos setup]===
131
132-
for txt in menu:widgets { set txt:style:fontsize to 14. set txt:style:padding:v to 1. }
132+
133
set servos to list().
134
set yawServos to list().
135
for s in allServos { 
136-
wait 1.
136+
	if s:part:tag <> "yaw" { 
137
		s:setfield("damping", 80). s:setfield("traverse rate", 80). servos:add(s). 
138
	} else {
139
		yawServos:add(s).
140-
function vertThrust {
140+
141-
	if props return max(1, vdot(rotor1:facing:vector, up:vector) * 20).
141+
142
set allHinges to list().
143-
	set vth to 0.
143+
144-
	for e in engs if e:ignition {
144+
	m:setfield("damping", 80). m:setfield("traverse rate", 80).
145-
		set vth to vth + vdot(up:vector, e:facing:vector * (choose -1 if e:tag = "reverse" else 1)) * e:availablethrust.
145+
	local pPos is m:part:position.
146
	local l is lexicon("right", choose 1 if vdot(facing:starvector, pPos) > 0 else -1, "front", choose 1 if vdot(facing:topvector, pPos) < 0 else -1, "s", m).
147-
	return max(1,vth).
147+
148
	allHinges:add(l).
149
}
150
set twoaxistilt to (allHinges:length > 1).
151
if twoaxistilt HUDTEXT("2-axis engine tilting enabled. Toggle 'twoaxistilt' to disable",20,2,22,yellow,false).
152-
	set p1 to vxcl(u,facing:vector):normalized * (bnds:size:mag).
152+
153
set jets to false.
154
155
//===[PID controllers]===
156
if jets { 
157
	set tpid to pidloop(8,0.2, 9, -0.5, 4). 
158
} else { 
159
	set tpid to pidloop(5,0.2, 0.5, -1, 4). 
160
}
161
set vsPID to pidloop(1,1,1,-50,100).
162
set tltpid to pidloop(20, 2, 2, -55, 60).
163
set tltStarpid to pidloop(20, 2, 2, -35, 35).
164
165
166
//===[TRIGGER WARNING!]===
167-
function showVD { 
167+
168-
	toggle terDisplay. 
168+
on round(time:seconds * 5) { 
169-
	set vdTer to vecdraw(v(0,0,0), up:vector * 1, red, "", 1, true, 0.9). 
169+
    
170-
	set vdSlope to vecdraw(v(0,0,0), up:vector * 1, yellow, "", 1, true, 0.4). 
170+
171-
	set vdVel to vecdraw(v(0,0,0), up:vector * 1, blue, "", 1, true, 0.4).
171+
	return vtol. 
172-
	set vdAcc to vecdraw(v(0,0,0), up:vector * 1, green, "", 1, true, 0.3).
172+
173
//fast (50hz) trigger
174
when true then {
175
	set vel to velocity:surface.
176
	set hvel to vxcl(up:vector,vel).
177-
	set vdTer:width to 1 + (pi:mag^0.75) / 80.
177+
178
	set tvCopyMag to tvCopy:mag.
179
	set altErr to altitude - talt.
180
	
181
	//[Terrain detection and minimum climb angle]
182-
	set velDiff to vel-velOld.
182+
	set gi to body:geopositionof((hvel * (1.5 - terI/terSteps) + tvCopy * terI/terSteps):normalized * (groundspeed + (tvCopyMag + groundspeed)/2 * (terI^1.4) * terStepDist)). set pi to choose gi:position if gi:terrainheight > 0 else gi:altitudeposition(0).
183-
	set vdAcc:vec to (velDiff:normalized * (velDiff:mag/0.02)) / 10.
183+
	set tempSlope to max(-60,90 - vang(up:vector, pi + (angleaxis(terSlope, vcrs(hvel, up:vector)) * up:vector) * min(alt:radar + height * terI/terSteps,height))).
184-
	set velOld to vel.
184+
	if tempSlope > terSlope {
185
		set terSlope to tempSlope.
186
		set terJ to 0.
187
	} else {
188
		set terJ to terJ + 1.
189
		set terSlope2 to max(tempSlope, terSlope2 * 0.999 + 0.001 * tempSlope).
190-
	if vsErr < -1 set tlt to tlt + tlt * max(-1, vsErr / 8). 
190+
		if terJ > terSteps * 3 + 30 { set terJ to 0. set terSlope to terSlope2. set terSlope2 to max(-30, terSlope2 - 25).  }
191-
	set tlt to tlt + vang(up:vector,  face:starvector) - 90.  
191+
192-
	set rollError to steeringmanager:rollpid:output. // rollerror
192+
	if terDisplay terDisplayFunc().
193-
	for hinge in servosSideTilt hinge["s"]:setfield("target angle", tlt * hinge["direction"] * hinge["right"] + tiltOutwards + min(20, max(-20,(rollError * 40) * hinge["front"] * hinge["right"])) ).
193+
	set terI to terI + terStepDist.
194
	if terI > terSteps {
195
		set terI to terStepDist.
196
		//if terSlope > 0 set terSlope to max(terSlope, getSlope(vel:normalized * (sl * terSteps), vel:normalized * (sl * 2))).
197-
	//if vsErr < -1  and (vdot(hvel:normalized, relVelVec) > -2 or vdot(tvCopy, hvel) < 0) or race set tlt to tlt + tlt * max(-1, vsErr / 10).
197+
198-
	if vsErr < -1  set tlt to tlt + tlt * max(-1, vsErr / 10).
198+
199-
	set curPitch to choose (vang(up:vector,  face:topvector) - 90) if vdot(face:vector, up:vector) >= 0 else (90 + vang(up:vector, -facing:topvector)).
199+
200-
	set tlt to tlt + curPitch.
200+
	set slopeVS to choose 0 if tAltOverride else (tan(terSlope) * (groundspeed + (choose 0 if altErr < 0 else max(0,20 - groundspeed^1.5)))).
201-
	if tlt > 180 set tlt to tlt - 360.
201+
	set vs to choose vsOverride if vsOverride <> 0 else max(max(vsMin,slopeVS)  ,min(vsMax,   	choose (-1 * (1 * acc * max(altErr + min(0, verticalspeed * 1) ,0.0001))^0.4) if altErr > 0 else sqrt(2 * (grav/2) * max(-altErr - verticalspeed * 0.2,0.0001))         )).
202-
	set mLast4:text to "pitch tilt: " + round(tlt,2).
202+
203-
	for s in servos s["s"]:setfield("target angle", tlt). 
203+
204-
	//if tlt > 45 {
204+
205-
	//	for s in servos s["s"]:setfield("target angle", tlt + s["front"] * steeringmanager:pitcherror / -2). 
205+
206-
	//} else {
206+
207-
	//	for s in servos s["s"]:setfield("target angle", tlt). 
207+
208-
	//}
208+
209
210
	For b in blades b:getmodule("ModuleControlSurface"):setfield("deploy angle", deploy). 
211
	for rotor in rotors rotor:getmodulebyindex(1):setfield("rpm limit", rpmlimit).
212-
		lock tv to choose (vxcl(up:vector,(target:position + target:facing:vector * -followDist) - localport:position):normalized * min(sl,(vxcl(up:vector,(target:position + target:facing:vector * -followDist) - localport:position):mag/3)^0.75) + (choose target:velocity:surface if target:loaded else v(0,0,0))) if hastarget else v(0,0,0).
212+
213
	return vtol.
214
}
215-
		lock tv to choose (vxcl(up:vector,target:position + target:facing:vector * -followDist):normalized * min(sl,(vxcl(up:vector,target:position + target:facing:vector * -followDist):mag/3)^0.75) + (choose target:velocity:surface if target:loaded else v(0,0,0))) if hastarget else v(0,0,0).
215+
216
//12hz trigger - steering and engine tilt
217
on round(time:seconds * 12) {
218
	tilt(tltpid:update(time:seconds, vdot(facing:topvector, relVelVec))).
219
	
220
	set stTopVector to choose tvCopy * -1 if tvCopyMag > 2 else (choose -target:facing:topvector if hastarget else facing:topvector).
221
	if twoaxistilt {
222
		tiltStar(tltStarpid:update(time:seconds, vdot(facing:starvector, relVelVec))).
223
		set st to lookdirup(angleaxis(choose 0 if alt:radar < alignTerrainHeight else (min(tvCopyMag/2,max(-tvCopyMag/2,terSlope - vsErr/6))), -facing:starvector) * (vel / -500 + (choose norm() if alt:radar < alignTerrainHeight else up:vector) * 10 + vxcl(vxcl(up:vector,facing:topvector),relVelVec * sideTiltMult )), stTopVector).
224
	} else {
225
		set st to lookdirup(angleaxis(min(tvCopyMag/2,max(-tvCopyMag/2,terSlope - vsErr/6)), -facing:starvector) * (vel / -500 + up:vector * 10 + vxcl(vxcl(up:vector,facing:topvector),relVelVec * sideTiltMult )), stTopVector).
226
	}
227
	return vtol.
228-
function goto { 
228+
229-
	parameter where. 
229+
230-
	if not(defined places) { print "ERROR: places json not loaded.". }
230+
231-
	else if places:haskey(where) { gotoposition(places[where]). }
231+
232-
	else { print char(7)+ "ERROR: no known place: " + where. }
232+
233
234-
function resetSteering { lock tv to heading(hdgLag,0):vector * sl. lock steering to st. set mode to "Heading". set keepCamSteer to false. }
234+
235
set trackCam to true.
236-
function powerdown {
236+
set pitch to 12.
237-
	for s in ship:modulesnamed("ModuleRoboticServoRotor") s:setfield("torque limit(%)", 0).
237+
238-
	on height powerup().
238+
239
when trackCam then {
240-
function powerup {
240+
	set cam:position to cam:position * 0.9 + 0.1 * (co + angleaxis(pitch, facing:starvector) * (-vel / 50 + (-relVelVec/10 + facing:topvector):normalized * bnds:size:mag * 1.2)).
241-
	if props {
241+
242-
		set t0 to time:seconds.
242+
243-
		when true then {
243+
244-
			set tPercent to min(100,(time:seconds - t0) * 33).
244+
245-
			for s in ship:modulesnamed("ModuleRoboticServoRotor") s:setfield("torque limit(%)", tPercent).
245+
set menu to gui(200, 30). Set menu:x to -30. set menu:y to 300. menu:show. 
246-
			return tPercent < 100.
246+
247-
		}
247+
248
set m1 to menu:addlabel("SL:").
249
set m2 to menu:addlabel("HDG:").
250
set m3 to menu:addlabel("Height:").
251
set m4 to menu:addlabel("tAltOverride:").
252-
set engs to list().
252+
253-
list engines in engs2. for e in engs2 if e:tag <> "aft" engs:add(e).
253+
254
set m7 to menu:addlabel("trackCam:").
255
set m8 to menu:addlabel("alignTerrainHeight:").
256
set m9 to menu:addlabel("tiltOutwards:").
257-
set servosSideTilt to list().
257+
258
set mLast to menu:addlabel("Functions: <color=white>goToTarget(), goToPosition(<geopos or position>), resetSteering()</color>").
259-
	if s:part:tag = "yaw" {
259+
260
set mLast3 to menu:addlabel("").
261-
	} else if abs(vdot(facing:starvector, s:part:facing:vector)) > 0.5 { 
261+
set mLast4 to menu:addlabel("").
262-
		local sLex is lexicon("direction", 1, "right", choose 1 if vdot(face:starvector, s:part:position) > 0 else -1, "front", choose 1 if vdot(face:topvector, s:part:position) < 0 else -1, "s", s).
262+
263-
		servos:add(sLex).
263+
for txt in menu:widgets { set txt:style:fontsize to 10. set txt:style:padding:v to 1. }
264-
	} else if abs(vdot(facing:topvector, s:part:facing:vector)) > 0.5 {
264+
265-
		local sLex is lexicon("direction", choose -1 if vdot(facing:topvector, s:part:facing:vector) > 0 else 1,"right", choose 1 if vdot(face:starvector, s:part:position) > 0 else -1, "front", choose 1 if vdot(face:topvector, s:part:position) < 0 else -1, "s", s).
265+
266-
		servosSideTilt:add(sLex).
266+
267
	set m0:text to "Mode: <color=yellow>" + mode + "</color>".
268
	set m1:text to "SL: <color=white>" + round(sl,2) + "m/s</color> (" + round(tvCopyMag,1) + ")".
269
	set m2:text to "HDG: <color=white>" + round(hdg,2) + "</color>".
270
	
271
	set m3:text to (choose "<color=#222>Height: </color>" if vsOverride <> 0 or tAltOverride <> 0 else "Height: ") + "<color=white>" + height + "</color> (priority #3)".
272-
	if m:part:tag = "enginePitch" {
272+
	set m4:text to (choose "<color=#222>tAltOverride: </color>" if vsOverride <> 0 or tAltOverride = 0 else "tAltOverride: ")+ "<color=white>" + tAltOverride + "</color> (priority #2 if <> 0)".
273-
		local pitchEngLex is lexicon("right", 0, "front", 0, "s", m).
273+
	set m5:text to (choose "<color=#222>vsOverride: </color>" if vsOverride = 0  else "vsOverride: ") + "<color=white>" + vsOverride + "</color> (priority #1 if <> 0)".
274-
		servos:add(pitchEngLex).
274+
275
	set m7:text to "TrackCam: <color=white>" + trackCam + "</color>".
276-
	else if m:part:tag <> "ignore" {
276+
277-
		local pPos is m:part:position.
277+
278-
		local l is lexicon("direction", 1, "right", choose 1 if vdot(face:starvector, pPos) > 0 else -1, "front", choose 1 if vdot(face:topvector, pPos) < 0 else -1, "s", m).
278+
279-
		if not (props) and engs:length <= 2 set l["front"] to 0.
279+
280-
		servosSideTilt:add(l).
280+
281
when true then {
282
	set m6:text to "Alt:radar: " + round(alt:radar,2) + "m".
283-
for l in servos { l["s"]:setfield("damping", 100). l["s"]:setfield("traverse rate", 120). }
283+
284-
for l in servosSideTilt { l["s"]:setfield("damping", 50). l["s"]:setfield("traverse rate", 120). }
284+
	set mLast4:text to "mul: " + round(mul,2) + ", tpid:iterm: " + round(tpid:iterm,4).
285
	return menu:visible. 
286-
set twoaxistilt to (servosSideTilt:length > 1).
286+
287
on vtol menu:dispose.
288
clearscreen.
289
print "VTOL hover script running. See GUI for available variables and functions.".
290-
for e in engs if e:sealevelisp > 3000 jets on.
290+
291
set places to readjson("kerbin.json").
292
function gotoplace { parameter placename is "helipad". set dest to places[placename]. lock taltoverride to max(dest:terrainheight + 15, ship:geoposition:terrainheight + 15). gotoposition(dest). }.
293-
if props {
293+
294-
	set aoaPID to pidloop(1.5, 0, 0, -2, 5). 
294+
295-
} else if jets { 
295+
296