From 7bcafa2c4d4fac60810597c13f8a95152461bf69 Mon Sep 17 00:00:00 2001 From: "Jasper v. Blanckenburg" Date: Tue, 24 Jan 2023 21:49:21 +0100 Subject: [PATCH] Talk to EET BMS eval board --- load_controller/bms.py | 62 +++++++++++++++++++++++++++++++++ load_controller/gui.py | 13 ++++--- load_controller/temperatures.py | 2 ++ main.py | 8 ++++- 4 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 load_controller/bms.py diff --git a/load_controller/bms.py b/load_controller/bms.py new file mode 100644 index 0000000..7b200e9 --- /dev/null +++ b/load_controller/bms.py @@ -0,0 +1,62 @@ +from abc import abstractmethod +import time +from dataclasses import dataclass + +from .temperatures import N_SENSORS + +from PySide6.QtCore import QObject, Signal, Slot, Qt + +from pymodbus.client import ModbusSerialClient + +MODBUS_BAUDRATE = 115200 +VOLTAGE_ADDRESS = 0x00 +SLAVE_UNIT_ID = 0x02 + +NUM_CELLS = 3 +VOLTAGE_QUANT = 1 / 10000.0 + + +@dataclass +class BMSData: + voltages: list[float] + temperatures: list[float] + + +class BMS(QObject): + dataUpdated = Signal(BMSData) + + @abstractmethod + def do_work(self): + pass + + +class BMSEvalBoard(BMS): + _dev: ModbusSerialClient + _data: BMSData + + def __init__(self, uart_path: str, temperaturesUpdated: Signal): + super().__init__(None) + self._dev = ModbusSerialClient( + method="rtu", port=uart_path, baudrate=MODBUS_BAUDRATE + ) + self._data = BMSData([0.0] * NUM_CELLS, [0.0] * N_SENSORS) + temperaturesUpdated.connect( + self._updateTemperatures, Qt.ConnectionType.DirectConnection + ) + + def do_work(self): + while True: + time.sleep(0.1) + result = self._dev.read_holding_registers( + VOLTAGE_ADDRESS, NUM_CELLS, SLAVE_UNIT_ID + ) + self._data.voltages = list( + map(lambda v: v * VOLTAGE_QUANT, result.registers) + ) + self.dataUpdated.emit(self._data) + + @Slot(list) + def _updateTemperatures(self, temps: list[float]): + assert len(temps) == N_SENSORS + self._data.temperatures = temps + self.dataUpdated.emit(self._data) diff --git a/load_controller/gui.py b/load_controller/gui.py index 965f7c5..05851d4 100644 --- a/load_controller/gui.py +++ b/load_controller/gui.py @@ -5,6 +5,7 @@ from PySide6.QtCore import QTimer, QObject, Signal from PySide6.QtWidgets import QFileDialog from PySide6.QtQml import QQmlApplicationEngine +from .bms import BMSData from .profile_handler import ProfileHandler, ProfileState @@ -17,7 +18,7 @@ class GUI(QObject): _start_pause_btn: QObject _stop_btn: QObject - def __init__(self, profile_handler: ProfileHandler, temperaturesUpdated: Signal): + def __init__(self, profile_handler: ProfileHandler, bmsUpdated: Signal): super().__init__(None) self._engine = QQmlApplicationEngine() @@ -42,7 +43,7 @@ class GUI(QObject): self._update_timer.timeout.connect(self._update) self._update_timer.start(100) - temperaturesUpdated.connect(self._updateTemperatures) + bmsUpdated.connect(self._updateBMS) def _choose_profile(self): dlg = QFileDialog() @@ -82,6 +83,8 @@ class GUI(QObject): dt = time.time() - self._profile_handler.profile_start self._win.setProperty("profileTime", dt) - def _updateTemperatures(self, temperatures: list[int]): - self._win.setProperty("temp_min", min(temperatures)) - self._win.setProperty("temp_max", max(temperatures)) + def _updateBMS(self, data: BMSData): + self._win.setProperty("voltage_min", min(data.voltages)) + self._win.setProperty("voltage_max", max(data.voltages)) + self._win.setProperty("temp_min", min(data.temperatures)) + self._win.setProperty("temp_max", max(data.temperatures)) diff --git a/load_controller/temperatures.py b/load_controller/temperatures.py index ac0a75b..a693344 100644 --- a/load_controller/temperatures.py +++ b/load_controller/temperatures.py @@ -1,6 +1,7 @@ import sys import serial import struct +import time from PySide6.QtCore import QObject, Signal @@ -21,6 +22,7 @@ class Temperatures(QObject): def run(self): while True: + time.sleep(0.1) self.dev.read_until(START_OF_TEMPS) data = self.dev.read(N_SENSORS * 2) temps = struct.unpack(f">{N_SENSORS}h", data) diff --git a/main.py b/main.py index d77da49..fca318c 100755 --- a/main.py +++ b/main.py @@ -10,6 +10,7 @@ from load_controller.gui import GUI from load_controller.load import Load from load_controller.profile_handler import ProfileHandler from load_controller.temperatures import Temperatures +from load_controller.bms import BMSEvalBoard def main(argv: list[str]) -> int: @@ -22,8 +23,13 @@ def main(argv: list[str]) -> int: temps.moveToThread(temp_thread) temp_thread.started.connect(temps.run) temp_thread.start() + bms = BMSEvalBoard(argv[3], temps.temperaturesUpdated) + bms_thread = QThread() + bms.moveToThread(bms_thread) + bms_thread.started.connect(bms.do_work) + bms_thread.start() - gui = GUI(profile_handler, temps.temperaturesUpdated) + gui = GUI(profile_handler, bms.dataUpdated) return app.exec()