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 |