Skip to content

Commit 60b68ef

Browse files
Fri3d Camp 2024 Badge: improve battery monitor calibration
1 parent 54b0aa0 commit 60b68ef

File tree

5 files changed

+46
-19
lines changed

5 files changed

+46
-19
lines changed

internal_filesystem/lib/mpos/battery_voltage.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
MAX_VOLTAGE = 4.15
55

66
adc = None
7-
scale_factor = 0
7+
conversion_func = None # Conversion function: ADC value -> voltage
88
adc_pin = None
99

1010
# Cache to reduce WiFi interruptions (ADC2 requires WiFi to be disabled)
@@ -19,7 +19,7 @@ def _is_adc2_pin(pin):
1919
return 11 <= pin <= 20
2020

2121

22-
def init_adc(pinnr, sf):
22+
def init_adc(pinnr, adc_to_voltage_func):
2323
"""
2424
Initialize ADC for battery voltage monitoring.
2525
@@ -29,13 +29,16 @@ def init_adc(pinnr, sf):
2929
3030
Args:
3131
pinnr: GPIO pin number
32-
sf: Scale factor to convert raw ADC (0-4095) to battery voltage
32+
adc_to_voltage_func: Conversion function that takes raw ADC value (0-4095)
33+
and returns battery voltage in volts
3334
"""
34-
global adc, scale_factor, adc_pin
35-
scale_factor = sf
35+
global adc, conversion_func, adc_pin
36+
37+
conversion_func = adc_to_voltage_func
3638
adc_pin = pinnr
39+
3740
try:
38-
print(f"Initializing ADC pin {pinnr} with scale_factor {sf}")
41+
print(f"Initializing ADC pin {pinnr} with conversion function")
3942
if _is_adc2_pin(pinnr):
4043
print(f" WARNING: GPIO{pinnr} is on ADC2 - WiFi will be disabled during readings")
4144
from machine import ADC, Pin
@@ -44,6 +47,9 @@ def init_adc(pinnr, sf):
4447
except Exception as e:
4548
print(f"Info: this platform has no ADC for measuring battery voltage: {e}")
4649

50+
initial_adc_value = read_raw_adc()
51+
print("Reading ADC at init to fill cache: {initial_adc_value} => {read_battery_voltage(raw_adc_value=initial_adc_value)}V => {get_battery_percentage(raw_adc_value=initial_adc_value)}%")
52+
4753

4854
def read_raw_adc(force_refresh=False):
4955
"""
@@ -63,12 +69,10 @@ def read_raw_adc(force_refresh=False):
6369
"""
6470
global _cached_raw_adc, _last_read_time
6571

66-
# Desktop mode - return random value
72+
# Desktop mode - return random value in typical ADC range
6773
if not adc:
6874
import random
69-
return random.randint(1900, 2600) if scale_factor == 0 else random.randint(
70-
int(MIN_VOLTAGE / scale_factor), int(MAX_VOLTAGE / scale_factor)
71-
)
75+
return random.randint(1900, 2600)
7276

7377
# Check if this is an ADC2 pin (requires WiFi disable)
7478
needs_wifi_disable = adc_pin is not None and _is_adc2_pin(adc_pin)
@@ -115,7 +119,7 @@ def read_raw_adc(force_refresh=False):
115119
WifiService.temporarily_enable(was_connected)
116120

117121

118-
def read_battery_voltage(force_refresh=False):
122+
def read_battery_voltage(force_refresh=False, raw_adc_value=None):
119123
"""
120124
Read battery voltage in volts.
121125
@@ -125,19 +129,19 @@ def read_battery_voltage(force_refresh=False):
125129
Returns:
126130
float: Battery voltage in volts (clamped to 0-MAX_VOLTAGE)
127131
"""
128-
raw = read_raw_adc(force_refresh)
129-
voltage = raw * scale_factor
132+
raw = raw_adc_value if raw_adc_value else read_raw_adc(force_refresh)
133+
voltage = conversion_func(raw) if conversion_func else 0.0
130134
return max(0.0, min(voltage, MAX_VOLTAGE))
131135

132136

133-
def get_battery_percentage():
137+
def get_battery_percentage(raw_adc_value=None):
134138
"""
135139
Get battery charge percentage.
136140
137141
Returns:
138142
float: Battery percentage (0-100)
139143
"""
140-
voltage = read_battery_voltage()
144+
voltage = read_battery_voltage(raw_adc_value=raw_adc_value)
141145
percentage = (voltage - MIN_VOLTAGE) * 100.0 / (MAX_VOLTAGE - MIN_VOLTAGE)
142146
return max(0.0, min(100.0, percentage))
143147

internal_filesystem/lib/mpos/board/fri3d_2024.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,14 @@ def keypad_read_cb(indev, data):
275275
2269 is 3.831
276276
"""
277277
def adc_to_voltage(adc_value):
278+
"""
279+
Convert raw ADC value to battery voltage using calibrated linear function.
280+
Calibration data shows linear relationship: voltage = -0.0016237 * adc + 8.2035
281+
This is ~10x more accurate than simple scaling (error ~0.01V vs ~0.1V).
282+
"""
278283
return (-0.0016237 * adc_value + 8.2035)
279-
#mpos.battery_voltage.init_adc(13, adc_to_voltage)
280-
mpos.battery_voltage.init_adc(13, 1/616) # simple scaling has an error of ~0.01V vs the adc_to_voltage() method
284+
285+
mpos.battery_voltage.init_adc(13, adc_to_voltage)
281286

282287
import mpos.sdcard
283288
mpos.sdcard.init(spi_bus, cs_pin=14)

internal_filesystem/lib/mpos/board/linux.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,12 @@ def catch_escape_key(indev, indev_data):
8888

8989
# Simulated battery voltage ADC measuring
9090
import mpos.battery_voltage
91-
mpos.battery_voltage.init_adc(999, (3.3 / 4095) * 2)
91+
92+
def adc_to_voltage(adc_value):
93+
"""Convert simulated ADC value to voltage."""
94+
return adc_value * (3.3 / 4095) * 2
95+
96+
mpos.battery_voltage.init_adc(999, adc_to_voltage)
9297

9398
print("linux.py finished")
9499

internal_filesystem/lib/mpos/board/waveshare_esp32_s3_touch_lcd_2.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,19 @@
8181

8282
# Battery voltage ADC measuring
8383
import mpos.battery_voltage
84-
mpos.battery_voltage.init_adc(5, 262 / 100000)
84+
85+
def adc_to_voltage(adc_value):
86+
"""
87+
Convert raw ADC value to battery voltage.
88+
Currently uses simple linear scaling: voltage = adc * 0.00262
89+
90+
This could be improved with calibration data similar to Fri3d board.
91+
To calibrate: measure actual battery voltages and corresponding ADC readings,
92+
then fit a linear or polynomial function.
93+
"""
94+
return adc_value * 0.00262
95+
96+
mpos.battery_voltage.init_adc(5, adc_to_voltage)
8597

8698
# On the Waveshare ESP32-S3-Touch-LCD-2, the camera is hard-wired to power on,
8799
# so it needs a software power off to prevent it from staying hot all the time and quickly draining the battery.

internal_filesystem/lib/mpos/ui/topmenu.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ def update_battery_icon(timer=None):
154154
# Percentage is not shown for now:
155155
#battery_label.set_text(f"{round(percent)}%")
156156
#battery_label.remove_flag(lv.obj.FLAG.HIDDEN)
157+
update_battery_icon() # run it immediately instead of waiting for the timer
157158

158159
def update_wifi_icon(timer):
159160
from mpos.net.wifi_service import WifiService

0 commit comments

Comments
 (0)