Check temperature & voltage
This commit is contained in:
parent
7bcafa2c4d
commit
a91f9d70db
@ -1,7 +1,9 @@
|
|||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
import time
|
import time
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from .load import Load
|
||||||
from .temperatures import N_SENSORS
|
from .temperatures import N_SENSORS
|
||||||
|
|
||||||
from PySide6.QtCore import QObject, Signal, Slot, Qt
|
from PySide6.QtCore import QObject, Signal, Slot, Qt
|
||||||
@ -15,16 +17,79 @@ SLAVE_UNIT_ID = 0x02
|
|||||||
NUM_CELLS = 3
|
NUM_CELLS = 3
|
||||||
VOLTAGE_QUANT = 1 / 10000.0
|
VOLTAGE_QUANT = 1 / 10000.0
|
||||||
|
|
||||||
|
THRESH_UV = 2.5
|
||||||
|
THRESH_OV = 4.2
|
||||||
|
THRESH_UT = 1
|
||||||
|
THRESH_OT = 60
|
||||||
|
|
||||||
|
|
||||||
|
class BMSError(Enum):
|
||||||
|
NONE = 0
|
||||||
|
UV = 1
|
||||||
|
OV = 2
|
||||||
|
UT = 3
|
||||||
|
OT = 4
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self == self.NONE:
|
||||||
|
return ""
|
||||||
|
elif self == self.UV:
|
||||||
|
return "Undervoltage"
|
||||||
|
elif self == self.OV:
|
||||||
|
return "Overvoltage"
|
||||||
|
elif self == self.UT:
|
||||||
|
return "Undertemperature"
|
||||||
|
elif self == self.OT:
|
||||||
|
return "Overtemperature"
|
||||||
|
else:
|
||||||
|
return "Unknown error"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class BMSData:
|
class BMSData:
|
||||||
voltages: list[float]
|
voltages: list[float]
|
||||||
temperatures: list[float]
|
temperatures: list[float]
|
||||||
|
error: BMSError
|
||||||
|
|
||||||
|
|
||||||
class BMS(QObject):
|
class BMS(QObject):
|
||||||
dataUpdated = Signal(BMSData)
|
dataUpdated = Signal(BMSData)
|
||||||
|
|
||||||
|
_data: BMSData
|
||||||
|
_load: Load
|
||||||
|
_num_cells: int
|
||||||
|
_num_sensors: int
|
||||||
|
|
||||||
|
def __init__(self, load: Load, num_cells: int, num_sensors: int):
|
||||||
|
super().__init__(None)
|
||||||
|
self._load = load
|
||||||
|
self._num_cells = num_cells
|
||||||
|
self._num_sensors = num_sensors
|
||||||
|
self._data = BMSData([0.0] * num_cells, [0.0] * num_sensors, BMSError.NONE)
|
||||||
|
|
||||||
|
def _check_for_errors(self):
|
||||||
|
error = BMSError.NONE
|
||||||
|
for v in self._data.voltages:
|
||||||
|
if v > THRESH_OV:
|
||||||
|
error = BMSError.OV
|
||||||
|
break
|
||||||
|
elif v < THRESH_UV:
|
||||||
|
error = BMSError.UV
|
||||||
|
break
|
||||||
|
for t in self._data.temperatures:
|
||||||
|
if t > THRESH_OT:
|
||||||
|
error = BMSError.OT
|
||||||
|
break
|
||||||
|
if t < THRESH_UT:
|
||||||
|
error = BMSError.UT
|
||||||
|
break
|
||||||
|
|
||||||
|
if error != self._data.error:
|
||||||
|
print(f"Error changed: {error}")
|
||||||
|
self._data.error = error
|
||||||
|
self._load.set_error(error != BMSError.NONE)
|
||||||
|
self.dataUpdated.emit(self._data)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def do_work(self):
|
def do_work(self):
|
||||||
pass
|
pass
|
||||||
@ -32,14 +97,12 @@ class BMS(QObject):
|
|||||||
|
|
||||||
class BMSEvalBoard(BMS):
|
class BMSEvalBoard(BMS):
|
||||||
_dev: ModbusSerialClient
|
_dev: ModbusSerialClient
|
||||||
_data: BMSData
|
|
||||||
|
|
||||||
def __init__(self, uart_path: str, temperaturesUpdated: Signal):
|
def __init__(self, uart_path: str, temperaturesUpdated: Signal, load: Load):
|
||||||
super().__init__(None)
|
super().__init__(load, NUM_CELLS, N_SENSORS)
|
||||||
self._dev = ModbusSerialClient(
|
self._dev = ModbusSerialClient(
|
||||||
method="rtu", port=uart_path, baudrate=MODBUS_BAUDRATE
|
method="rtu", port=uart_path, baudrate=MODBUS_BAUDRATE
|
||||||
)
|
)
|
||||||
self._data = BMSData([0.0] * NUM_CELLS, [0.0] * N_SENSORS)
|
|
||||||
temperaturesUpdated.connect(
|
temperaturesUpdated.connect(
|
||||||
self._updateTemperatures, Qt.ConnectionType.DirectConnection
|
self._updateTemperatures, Qt.ConnectionType.DirectConnection
|
||||||
)
|
)
|
||||||
@ -53,10 +116,12 @@ class BMSEvalBoard(BMS):
|
|||||||
self._data.voltages = list(
|
self._data.voltages = list(
|
||||||
map(lambda v: v * VOLTAGE_QUANT, result.registers)
|
map(lambda v: v * VOLTAGE_QUANT, result.registers)
|
||||||
)
|
)
|
||||||
|
self._check_for_errors()
|
||||||
self.dataUpdated.emit(self._data)
|
self.dataUpdated.emit(self._data)
|
||||||
|
|
||||||
@Slot(list)
|
@Slot(list)
|
||||||
def _updateTemperatures(self, temps: list[float]):
|
def _updateTemperatures(self, temps: list[float]):
|
||||||
assert len(temps) == N_SENSORS
|
assert len(temps) == N_SENSORS
|
||||||
self._data.temperatures = temps
|
self._data.temperatures = temps
|
||||||
|
self._check_for_errors()
|
||||||
self.dataUpdated.emit(self._data)
|
self.dataUpdated.emit(self._data)
|
||||||
|
@ -88,3 +88,4 @@ class GUI(QObject):
|
|||||||
self._win.setProperty("voltage_max", max(data.voltages))
|
self._win.setProperty("voltage_max", max(data.voltages))
|
||||||
self._win.setProperty("temp_min", min(data.temperatures))
|
self._win.setProperty("temp_min", min(data.temperatures))
|
||||||
self._win.setProperty("temp_max", max(data.temperatures))
|
self._win.setProperty("temp_max", max(data.temperatures))
|
||||||
|
self._win.setProperty("bmsError", str(data.error))
|
||||||
|
@ -9,6 +9,7 @@ from .profile_handler import ProfileHandler
|
|||||||
class Load(QObject):
|
class Load(QObject):
|
||||||
dev: serial.Serial
|
dev: serial.Serial
|
||||||
|
|
||||||
|
_error: bool
|
||||||
_current: float
|
_current: float
|
||||||
|
|
||||||
_timer: QTimer
|
_timer: QTimer
|
||||||
@ -17,6 +18,7 @@ class Load(QObject):
|
|||||||
def __init__(self, uart_path: str, profile_handler: ProfileHandler):
|
def __init__(self, uart_path: str, profile_handler: ProfileHandler):
|
||||||
super().__init__(None)
|
super().__init__(None)
|
||||||
self.dev = serial.Serial(uart_path, 115200)
|
self.dev = serial.Serial(uart_path, 115200)
|
||||||
|
self._error = False
|
||||||
self._current = 0
|
self._current = 0
|
||||||
|
|
||||||
self._profile_handler = profile_handler
|
self._profile_handler = profile_handler
|
||||||
@ -25,12 +27,16 @@ class Load(QObject):
|
|||||||
self._timer.timeout.connect(self._update_load)
|
self._timer.timeout.connect(self._update_load)
|
||||||
self._timer.start(100)
|
self._timer.start(100)
|
||||||
|
|
||||||
|
def set_error(self, error):
|
||||||
|
self._error = error
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def _update_current(self, current):
|
def _update_current(self, current):
|
||||||
self._current = current
|
self._current = current
|
||||||
|
|
||||||
def _update_load(self):
|
def _update_load(self):
|
||||||
curr_quants = round(self._current / 0.1)
|
current = 0 if self._error else self._current
|
||||||
|
curr_quants = round(current / 0.1)
|
||||||
assert curr_quants <= 0xFFFF
|
assert curr_quants <= 0xFFFF
|
||||||
|
|
||||||
msb = curr_quants >> 8
|
msb = curr_quants >> 8
|
||||||
|
2
main.py
2
main.py
@ -23,7 +23,7 @@ def main(argv: list[str]) -> int:
|
|||||||
temps.moveToThread(temp_thread)
|
temps.moveToThread(temp_thread)
|
||||||
temp_thread.started.connect(temps.run)
|
temp_thread.started.connect(temps.run)
|
||||||
temp_thread.start()
|
temp_thread.start()
|
||||||
bms = BMSEvalBoard(argv[3], temps.temperaturesUpdated)
|
bms = BMSEvalBoard(argv[3], temps.temperaturesUpdated, load)
|
||||||
bms_thread = QThread()
|
bms_thread = QThread()
|
||||||
bms.moveToThread(bms_thread)
|
bms.moveToThread(bms_thread)
|
||||||
bms_thread.started.connect(bms.do_work)
|
bms_thread.started.connect(bms.do_work)
|
||||||
|
@ -18,12 +18,13 @@ ApplicationWindow {
|
|||||||
property real voltage_max: 0
|
property real voltage_max: 0
|
||||||
property real temp_min: 0
|
property real temp_min: 0
|
||||||
property real temp_max: 0
|
property real temp_max: 0
|
||||||
|
property string bmsError: ""
|
||||||
|
property bool bmsErrorVisible: false
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: profile_handler
|
target: profile_handler
|
||||||
|
|
||||||
function onCurrentChanged(new_current) {
|
function onCurrentChanged(new_current) {
|
||||||
console.log("currentChanged");
|
|
||||||
current = new_current;
|
current = new_current;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +46,11 @@ ApplicationWindow {
|
|||||||
currentTimeSeries.append(profileTime, 100)
|
currentTimeSeries.append(profileTime, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBmsErrorChanged: {
|
||||||
|
console.log(bmsError);
|
||||||
|
bmsErrorVisible = bmsError != "";
|
||||||
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: layout
|
id: layout
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@ -151,6 +157,22 @@ ApplicationWindow {
|
|||||||
Layout.row: 3
|
Layout.row: 3
|
||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
}
|
}
|
||||||
|
Text {
|
||||||
|
text: "BMS Error:"
|
||||||
|
Layout.row: 4
|
||||||
|
Layout.column: 0
|
||||||
|
visible: bmsErrorVisible
|
||||||
|
color: "red"
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: bmsError
|
||||||
|
Layout.row: 4
|
||||||
|
Layout.column: 1
|
||||||
|
visible: bmsErrorVisible
|
||||||
|
color: "red"
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user