Read current & coulomb counter
This commit is contained in:
parent
23f96c214b
commit
5bf6b286b6
@ -1,4 +1,6 @@
|
|||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
import time
|
import time
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
@ -12,10 +14,12 @@ from pymodbus.client import ModbusSerialClient
|
|||||||
|
|
||||||
MODBUS_BAUDRATE = 115200
|
MODBUS_BAUDRATE = 115200
|
||||||
VOLTAGE_ADDRESS = 0x00
|
VOLTAGE_ADDRESS = 0x00
|
||||||
|
CURRENT_ADDRESS = 2048
|
||||||
SLAVE_UNIT_ID = 0x02
|
SLAVE_UNIT_ID = 0x02
|
||||||
|
|
||||||
NUM_CELLS = 3
|
NUM_CELLS = 3
|
||||||
VOLTAGE_QUANT = 1 / 10000.0
|
VOLTAGE_QUANT = 1 / 10000.0
|
||||||
|
CURRENT_QUANT = 1 / (500 * 72e-6)
|
||||||
|
|
||||||
THRESH_UV = 2.5
|
THRESH_UV = 2.5
|
||||||
THRESH_OV = 4.2
|
THRESH_OV = 4.2
|
||||||
@ -58,6 +62,8 @@ class BMSData:
|
|||||||
voltages: list[float]
|
voltages: list[float]
|
||||||
temperatures: list[float]
|
temperatures: list[float]
|
||||||
error: BMSError
|
error: BMSError
|
||||||
|
current: float
|
||||||
|
current_integrated: float
|
||||||
|
|
||||||
|
|
||||||
class BMS(QObject):
|
class BMS(QObject):
|
||||||
@ -75,7 +81,13 @@ class BMS(QObject):
|
|||||||
self._load = load
|
self._load = load
|
||||||
self._num_cells = num_cells
|
self._num_cells = num_cells
|
||||||
self._num_sensors = num_sensors
|
self._num_sensors = num_sensors
|
||||||
self._data = BMSData([0.0] * num_cells, [0.0] * num_sensors, BMSError.NONE)
|
self._data = BMSData(
|
||||||
|
voltages=[0.0] * num_cells,
|
||||||
|
temperatures=[0.0] * num_sensors,
|
||||||
|
error=BMSError.NONE,
|
||||||
|
current=0,
|
||||||
|
current_integrated=0,
|
||||||
|
)
|
||||||
|
|
||||||
def _check_for_errors(self):
|
def _check_for_errors(self):
|
||||||
error = BMSError.NONE
|
error = BMSError.NONE
|
||||||
@ -126,19 +138,33 @@ class BMSEvalBoard(BMS):
|
|||||||
|
|
||||||
def do_work(self):
|
def do_work(self):
|
||||||
while True:
|
while True:
|
||||||
|
self._check_for_errors()
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
result = self._dev.read_holding_registers(
|
result = self._dev.read_holding_registers(
|
||||||
VOLTAGE_ADDRESS, NUM_CELLS, SLAVE_UNIT_ID
|
VOLTAGE_ADDRESS, NUM_CELLS, SLAVE_UNIT_ID
|
||||||
)
|
)
|
||||||
if result.isError():
|
if result.isError():
|
||||||
print(f"ERROR READING VOLTAGES: {result}")
|
print(f"ERROR READING VOLTAGES: {result}", file=sys.stderr)
|
||||||
else:
|
continue
|
||||||
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._last_voltage_time = time.time()
|
self._last_voltage_time = time.time()
|
||||||
self.dataUpdated.emit(self._data)
|
result = self._dev.read_holding_registers(CURRENT_ADDRESS, 6, SLAVE_UNIT_ID)
|
||||||
self._check_for_errors()
|
if result.isError():
|
||||||
|
print(f"ERROR READING CURRENT: {result}", file=sys.stderr)
|
||||||
|
continue
|
||||||
|
assert len(result.registers) == 6
|
||||||
|
self._data.current = (
|
||||||
|
(result.registers[0] << 16) | result.registers[1]
|
||||||
|
) * CURRENT_QUANT
|
||||||
|
self._data.current_integrated = (
|
||||||
|
(result.registers[2] << 48)
|
||||||
|
| (result.registers[3] << 32)
|
||||||
|
| (result.registers[4] << 16)
|
||||||
|
| result.registers[5]
|
||||||
|
) * CURRENT_QUANT
|
||||||
|
self.dataUpdated.emit(self._data)
|
||||||
|
|
||||||
@Slot(list)
|
@Slot(list)
|
||||||
def _updateTemperatures(self, temps: list[float]):
|
def _updateTemperatures(self, temps: list[float]):
|
||||||
|
@ -89,3 +89,5 @@ class GUI(QObject):
|
|||||||
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))
|
self._win.setProperty("bmsError", str(data.error))
|
||||||
|
self._win.setProperty("currentActual", data.current)
|
||||||
|
self._win.setProperty("currentIntegrated", data.current_integrated)
|
||||||
|
@ -51,6 +51,8 @@ class Logger(QObject):
|
|||||||
time.time() - self._start_time,
|
time.time() - self._start_time,
|
||||||
self._data.error.value,
|
self._data.error.value,
|
||||||
self._current,
|
self._current,
|
||||||
|
self._data.current,
|
||||||
|
self._data.current_integrated,
|
||||||
*self._data.voltages,
|
*self._data.voltages,
|
||||||
*self._data.temperatures,
|
*self._data.temperatures,
|
||||||
]
|
]
|
||||||
|
@ -13,6 +13,8 @@ ApplicationWindow {
|
|||||||
property string profile: "None"
|
property string profile: "None"
|
||||||
property real profileTime: 0
|
property real profileTime: 0
|
||||||
property real current: 0
|
property real current: 0
|
||||||
|
property real currentActual: 0
|
||||||
|
property real currentIntegrated: 0
|
||||||
property string time: "00:00 / 00:00"
|
property string time: "00:00 / 00:00"
|
||||||
property real voltage_min: 0
|
property real voltage_min: 0
|
||||||
property real voltage_max: 0
|
property real voltage_max: 0
|
||||||
@ -143,7 +145,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
GridLayout {
|
GridLayout {
|
||||||
Text {
|
Text {
|
||||||
text: "Current [A]:"
|
text: "Current (target) [A]:"
|
||||||
Layout.row: 0
|
Layout.row: 0
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
@ -153,38 +155,58 @@ ApplicationWindow {
|
|||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: "Time [min]:"
|
text: "Current (actual) [A]:"
|
||||||
Layout.row: 1
|
Layout.row: 1
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
|
Text {
|
||||||
|
text: currentActual.toFixed(1)
|
||||||
|
Layout.row: 1
|
||||||
|
Layout.column: 1
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: "Time [min]:"
|
||||||
|
Layout.row: 2
|
||||||
|
Layout.column: 0
|
||||||
|
}
|
||||||
Text {
|
Text {
|
||||||
text: time
|
text: time
|
||||||
Layout.row: 1
|
Layout.row: 2
|
||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: "Voltage [V]:"
|
text: "Voltage [V]:"
|
||||||
Layout.row: 2
|
Layout.row: 3
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: "[" + voltage_min.toFixed(2) + ", " + voltage_max.toFixed(2) + "]"
|
text: "[" + voltage_min.toFixed(2) + ", " + voltage_max.toFixed(2) + "]"
|
||||||
Layout.row: 2
|
Layout.row: 3
|
||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: "Temperature [°C]:"
|
text: "Temperature [°C]:"
|
||||||
Layout.row: 3
|
Layout.row: 4
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: "[" + temp_min.toFixed(1) + ", " + temp_max.toFixed(1) + "]"
|
text: "[" + temp_min.toFixed(1) + ", " + temp_max.toFixed(1) + "]"
|
||||||
Layout.row: 3
|
Layout.row: 4
|
||||||
|
Layout.column: 1
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: "Coulomb counter [Ah]:"
|
||||||
|
Layout.row: 5
|
||||||
|
Layout.column: 0
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: currentIntegrated.toFixed(1)
|
||||||
|
Layout.row: 5
|
||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: "BMS Error:"
|
text: "BMS Error:"
|
||||||
Layout.row: 4
|
Layout.row: 6
|
||||||
Layout.column: 0
|
Layout.column: 0
|
||||||
visible: bmsErrorVisible
|
visible: bmsErrorVisible
|
||||||
color: "red"
|
color: "red"
|
||||||
@ -192,7 +214,7 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: bmsError
|
text: bmsError
|
||||||
Layout.row: 4
|
Layout.row: 6
|
||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
visible: bmsErrorVisible
|
visible: bmsErrorVisible
|
||||||
color: "red"
|
color: "red"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user