Skip to content

Commit 27cae8c

Browse files
authored
Merge pull request #73 from openppg/7-2-cleanup
7.2 cleanup
2 parents 93edb8f + ca8856b commit 27cae8c

File tree

19 files changed

+691
-125
lines changed

19 files changed

+691
-125
lines changed

CPPLINT.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
linelength=140
2+
filter=-legal/copyright,-runtime/int,-build/include_subdir,-readability/casting,-readability/todo,-build/include_order,-build/include_what_you_use

inc/sp140/monitor_config.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,24 @@
66
// This file serves as the single source of truth for all sensor monitoring thresholds.
77

88
// -- ESC Thresholds --
9-
static const Thresholds escMosTempThresholds = {.warnLow = -10, .warnHigh = 90, .critLow = -20, .critHigh = 110};
10-
static const Thresholds escMcuTempThresholds = {.warnLow = -10, .warnHigh = 80, .critLow = -20, .critHigh = 95};
11-
static const Thresholds escCapTempThresholds = {.warnLow = -10, .warnHigh = 85, .critLow = -20, .critHigh = 100};
12-
static const Thresholds motorTempThresholds = {.warnLow = -20, .warnHigh = 105, .critLow = -25, .critHigh = 115};
9+
static const Thresholds escMosTempThresholds = {.warnLow = -10, .warnHigh = 90, .critLow = -20, .critHigh = 110, .hysteresis = 2.0f};
10+
static const Thresholds escMcuTempThresholds = {.warnLow = -10, .warnHigh = 80, .critLow = -20, .critHigh = 95, .hysteresis = 2.0f};
11+
static const Thresholds escCapTempThresholds = {.warnLow = -10, .warnHigh = 85, .critLow = -20, .critHigh = 100, .hysteresis = 2.0f};
12+
static const Thresholds motorTempThresholds = {.warnLow = -20, .warnHigh = 105, .critLow = -25, .critHigh = 115, .hysteresis = 2.0f};
1313

1414
// -- BMS Thresholds --
15-
static const Thresholds bmsTempThresholds = {.warnLow = -10, .warnHigh = 50, .critLow = -15, .critHigh = 60};
16-
static const Thresholds bmsCellTempThresholds = {.warnLow = -10, .warnHigh = 50, .critLow = -15, .critHigh = 56};
17-
static const Thresholds bmsHighCellVoltageThresholds = {.warnLow = 0.0, .warnHigh = 4.18, .critLow = 0.0, .critHigh = 4.20};
15+
static const Thresholds bmsTempThresholds = {.warnLow = -10, .warnHigh = 50, .critLow = -15, .critHigh = 60, .hysteresis = 2.0f};
16+
static const Thresholds bmsCellTempThresholds = {.warnLow = -10, .warnHigh = 50, .critLow = -15, .critHigh = 56, .hysteresis = 2.0f};
17+
static const Thresholds bmsHighCellVoltageThresholds = {.warnLow = 0.0, .warnHigh = 4.19, .critLow = 0.0, .critHigh = 4.20};
1818
static const Thresholds bmsLowCellVoltageThresholds = {.warnLow = 3.2, .warnHigh = 4.5, .critLow = 3.0, .critHigh = 4.8};
1919
static const Thresholds bmsSOCThresholds = {.warnLow = 15.0, .warnHigh = 101.0, .critLow = 5.0, .critHigh = 110.0};
2020
static const Thresholds bmsTotalVoltageThresholds = {.warnLow = 79.2, .warnHigh = 100.4, .critLow = 69.6, .critHigh = 100.8};
2121
static const Thresholds bmsVoltageDifferentialThresholds = {.warnLow = -1.0, .warnHigh = 0.2, .critLow = -2.0, .critHigh = 0.4};
2222

2323
// -- Altimeter Thresholds --
24-
static const Thresholds baroTempThresholds = {.warnLow = 0, .warnHigh = 50, .critLow = -10, .critHigh = 80};
24+
static const Thresholds baroTempThresholds = {.warnLow = 0, .warnHigh = 50, .critLow = -10, .critHigh = 80, .hysteresis = 2.0f};
2525

2626
// -- Internal Thresholds --
27-
static const Thresholds cpuTempThresholds = {.warnLow = 0, .warnHigh = 60, .critLow = -10, .critHigh = 80};
27+
static const Thresholds cpuTempThresholds = {.warnLow = 0, .warnHigh = 60, .critLow = -10, .critHigh = 80, .hysteresis = 2.0f};
2828

2929
#endif // INC_SP140_MONITOR_CONFIG_H_

inc/sp140/simple_monitor.h

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,14 @@ enum class SensorID {
7070
// Alert levels
7171
enum class AlertLevel { OK, WARN_LOW, WARN_HIGH, CRIT_LOW, CRIT_HIGH, INFO };
7272

73-
// Threshold set
73+
// Threshold set with hysteresis support
7474
struct Thresholds {
7575
float warnLow, warnHigh;
7676
float critLow, critHigh;
77+
78+
// Hysteresis value - must be positive
79+
// This defines the deadband around all thresholds to prevent bouncing
80+
float hysteresis;
7781
};
7882

7983
// Logger interface
@@ -167,6 +171,67 @@ struct SensorMonitor : public IMonitor {
167171
}
168172
};
169173

174+
// Enhanced sensor monitor with hysteresis to prevent alert bouncing
175+
struct HysteresisSensorMonitor : public SensorMonitor {
176+
// Constructor - inherits all member variables from SensorMonitor
177+
HysteresisSensorMonitor(SensorID i, SensorCategory cat, Thresholds t, std::function<float()> r, ILogger* l)
178+
: SensorMonitor(i, cat, t, r, l) {}
179+
180+
void check() override {
181+
float v = read();
182+
AlertLevel now = last; // Start with current state
183+
184+
// Hysteresis logic to prevent bouncing
185+
switch (last) {
186+
case AlertLevel::OK:
187+
// From OK, we can transition to warnings/criticals
188+
if (v <= thr.critLow) now = AlertLevel::CRIT_LOW;
189+
else if (v <= thr.warnLow) now = AlertLevel::WARN_LOW;
190+
else if (v >= thr.critHigh) now = AlertLevel::CRIT_HIGH;
191+
else if (v >= thr.warnHigh) now = AlertLevel::WARN_HIGH;
192+
break;
193+
194+
case AlertLevel::WARN_LOW:
195+
// From WARN_LOW, need to go below warnLow - hysteresis to clear
196+
// Or escalate to critical if still below critLow + hysteresis
197+
if (v <= thr.critLow + thr.hysteresis) now = AlertLevel::CRIT_LOW;
198+
else if (v > thr.warnLow + thr.hysteresis) now = AlertLevel::OK;
199+
break;
200+
201+
case AlertLevel::WARN_HIGH:
202+
// From WARN_HIGH, need to go below warnHigh - hysteresis to clear
203+
// Or escalate to critical if still above critHigh - hysteresis
204+
if (v >= thr.critHigh - thr.hysteresis) now = AlertLevel::CRIT_HIGH;
205+
else if (v < thr.warnHigh - thr.hysteresis) now = AlertLevel::OK;
206+
break;
207+
208+
case AlertLevel::CRIT_LOW:
209+
// From CRIT_LOW, need to go above critLow + hysteresis to de-escalate
210+
if (v > thr.critLow + thr.hysteresis) {
211+
if (v <= thr.warnLow + thr.hysteresis) now = AlertLevel::WARN_LOW;
212+
else now = AlertLevel::OK;
213+
}
214+
break;
215+
216+
case AlertLevel::CRIT_HIGH:
217+
// From CRIT_HIGH, need to go below critHigh - hysteresis to de-escalate
218+
if (v < thr.critHigh - thr.hysteresis) {
219+
if (v >= thr.warnHigh - thr.hysteresis) now = AlertLevel::WARN_HIGH;
220+
else now = AlertLevel::OK;
221+
}
222+
break;
223+
224+
default:
225+
break;
226+
}
227+
228+
if (now != last) {
229+
logger->log(id, now, v);
230+
last = now;
231+
}
232+
}
233+
};
234+
170235
// New monitor for boolean conditions
171236
struct BooleanMonitor : public IMonitor {
172237
SensorID id;

inc/sp140/throttle.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,26 @@
33

44
#include <Arduino.h>
55

6+
/**
7+
* Throttle module (PWM-first pipeline)
8+
*
9+
* Responsibilities:
10+
* - Initialize throttle ADC input
11+
* - Read raw potentiometer value (0..4095)
12+
* - Convert raw value to PWM (ESC_MIN_PWM..ESC_MAX_PWM)
13+
* - Smooth PWM via an internal 8-sample ring buffer
14+
* - Apply mode-based ramp limiting and clamping in PWM domain
15+
*/
16+
617
// Constants related to throttle behavior
718
#define DECEL_MULTIPLIER 2.0 // How much faster deceleration is vs acceleration
819

20+
// Throttle control (PWM-first) constants
21+
// Ramping in PWM microseconds per tick (~20ms per tick in throttle task)
22+
#define CHILL_MODE_MAX_PWM 1850 // 85% max power in chill mode
23+
#define CHILL_MODE_RAMP_RATE 10 // us/tick in chill mode (~1.6s 1035->1850)
24+
#define SPORT_MODE_RAMP_RATE 27 // us/tick in sport mode (~0.68s 1035->1950)
25+
926
/**
1027
* Throttle easing function based on threshold/performance mode
1128
* Limits how quickly throttle can increase or decrease
@@ -15,8 +32,48 @@
1532
* @param threshold Maximum allowed change per cycle
1633
* @return Limited throttle value
1734
*/
35+
/**
36+
* Limits how quickly a value may change between ticks.
37+
* - Caps acceleration to `threshold` per tick.
38+
* - Caps deceleration to `threshold * DECEL_MULTIPLIER` per tick.
39+
*
40+
* @param current Proposed value for this tick
41+
* @param last Value applied in the previous tick
42+
* @param threshold Max allowed increase per tick (units depend on caller)
43+
* @return Value adjusted to respect ramp limits
44+
*/
1845
int limitedThrottle(int current, int last, int threshold);
1946

47+
/** Initialize throttle input pin and ADC (12-bit on ESP32). */
48+
void initThrottleInput();
49+
50+
/** Read raw throttle value from ADC (0..4095). */
51+
uint16_t readThrottleRaw();
52+
53+
/** Convert raw pot reading (0..4095) to PWM microseconds. */
54+
int potRawToPwm(uint16_t raw);
55+
56+
/**
57+
* Apply mode-based ramp (us/tick) and clamp to the mode's max PWM.
58+
* Updates `prevPwm` with the final value.
59+
*
60+
* @param pwmAvg Smoothed PWM input (microseconds)
61+
* @param prevPwm Reference to previous PWM for ramping
62+
* @param performance_mode 0 = CHILL, 1 = SPORT
63+
* @return Final PWM to send to ESC (microseconds)
64+
*/
65+
int applyModeRampClamp(int pwmAvg, int& prevPwm, uint8_t performance_mode);
66+
67+
// Throttle PWM filter (8-sample ring buffer)
68+
/** Clear the internal PWM smoothing buffer. */
69+
void throttleFilterClear();
70+
/** Clear and pre-fill the buffer with `pwmValue` for a smooth restart. */
71+
void throttleFilterReset(int pwmValue);
72+
/** Push a new PWM sample into the smoothing buffer. */
73+
void throttleFilterPush(int pwmValue);
74+
/** Return the averaged PWM from the smoothing buffer. */
75+
int throttleFilterAverage();
76+
2077
/**
2178
* Checks if throttle is in safe position (below threshold)
2279
*
@@ -32,6 +89,22 @@ bool throttleSafe(int threshold);
3289
*/
3390
bool throttleEngaged();
3491

92+
/**
93+
* Read throttle input and return smoothed PWM value.
94+
* This is the core throttle processing pipeline without any state logic.
95+
*
96+
* @return Smoothed PWM value from throttle input
97+
*/
98+
int getSmoothedThrottlePwm();
99+
100+
/**
101+
* Reset throttle state for clean startup/disarm.
102+
* Clears smoothing buffer and resets previous PWM tracking.
103+
*
104+
* @param prevPwm Reference to previous PWM variable to reset
105+
*/
106+
void resetThrottleState(int& prevPwm);
107+
35108
/**
36109
* Main throttle handling function - processes throttle input
37110
* and applies appropriate limits based on device state

platformio.ini

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ lib_deps =
4343
Wire
4444
SPI
4545
ArduinoJson@7.3.1
46-
ResponsiveAnalogRead@1.2.1 ; deprecated
4746
Time@1.6.1
4847
adafruit/Adafruit BusIO@1.17.2
4948
adafruit/Adafruit BMP3XX Library@2.1.6
@@ -53,7 +52,7 @@ lib_deps =
5352
adafruit/Adafruit MCP2515@0.2.1
5453
https://github.com/rlogiacco/CircularBuffer@1.4.0
5554
https://github.com/openppg/SINE-ESC-CAN#8caa93996b5d000fe10ca5265bd1c472dfdf885b
56-
https://github.com/openppg/ANT-BMS-CAN#818e2988356235333867553ac29f28c9fba2fd85
55+
https://github.com/openppg/ANT-BMS-CAN#da685ce2a0e87e23df625f33ad751203ad6a4f8f
5756
lvgl/lvgl@^8.4.0
5857
lib_ignore =
5958
Adafruit SleepyDog Library
@@ -75,6 +74,9 @@ build_type = debug
7574
build_flags =
7675
-I inc
7776
-I test/native_stubs
77+
-I .pio/libdeps/native-test/CircularBuffer
7878
-D ARDUINO=1
7979
build_src_filter = -<*>
8080
test_ignore = neopixel*
81+
lib_deps =
82+
rlogiacco/CircularBuffer@^1.4.0

src/sp140/alert_display.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,12 @@ static void recalcCountsAndPublish() {
197197
*/
198198
static void handleAlertVibration(const AlertCounts& newCounts, const AlertCounts& previousCounts) {
199199
// Handle warning transitions (only when no critical alerts)
200-
if (newCounts.criticalCount == 0 &&
201-
previousCounts.warningCount == 0 && newCounts.warningCount > 0) {
202-
// Short delay to sync with UI
203-
vTaskDelay(pdMS_TO_TICKS(100));
204-
// Transition from 0 warnings to >0 warnings - trigger double pulse
205-
executeVibePattern(VIBE_DOUBLE_PULSE);
200+
if (newCounts.criticalCount == 0) {
201+
const int deltaWarnings = static_cast<int>(newCounts.warningCount) - static_cast<int>(previousCounts.warningCount);
202+
if (deltaWarnings > 0) {
203+
// Any increase in warnings: another double pulse
204+
vTaskDelay(pdMS_TO_TICKS(100));
205+
executeVibePattern(VIBE_DOUBLE_PULSE);
206+
}
206207
}
207208
}

src/sp140/bms_monitors.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,50 +10,50 @@ extern MultiLogger multiLogger;
1010
extern STR_BMS_TELEMETRY_140 monitoringBmsData;
1111

1212
void addBMSMonitors() {
13-
// BMS MOSFET Temperature (Warning: 50°C, Critical: 60°C)
14-
static SensorMonitor* bmsMosTemp = new SensorMonitor(
13+
// BMS MOSFET Temperature (Warning: 50°C, Critical: 60°C) - with hysteresis
14+
static HysteresisSensorMonitor* bmsMosTemp = new HysteresisSensorMonitor(
1515
SensorID::BMS_MOS_Temp,
1616
SensorCategory::BMS,
1717
bmsTempThresholds,
1818
[]() { return monitoringBmsData.mos_temperature; },
1919
&multiLogger);
2020
monitors.push_back(bmsMosTemp);
2121

22-
// BMS Balance Resistor Temperature (Warning: 50°C, Critical: 60°C)
23-
static SensorMonitor* bmsBalanceTemp = new SensorMonitor(
22+
// BMS Balance Resistor Temperature (Warning: 50°C, Critical: 60°C) - with hysteresis
23+
static HysteresisSensorMonitor* bmsBalanceTemp = new HysteresisSensorMonitor(
2424
SensorID::BMS_Balance_Temp,
2525
SensorCategory::BMS,
2626
bmsTempThresholds,
2727
[]() { return monitoringBmsData.balance_temperature; },
2828
&multiLogger);
2929
monitors.push_back(bmsBalanceTemp);
3030

31-
// T1-T4 Cell Temperature Sensors (Warning: 50°C, Critical: 56°C)
32-
static SensorMonitor* bmsT1Temp = new SensorMonitor(
31+
// T1-T4 Cell Temperature Sensors (Warning: 50°C, Critical: 56°C) - with hysteresis
32+
static HysteresisSensorMonitor* bmsT1Temp = new HysteresisSensorMonitor(
3333
SensorID::BMS_T1_Temp,
3434
SensorCategory::BMS,
3535
bmsCellTempThresholds,
3636
[]() { return monitoringBmsData.t1_temperature; },
3737
&multiLogger);
3838
monitors.push_back(bmsT1Temp);
3939

40-
static SensorMonitor* bmsT2Temp = new SensorMonitor(
40+
static HysteresisSensorMonitor* bmsT2Temp = new HysteresisSensorMonitor(
4141
SensorID::BMS_T2_Temp,
4242
SensorCategory::BMS,
4343
bmsCellTempThresholds,
4444
[]() { return monitoringBmsData.t2_temperature; },
4545
&multiLogger);
4646
monitors.push_back(bmsT2Temp);
4747

48-
static SensorMonitor* bmsT3Temp = new SensorMonitor(
48+
static HysteresisSensorMonitor* bmsT3Temp = new HysteresisSensorMonitor(
4949
SensorID::BMS_T3_Temp,
5050
SensorCategory::BMS,
5151
bmsCellTempThresholds,
5252
[]() { return monitoringBmsData.t3_temperature; },
5353
&multiLogger);
5454
monitors.push_back(bmsT3Temp);
5555

56-
static SensorMonitor* bmsT4Temp = new SensorMonitor(
56+
static HysteresisSensorMonitor* bmsT4Temp = new HysteresisSensorMonitor(
5757
SensorID::BMS_T4_Temp,
5858
SensorCategory::BMS,
5959
bmsCellTempThresholds,

src/sp140/esc_monitors.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,35 @@ extern MultiLogger multiLogger;
1111
extern STR_ESC_TELEMETRY_140 monitoringEscData;
1212

1313
void addESCMonitors() {
14-
// ESC MOS Temperature Monitor
15-
static SensorMonitor* escMosTemp = new SensorMonitor(
14+
// ESC MOS Temperature Monitor - with hysteresis
15+
static HysteresisSensorMonitor* escMosTemp = new HysteresisSensorMonitor(
1616
SensorID::ESC_MOS_Temp,
1717
SensorCategory::ESC,
1818
escMosTempThresholds,
1919
[]() { return monitoringEscData.mos_temp; },
2020
&multiLogger);
2121
monitors.push_back(escMosTemp);
2222

23-
// ESC MCU Temperature Monitor
24-
static SensorMonitor* escMcuTemp = new SensorMonitor(
23+
// ESC MCU Temperature Monitor - with hysteresis
24+
static HysteresisSensorMonitor* escMcuTemp = new HysteresisSensorMonitor(
2525
SensorID::ESC_MCU_Temp,
2626
SensorCategory::ESC,
2727
escMcuTempThresholds,
2828
[]() { return monitoringEscData.mcu_temp; },
2929
&multiLogger);
3030
monitors.push_back(escMcuTemp);
3131

32-
// ESC Capacitor Temperature Monitor
33-
static SensorMonitor* escCapTemp = new SensorMonitor(
32+
// ESC Capacitor Temperature Monitor - with hysteresis
33+
static HysteresisSensorMonitor* escCapTemp = new HysteresisSensorMonitor(
3434
SensorID::ESC_CAP_Temp,
3535
SensorCategory::ESC,
3636
escCapTempThresholds,
3737
[]() { return monitoringEscData.cap_temp; },
3838
&multiLogger);
3939
monitors.push_back(escCapTemp);
4040

41-
// Motor Temperature Monitor
42-
static SensorMonitor* motorTemp = new SensorMonitor(
41+
// Motor Temperature Monitor - with hysteresis
42+
static HysteresisSensorMonitor* motorTemp = new HysteresisSensorMonitor(
4343
SensorID::Motor_Temp,
4444
SensorCategory::ESC,
4545
motorTempThresholds,

src/sp140/extra-data.ino

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// OpenPPG
33

44
#include <Preferences.h> // Add ESP32 Preferences library
5+
#include "../../inc/sp140/throttle.h"
56

67
/**
78
* WebSerial Protocol Documentation
@@ -282,9 +283,8 @@ class ScreenRotationCallbacks: public BLECharacteristicCallbacks {
282283

283284
class ThrottleValueCallbacks: public BLECharacteristicCallbacks {
284285
void onRead(BLECharacteristic *pCharacteristic) {
285-
// Return the current pot value when read
286-
pot->update();
287-
uint16_t potVal = pot->getValue();
286+
// Return the current pot value when read (raw ADC)
287+
uint16_t potVal = readThrottleRaw();
288288
pCharacteristic->setValue((uint8_t*)&potVal, sizeof(potVal));
289289
}
290290

src/sp140/lvgl/lvgl_main_screen.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ lv_obj_t* createTempBackground(lv_obj_t* parent, int x, int y, int width, int he
7373
lv_obj_set_pos(bg, x, y);
7474
lv_obj_set_style_border_width(bg, 0, LV_PART_MAIN);
7575
lv_obj_set_style_radius(bg, 0, LV_PART_MAIN);
76-
lv_obj_set_style_bg_opa(bg, LV_OPA_0, LV_PART_MAIN);
76+
// Default to opaque background; visibility controlled by HIDDEN flag in updates
77+
lv_obj_set_style_bg_opa(bg, LV_OPA_100, LV_PART_MAIN);
7778
lv_obj_set_style_shadow_width(bg, 0, LV_PART_MAIN);
7879
lv_obj_set_style_outline_width(bg, 0, LV_PART_MAIN);
7980
lv_obj_set_style_pad_all(bg, 0, LV_PART_MAIN);

0 commit comments

Comments
 (0)