Skip to content

Commit 4c6af52

Browse files
authored
Merge pull request #203 from sensei-hacker/attitude_indicator
Jetrell wants to have an attitude
2 parents 20f39d6 + d8faf45 commit 4c6af52

7 files changed

Lines changed: 331 additions & 147 deletions

File tree

src/SCRIPTS/TELEMETRY/iNav/config.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ local config = {
3737
{ o = 26, c = 1, v = 0 }, -- Roll Scale - 33
3838
{ o = 34, c = 1, v = 0, l = {[0] = "?"}, x = -1 }, -- Review Log Date - 34
3939
{ o = 35, c = 1, v = 0 }, -- Greyscale toggle - 35
40+
{ o = 36, c = 1, v = 0 }, -- Horizon Mode - 36
4041
}
4142

4243
for i = 1, #config do

src/SCRIPTS/TELEMETRY/iNav/horus.lua

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ local function view(data, config, modes, dir, units, labels, gpsDegMin, hdopGrap
137137

138138
-- Draw ground
139139
local gflag = data.set_flags(0, GROUND)
140-
if skip then
140+
local fixedHorizon = config[36] ~= nil and config[36].v == 1
141+
if fixedHorizon then
142+
-- Fixed horizon: flat ground below center
143+
fill(tl.x, Y_CNTR, br.x - tl.x + 1, br.y - Y_CNTR + 1, gflag)
144+
line(tl.x, Y_CNTR, br.x, Y_CNTR, SOLID, data.set_flags(0, LIGHTGREY))
145+
elseif skip then
141146
-- Must be going down hard!
142147
if (pitch - 90) * (upsideDown and -1 or 1) < 0 then
143148
fill(tl.x, tl.y, br.x - tl.x + 1, br.y - tl.y + 1, gflag)
@@ -237,10 +242,12 @@ local function view(data, config, modes, dir, units, labels, gpsDegMin, hdopGrap
237242
-- Pitch ladder
238243
if data.telem then
239244
tmp = pitch - 90
240-
local tmp2 = max(min((tmp >= 0 and floor(tmp * 0.2) or math.ceil(tmp * 0.2)) * 5, 30), -30)
241-
for x = tmp2 - 20, tmp2 + 20, 5 do
242-
if x ~= 0 and (x % 10 == 0 or (x > -30 and x < 30)) then
243-
pitchLadder(x % 10 == 0 and 20 or 15, x)
245+
if not fixedHorizon then
246+
local tmp2 = max(min((tmp >= 0 and floor(tmp * 0.2) or math.ceil(tmp * 0.2)) * 5, 30), -30)
247+
for x = tmp2 - 20, tmp2 + 20, 5 do
248+
if x ~= 0 and (x % 10 == 0 or (x > -30 and x < 30)) then
249+
pitchLadder(x % 10 == 0 and 20 or 15, x)
250+
end
244251
end
245252
end
246253

@@ -324,8 +331,36 @@ local function view(data, config, modes, dir, units, labels, gpsDegMin, hdopGrap
324331
end
325332
end
326333

327-
-- View overlay
328-
bmap(icons.fg, 1, 20)
334+
-- View overlay / aircraft symbol
335+
if fixedHorizon then
336+
-- Fixed horizon mode: aircraft symbol moves with pitch/roll
337+
local py = Y_CNTR - (pitch - 90) * DEGV / 90
338+
py = max(TOP + 10, min(BOTTOM - 10, py))
339+
local r = rad(roll - 90)
340+
local s, c = sin(r), cos(r)
341+
local wing = 40
342+
local gap = 8
343+
local ycol = data.set_flags(0, OYELLOW)
344+
local oc = data.set_flags(0, BLACK)
345+
-- Wing bars: perpendicular-offset lines for thickness (5px: 3 yellow + 2 black outline)
346+
for d = -2, 2 do
347+
local col = (d > -2 and d < 2) and ycol or oc
348+
local ox, oy = -s * d, c * d
349+
line(X_CNTR - c * wing + ox, py + s * wing + oy, X_CNTR - c * gap + ox, py + s * gap + oy, SOLID, col)
350+
line(X_CNTR + c * gap + ox, py - s * gap + oy, X_CNTR + c * wing + ox, py - s * wing + oy, SOLID, col)
351+
end
352+
-- Tail (points up from center when level)
353+
local tail = 15
354+
for d = -1, 1 do
355+
local col = d == 0 and ycol or oc
356+
line(X_CNTR, py + d, X_CNTR - s * tail, py - c * tail + d, SOLID, col)
357+
end
358+
-- Center dot
359+
fill(X_CNTR - 2, py - 2, 5, 5, oc)
360+
fill(X_CNTR - 1, py - 1, 3, 3, ycol)
361+
else
362+
bmap(icons.fg, 1, 20)
363+
end
329364

330365
-- Speed & altitude
331366
tmp = data.showMax and data.speedMax or data.speed

src/SCRIPTS/TELEMETRY/iNav/menu.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ local function view(data, config, units, lang, event, gpsDegMin, getTelemetryId,
4545
{ t = "Roll Scale", l = 1 }, -- 33
4646
{ t = "Playback Log", l = config[34].l }, -- 34
4747
{ t = "Greyscale Gfx", l = {[0] = "On", "Off"} }, -- 35
48+
{ t = "Horizon Mode", l = {[0] = "Standard", "Fixed"} }, -- 36
4849
}
4950

5051
-- Import language changes

src/SCRIPTS/TELEMETRY/iNav/nirvana.lua

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,12 @@ local function view(data, config, modes, dir, units, labels, gpsDegMin, hdopGrap
139139

140140
-- Draw ground
141141
local gflag = data.set_flags(0, GROUND)
142-
if skip then
142+
local fixedHorizon = config[36] ~= nil and config[36].v == 1
143+
if fixedHorizon then
144+
-- Fixed horizon: flat ground below center
145+
fill(tl.x, Y_CNTR, br.x - tl.x + 1, br.y - Y_CNTR + 1, gflag)
146+
line(tl.x, Y_CNTR, br.x, Y_CNTR, SOLID, data.set_flags(0, LIGHTGREY))
147+
elseif skip then
143148
-- Must be going down hard!
144149
if (pitch - 90) * (upsideDown and -1 or 1) < 0 then
145150
fill(tl.x, tl.y, br.x - tl.x + 1, br.y - tl.y + 1, gflag)
@@ -239,10 +244,12 @@ local function view(data, config, modes, dir, units, labels, gpsDegMin, hdopGrap
239244
-- Pitch ladder
240245
if data.telem then
241246
tmp = pitch - 90
242-
local tmp2 = max(min((tmp >= 0 and floor(tmp * 0.2) or math.ceil(tmp * 0.2)) * 5, 30), -30)
243-
for x = tmp2 - 20, tmp2 + 20, 5 do
244-
if x ~= 0 and (x % 10 == 0 or (x > -30 and x < 30)) then
245-
pitchLadder(x % 10 == 0 and 20 or 15, x)
247+
if not fixedHorizon then
248+
local tmp2 = max(min((tmp >= 0 and floor(tmp * 0.2) or math.ceil(tmp * 0.2)) * 5, 30), -30)
249+
for x = tmp2 - 20, tmp2 + 20, 5 do
250+
if x ~= 0 and (x % 10 == 0 or (x > -30 and x < 30)) then
251+
pitchLadder(x % 10 == 0 and 20 or 15, x)
252+
end
246253
end
247254
end
248255
if not data.showMax then
@@ -323,8 +330,36 @@ local function view(data, config, modes, dir, units, labels, gpsDegMin, hdopGrap
323330
end
324331
end
325332

326-
-- View overlay
327-
bmap(icons.fg, 1, 20)
333+
-- View overlay / aircraft symbol
334+
if fixedHorizon then
335+
-- Fixed horizon mode: aircraft symbol moves with pitch/roll
336+
local py = Y_CNTR - (pitch - 90) * DEGV / 90
337+
py = max(TOP + 10, min(BOTTOM - 10, py))
338+
local r = rad(roll - 90)
339+
local s, c = sin(r), cos(r)
340+
local wing = 35
341+
local ycol = data.set_flags(0, OYELLOW)
342+
local oc = data.set_flags(0, BLACK)
343+
-- Rotated wings (with black outline, perpendicular thickness)
344+
local gap = 8
345+
for d = -2, 2 do
346+
local col = (d > -2 and d < 2) and ycol or oc
347+
local ox, oy = -s * d, c * d
348+
line(X_CNTR - c * wing + ox, py + s * wing + oy, X_CNTR - c * gap + ox, py + s * gap + oy, SOLID, col)
349+
line(X_CNTR + c * gap + ox, py - s * gap + oy, X_CNTR + c * wing + ox, py - s * wing + oy, SOLID, col)
350+
end
351+
-- Tail
352+
local tail = 15
353+
for d = -1, 1 do
354+
local col = (d == 0) and ycol or oc
355+
line(X_CNTR, py + d, X_CNTR - s * tail, py - c * tail + d, SOLID, col)
356+
end
357+
-- Center dot
358+
fill(X_CNTR - 2, py - 2, 5, 5, oc)
359+
fill(X_CNTR - 1, py - 1, 3, 3, ycol)
360+
else
361+
bmap(icons.fg, 1, 20)
362+
end
328363
--line(0, BOTTOM, RIGHT_POS, BOTTOM, SOLID, DKGREY)
329364
line(0, BOTTOM + 1, RIGHT_POS, BOTTOM + 1, SOLID, data.set_flags(0, MAP))
330365
local telemCol = (data.telem) and data.TextColor or RED

src/SCRIPTS/TELEMETRY/iNav/pilot.lua

Lines changed: 111 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,20 @@ local function view(data, config, modes, dir, units, labels, gpsDegMin, hdopGrap
9898
upsideDown = data.accz < 0
9999
end
100100
roll1 = math.rad(roll)
101+
local fixedHorizon = config[36] ~= nil and config[36].v == 1
101102
if data.startup == 0 and data.telem then
102103
tmp = pitch - 90
103-
local short = SMLCD and 4 or 6
104-
local tmp2 = math.max(math.min((tmp >= 0 and math.floor(tmp * 0.2) or math.ceil(tmp * 0.2)) * 5, 35), -35)
105-
for x = tmp2 - 15, tmp2 + 15, 5 do
106-
if x ~= 0 and (x % 10 == 0 or (x > -30 and x < 30)) then
107-
pitchLadder(x % 10 == 0 and 11 or short, x)
104+
if not fixedHorizon then
105+
local short = SMLCD and 4 or 6
106+
local tmp2 = math.max(math.min((tmp >= 0 and math.floor(tmp * 0.2) or math.ceil(tmp * 0.2)) * 5, 35), -35)
107+
for x = tmp2 - 15, tmp2 + 15, 5 do
108+
if x ~= 0 and (x % 10 == 0 or (x > -30 and x < 30)) then
109+
pitchLadder(x % 10 == 0 and 11 or short, x)
110+
end
108111
end
109112
end
110113
if not data.showMax then
111-
tmp2 = tmp >= 0 and (tmp < 1 and 0 or math.floor(tmp + 0.5)) or (tmp > -1 and 0 or math.ceil(tmp - 0.5))
114+
local tmp2 = tmp >= 0 and (tmp < 1 and 0 or math.floor(tmp + 0.5)) or (tmp > -1 and 0 or math.ceil(tmp - 0.5))
112115
text(X_CNTR - (SMLCD and 14 or 24), 33, math.abs(tmp2) .. (SMLCD and "" or "\64"), SMLSIZE + RIGHT)
113116
end
114117
end
@@ -187,74 +190,114 @@ local function view(data, config, modes, dir, units, labels, gpsDegMin, hdopGrap
187190
end
188191

189192
-- Attitude part 2 (artificial horizon)
190-
fill(X_CNTR - 1, 34, 3, 3, ERASE)
191-
local x = math.sin(roll1) * 200
192-
local y = math.cos(roll1) * 200
193-
local p = math.cos(math.rad(pitch)) * 85
194-
local x1, y1, x2, y2 = X_CNTR - x - 2.5, 35 + y - p, X_CNTR + x - 2.5, 35 - y - p
195-
local a = (y2 - y1) / (x2 - x1 + .001)
196-
local y = y1 - ((x1 - LEFT_POS + 1) * a)
197-
--[[ Old slower method
198-
for x = LEFT_POS + 1, RIGHT_POS - 1 do
199-
local yy = y + 0.5
200-
if (not upsideDown and yy < 64) or (upsideDown and yy > 7) then
201-
line(x, math.min(math.max(yy, 8), 63), x, upsideDown and 8 or 63, SOLID, (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT)
193+
if fixedHorizon then
194+
-- Fixed horizon: flat ground below center
195+
local gcolor = (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT
196+
fill(LEFT_POS + 1, 36, RIGHT_POS - LEFT_POS - 2, 28, gcolor)
197+
line(LEFT_POS + 1, 35, RIGHT_POS - 1, 35, SOLID, SMLCD and 0 or FORCE)
198+
-- Moving aircraft symbol
199+
local py = 35 - (pitch - 90) * 85 / 90
200+
py = math.max(17, math.min(54, py))
201+
local r = math.rad(roll - 90)
202+
local s, c = math.sin(r), math.cos(r)
203+
local w = SMLCD and 10 or 18
204+
local lf = SMLCD and 0 or FORCE
205+
-- Erase area around aircraft symbol
206+
local et = math.max(8, py - w - 2)
207+
fill(X_CNTR - w - 2, et, w * 2 + 5, math.min(64, py + w + 2) - et + 1, ERASE)
208+
-- Redraw ground behind symbol if needed
209+
if py + w + 2 > 35 then
210+
local gt = math.max(36, py - w - 2)
211+
fill(X_CNTR - w - 2, gt, w * 2 + 5, math.min(64, py + w + 2) - gt, gcolor)
202212
end
203-
y = y + a
204-
end
205-
]]
206-
-- Faster method
207-
local width = math.min(math.max(4 - math.ceil(math.abs(roll - 90) * 0.05), 1), 3)
208-
for x = LEFT_POS + 1, RIGHT_POS - 1, width do
209-
local yy = y + 0.5
210-
if (not upsideDown and yy < 64) or (upsideDown and yy > 7) then
211-
local t = upsideDown and 8 or math.min(math.max(yy, 8), 63)
212-
local h = upsideDown and math.min(math.max(yy, 8), 64) - t or 65 - t
213-
fill(x, t, width, h, (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT)
213+
-- Rotated wing lines (perpendicular thickness)
214+
local gap = SMLCD and 3 or 5
215+
for d = -1, 1 do
216+
local ox, oy = -s * d, c * d
217+
line(X_CNTR - c * w + ox, py + s * w + oy, X_CNTR - c * gap + ox, py + s * gap + oy, SOLID, lf)
218+
line(X_CNTR + c * gap + ox, py - s * gap + oy, X_CNTR + c * w + ox, py - s * w + oy, SOLID, lf)
214219
end
215-
y = y + a * width
216-
end
217-
--[[ Even faster?
218-
local width = math.min(math.max(4 - math.ceil(math.abs(roll - 90) * 0.05), 1), 3)
219-
local lastx = -1
220-
for x = LEFT_POS + 1, RIGHT_POS - 1, width do
221-
if upsideDown then
222-
if y > 8 then
223-
local h = math.min(math.max(y + 0.5, 8), 64) - 8
224-
if roll > 90 and h == 56 then
225-
lastx = x
226-
break
227-
end
228-
fill(x, 8, width, h, (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT)
229-
end
220+
-- Tail line
221+
local tail = SMLCD and 6 or 10
222+
line(X_CNTR, py, X_CNTR - s * tail, py - c * tail, SOLID, lf)
223+
-- Center dot
224+
line(X_CNTR - 1, py, X_CNTR + 1, py, SOLID, lf)
225+
if SMLCD then
226+
lcd.drawPoint(X_CNTR, py - 1, 0)
227+
lcd.drawPoint(X_CNTR, py + 1, 0)
230228
else
231-
if y < 64 then
232-
local t = math.min(math.max(y + 0.5, 8), 63)
233-
if roll < 90 and t == 8 then
234-
lastx = x
235-
break
229+
line(X_CNTR, py - 1, X_CNTR, py + 1, SOLID, FORCE)
230+
end
231+
else
232+
fill(X_CNTR - 1, 34, 3, 3, ERASE)
233+
local x = math.sin(roll1) * 200
234+
local y = math.cos(roll1) * 200
235+
local p = math.cos(math.rad(pitch)) * 85
236+
local x1, y1, x2, y2 = X_CNTR - x - 2.5, 35 + y - p, X_CNTR + x - 2.5, 35 - y - p
237+
local a = (y2 - y1) / (x2 - x1 + .001)
238+
local y = y1 - ((x1 - LEFT_POS + 1) * a)
239+
--[[ Old slower method
240+
for x = LEFT_POS + 1, RIGHT_POS - 1 do
241+
local yy = y + 0.5
242+
if (not upsideDown and yy < 64) or (upsideDown and yy > 7) then
243+
line(x, math.min(math.max(yy, 8), 63), x, upsideDown and 8 or 63, SOLID, (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT)
244+
end
245+
y = y + a
246+
end
247+
]]
248+
-- Faster method
249+
local width = math.min(math.max(4 - math.ceil(math.abs(roll - 90) * 0.05), 1), 3)
250+
for x = LEFT_POS + 1, RIGHT_POS - 1, width do
251+
local yy = y + 0.5
252+
if (not upsideDown and yy < 64) or (upsideDown and yy > 7) then
253+
local t = upsideDown and 8 or math.min(math.max(yy, 8), 63)
254+
local h = upsideDown and math.min(math.max(yy, 8), 64) - t or 65 - t
255+
fill(x, t, width, h, (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT)
256+
end
257+
y = y + a * width
258+
end
259+
--[[ Even faster?
260+
local width = math.min(math.max(4 - math.ceil(math.abs(roll - 90) * 0.05), 1), 3)
261+
local lastx = -1
262+
for x = LEFT_POS + 1, RIGHT_POS - 1, width do
263+
if upsideDown then
264+
if y > 8 then
265+
local h = math.min(math.max(y + 0.5, 8), 64) - 8
266+
if roll > 90 and h == 56 then
267+
lastx = x
268+
break
269+
end
270+
fill(x, 8, width, h, (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT)
271+
end
272+
else
273+
if y < 64 then
274+
local t = math.min(math.max(y + 0.5, 8), 63)
275+
if roll < 90 and t == 8 then
276+
lastx = x
277+
break
278+
end
279+
fill(x, t, width, 65 - t, (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT)
236280
end
237-
fill(x, t, width, 65 - t, (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT)
238281
end
282+
y = y + a * width
283+
end
284+
if lastx then
285+
fill(lastx, 8, RIGHT_POS - lastx, 57, (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT)
286+
end
287+
]]
288+
local inside = SMLCD and 6 or 13
289+
local outside = SMLCD and 14 or 24
290+
line(X_CNTR - outside, 35, X_CNTR - inside, 35, SOLID, SMLCD and 0 or FORCE)
291+
line(X_CNTR + outside, 35, X_CNTR + inside, 35, SOLID, SMLCD and 0 or FORCE)
292+
line(X_CNTR - inside, 36, X_CNTR - inside, SMLCD and 37 or 38, SOLID, SMLCD and 0 or FORCE)
293+
line(X_CNTR + inside, 36, X_CNTR + inside, SMLCD and 37 or 38, SOLID, SMLCD and 0 or FORCE)
294+
line(X_CNTR - 1, 35, X_CNTR + 1, 35, SOLID, SMLCD and 0 or FORCE)
295+
if SMLCD then
296+
lcd.drawPoint(X_CNTR, 34, 0)
297+
lcd.drawPoint(X_CNTR, 36, 0)
298+
else
299+
line(X_CNTR, 34, X_CNTR, 36, SOLID, FORCE)
239300
end
240-
y = y + a * width
241-
end
242-
if lastx then
243-
fill(lastx, 8, RIGHT_POS - lastx, 57, (SMLCD or config[35].v == 1) and 0 or GREY_DEFAULT)
244-
end
245-
]]
246-
local inside = SMLCD and 6 or 13
247-
local outside = SMLCD and 14 or 24
248-
line(X_CNTR - outside, 35, X_CNTR - inside, 35, SOLID, SMLCD and 0 or FORCE)
249-
line(X_CNTR + outside, 35, X_CNTR + inside, 35, SOLID, SMLCD and 0 or FORCE)
250-
line(X_CNTR - inside, 36, X_CNTR - inside, SMLCD and 37 or 38, SOLID, SMLCD and 0 or FORCE)
251-
line(X_CNTR + inside, 36, X_CNTR + inside, SMLCD and 37 or 38, SOLID, SMLCD and 0 or FORCE)
252-
line(X_CNTR - 1, 35, X_CNTR + 1, 35, SOLID, SMLCD and 0 or FORCE)
253-
if SMLCD then
254-
lcd.drawPoint(X_CNTR, 34, 0)
255-
lcd.drawPoint(X_CNTR, 36, 0)
256-
else
257-
line(X_CNTR, 34, X_CNTR, 36, SOLID, FORCE)
258301
end
259302

260303
-- Heading part 2

0 commit comments

Comments
 (0)