Skip to content

Commit 082cb85

Browse files
committed
lua: cruise control example
By Dmitriy Zav only:uaefi
1 parent e3804ad commit 082cb85

1 file changed

Lines changed: 162 additions & 0 deletions

File tree

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
-- Cruise Control + Check Engine LED
2+
--
3+
-- Hardware:
4+
-- LED : PWM output 0, 50 Hz
5+
-- Buttons : AuxAnalog 0, resistor-ladder
6+
-- Set : 0.75-1.40 V -- engage / disengage cruise 4x4.7k in parallel
7+
-- Decrease : 1.80-2.70 V -- target RPM - RPM_STEP 2x4.7k in parallel
8+
-- Increase : 2.90-3.55 V -- target RPM + RPM_STEP 1x4.7k
9+
-- No button : all other voltages
10+
-- Brake pedal : getOutput("brakePedalState")
11+
--
12+
-- LED priority (highest first):
13+
-- 1. Fault (CLT > 100) -- blink 1 s period, 100 %
14+
-- 2. Engine stopped (RPM = 0) -- 100 % steady
15+
-- 3. Cruise active -- 50 % steady
16+
-- 4. Normal run -- off
17+
18+
-- ========= tuneable constants =========
19+
local CRUISE_MIN_RPM = 1200 -- minimum RPM to allow engagement
20+
local CRUISE_MAX_RPM = 4000 -- RPM above this forces disengagement
21+
local RPM_STEP = 100 -- RPM per increase / decrease press
22+
local CLT_FAULT_TEMP = 100 -- degrees C for fault LED blink
23+
local PID_KP = 0.02 -- %ETB per RPM of error
24+
local PID_KI = 0.003 -- integrator gain
25+
local PID_MIN = 0.0 -- don't wont to decrease ETB below baseline
26+
local PID_MAX = 50.0 -- limit max ETB increase to avoid big throttle jumps
27+
local BLINK_HALF = 0.5 -- fault blink half-period [s]
28+
local DEBOUNCE = 20 -- ticks of stable reading (~100 ms at 200 Hz)
29+
-- ======================================
30+
31+
-- button state constants
32+
local BTN_NONE = 0
33+
local BTN_SET = 1
34+
local BTN_DECREASE = 2
35+
local BTN_INCREASE = 3
36+
37+
startPwm(0, 50, 0) -- LED: PWM output 0, 50 Hz, off
38+
39+
local pid = Pid.new(PID_KP, PID_KI, 0, PID_MIN, PID_MAX)
40+
41+
local cruiseActive = false
42+
local targetRpm = 0
43+
44+
-- debounce state
45+
local btnCandidate = BTN_NONE
46+
local btnCount = 0
47+
local btnStable = BTN_NONE
48+
local btnPrev = BTN_NONE
49+
50+
-- LED blink state
51+
local blinkTimer = Timer.new()
52+
local blinkOn = false
53+
54+
-- ---- helpers ----
55+
56+
local function readBtn()
57+
local v = getAuxAnalog(0)
58+
if v == nil then return BTN_NONE end
59+
if v >= 0.75 and v <= 1.40 then return BTN_SET end
60+
if v >= 1.80 and v <= 2.70 then return BTN_DECREASE end
61+
if v >= 2.90 and v <= 3.55 then return BTN_INCREASE end
62+
return BTN_NONE
63+
end
64+
65+
local function disengageCruise()
66+
cruiseActive = false
67+
pid:reset()
68+
setEtbAdd(0)
69+
setLuaGauge(1, 0)
70+
setLuaGauge(2, 0)
71+
print("Cruise OFF")
72+
end
73+
74+
-- ---- main loop ----
75+
76+
function onTick()
77+
local rpm = getSensor("RPM") or 0
78+
79+
-- ---- button debounce ----
80+
local raw = readBtn()
81+
if raw == btnCandidate then
82+
btnCount = btnCount + 1
83+
if btnCount >= DEBOUNCE then btnStable = btnCandidate end
84+
else
85+
btnCandidate = raw
86+
btnCount = 1
87+
end
88+
89+
-- ---- single-fire edge detection (none -> button) ----
90+
if btnStable ~= BTN_NONE and btnPrev == BTN_NONE then
91+
if btnStable == BTN_SET then
92+
if not cruiseActive then
93+
if rpm >= CRUISE_MIN_RPM then
94+
cruiseActive = true
95+
targetRpm = rpm
96+
pid:reset()
97+
print("Cruise ON target=" .. math.floor(rpm) .. " RPM")
98+
else
99+
print("Cruise: RPM too low (" .. math.floor(rpm) .. ")")
100+
end
101+
else
102+
disengageCruise()
103+
end
104+
elseif cruiseActive then
105+
if btnStable == BTN_INCREASE then
106+
targetRpm = targetRpm + RPM_STEP
107+
elseif btnStable == BTN_DECREASE then
108+
targetRpm = math.max(CRUISE_MIN_RPM, targetRpm - RPM_STEP)
109+
end
110+
pid:reset()
111+
print("Cruise target=" .. math.floor(targetRpm) .. " RPM")
112+
end
113+
end
114+
btnPrev = btnStable
115+
116+
-- ---- auto-disengage ----
117+
if cruiseActive then
118+
local brake = getOutput("brakePedalState")
119+
if (brake ~= nil and brake > 0) then
120+
print("Cruise OFF: brake")
121+
disengageCruise()
122+
elseif rpm > CRUISE_MAX_RPM then
123+
print("Cruise OFF: RPM " .. math.floor(rpm))
124+
disengageCruise()
125+
end
126+
end
127+
128+
-- ---- ETB PI control ----
129+
if cruiseActive then
130+
local adj = pid:get(targetRpm, rpm)
131+
setEtbAdd(adj)
132+
setLuaGauge(1, adj)
133+
setLuaGauge(2, targetRpm)
134+
else
135+
setEtbAdd(0)
136+
end
137+
138+
-- ---- LED ----
139+
local clt = getSensor("Clt")
140+
local fault = clt ~= nil and clt > CLT_FAULT_TEMP
141+
local stopped = rpm == 0
142+
143+
local duty
144+
if fault then
145+
if blinkTimer:getElapsedSeconds() >= BLINK_HALF then
146+
blinkOn = not blinkOn
147+
blinkTimer:reset()
148+
end
149+
duty = blinkOn and 1.0 or 0.0
150+
elseif stopped then
151+
blinkOn = false ; blinkTimer:reset()
152+
duty = 1.0
153+
elseif cruiseActive then
154+
blinkOn = false ; blinkTimer:reset()
155+
duty = 0.5
156+
else
157+
blinkOn = false ; blinkTimer:reset()
158+
duty = 0.0
159+
end
160+
161+
setPwmDuty(0, duty)
162+
end

0 commit comments

Comments
 (0)