This repository was archived by the owner on Sep 23, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEmus.py
150 lines (135 loc) · 7.44 KB
/
Emus.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# Peter Ferland 02.07.2019
# AERO Data Acquisition Project
# Purpose: Grab information off the CAN BUS, format it nicely and save it to a .csv file
# Information Sources: Rinehart Motor Controller, EMUS BMS, Temp Monitor Board
# Information Sources: Steering Position, Wheel Speed, Throttle Position, Brake Pressure, Damper Position
from Canpak import Canpak
import csv
from CanError import CanError
from CanDevice import CanDevice
class Emus(CanDevice):
def __init__(self, filename, deviceName="Emus"):
super().__init__(filename,deviceName)
# pre allocate a list of 80 elements to hold 80 cell voltages
self.cellVoltages = [0] * 80
self.voltageDict = {"cell_volt":self.cellVoltages}
self.dataDict = {"UnderVoltage":0,\
"OverVoltage":0,\
"DischargeOverCurrent":0,\
"ChargeOverCurrent":0,\
"CellModuleOverheat":0,\
"Leakage":0,\
"NoCellCommunication":0,\
"LowVoltage":0,\
"HighCurrent":0,\
"HighTemperature":0,\
"CellOverheat":0,\
"NoCurrentSensor":0,\
"PackUnderVoltage":0,\
"CellVoltageValidity":0,\
"CellModuleTemperatureValidity":0,\
"CellBalanceRateValidity":0,\
"LiveCellCountValidity":0,\
"BatteryChargeFinished":0,\
"CellTemperatureValidity":0}
# Purpose: Process Individual Cell Voltage Data From the EMUS
# Input:
# data - byte array of hex data
# ID - CAN ID, used to determine which cell voltages to update
def processVoltages(self,ID,data):
if ID == "VG0":
# Update cell voltage list for cells 0 - 7
self.cellVoltages[0:7] = data
if ID == "VG1":
# Update cell voltage list for cells 8 - 15
self.cellVoltages[8:15] = data
if ID == "VG2":
# Update cell voltage list for cells 16 - 23
self.cellVoltages[16:23] = data
if ID == "VG3":
# Update cell voltage list for cells 24 - 31
self.cellVoltages[24:31] = data
if ID == "VG4":
# Update cell voltage list for cells 32 - 39
self.cellVoltages[32:39] = data
if ID == "VG5":
# Update cell voltage list for cells 48 - 55
self.cellVoltages[48:55] = data
if ID == "VG6":
# Update cell voltage list for cells 56 - 63
self.cellVoltages[56:63] = data
if ID == "VG7":
# Update cell voltage list for cells 64 - 71
self.cellVoltages[64:71] = data
if ID == "VG8":
# Update cell voltage list for cells 72 - 79
self.cellVoltages[72:79] = data
# Return a dictionary containing cell voltages
self.voltageDict["cell_volt"] = self.cellVoltages
# Purpose: Process Individual Cell Voltage Data From the EMUS
# Input:
# data - byte array of hex data (bytes 4-7 are unused)
# ID - CAN ID, used to determine which cell voltages to update
def processFaults(self,data):
# Protection Flags (LSB) (byte 0)
# Bit 0 Cell Under Voltage - some cell is below critical minimum voltage
self.dataDict["UnderVoltage"] = super().interpretFlags(data[0],0)
# Bit 1 Cell Over Voltage - some cell is above critical maximum voltage
self.dataDict["OverVoltage"] = super().interpretFlags(data[0],1)
# Bit 2 Discharge OverCurrent - discharge current (negative current) exceeds max
self.dataDict["DischargeOverCurrent"] = super().interpretFlags(data[0],2)
# Bit 3 Charge OverCurrent - charge current (positive current) exceeds max
self.dataDict["ChargeOverCurrent"] = super().interpretFlags(data[0],3)
# Bit 4 Cell Module Overheat - cell module temperature exceeds maximum
self.dataDict["CellModuleOverheat"] = super().interpretFlags(data[0],4)
# Bit 5 Leakage - Leakage signal was detected on the leakage input pin
self.dataDict["Leakage"] = super().interpretFlags(data[0],5)
# Bit 6 No Cell Communication - Loss of communication to cells
self.dataDict["NoCellCommunication"] = super().interpretFlags(data[0],6)
# Warning (reduction) flags (byte 1)
# Bit 0 Low Voltage - some cell is below low voltage warning setting
self.dataDict["LowVoltage"] = super().interpretFlags(data[1],0)
# Bit 1 High Current - discharge current (negative current) exceeds the current warning setting
self.dataDict["HighCurrent"] = super().interpretFlags(data[1],1)
# Bit 2 High Temperature - Cell Module Tempreture Exceeds Warning Temperature Setting
self.dataDict["HighTemperature"] = super().interpretFlags(data[1],2)
# Protection flags (MSB) (byte 2)
# Bits 0-2 and 4-7 are reserved!
# Bit 3 Cell Overheat - Cell Temperature Exceeds Maximum Cell Temperature Threshold
self.dataDict["CellOverheat"] = super().interpretFlags(data[2],3)
# Bit 4 No Current Sensor
self.dataDict["NoCurrentSensor"] = super().interpretFlags(data[2],4)
# Bit 5 Pack Under Voltage
self.dataDict["PackUnderVoltage"] = super().interpretFlags(data[2],5)
# Battery Status Flags (byte 3)
# Bit 0 Cell Voltages Validity - (1 if valid, 0 if invalid)
self.dataDict["CellVoltageValidity"] = super().interpretFlags(data[3],0)
# Bit 1 Cell Module Temperatures Validity
self.dataDict["CellModuleTemperatureValidity"] = super().interpretFlags(data[3],1)
# Bit 2 Cell Balancing Rate Validity
self.dataDict["CellBalanceRateValidity"] = super().interpretFlags(data[3],2)
# Bit 3 Number of Live Cells Validity
self.dataDict["LiveCellCountValidity"] = super().interpretFlags(data[3],3)
# Bit 4 Battery Charging Finished, Used only when using a non-CAN charger
self.dataDict["BatteryChargeFinished"] = super().interpretFlags(data[3],4)
# Bit 5 Cell Temperatures Validity
self.dataDict["CellTemperatureValidity"] =super().interpretFlags(data[3],5)
# Purpose: Determine which message was sent by the rinehart, perform appropriate data processing
# and return the updated emus data dictionaries
# Input: Frame - A tuple containing 3 hex values (ID,DLC,DATA)
# Output: dataList - a dictionary of dictionaries of the following format
# {"rinehart":{"DataID1": DataValue1, "DataID2": DataValue2, ...}}
def checkBroadcast(self,frame):
# check if the data supplied is a rinehart message, if so continue processing
# if the message is from the rinehart chk will be a tuple with the format
# chk = (ID,DATA)
processedData = super().process(frame)
# if process returns a boolean we know this isn't rinehart data, exit without returning data
if isinstance(processedData, bool):
return self.dataDict,self.voltageDict
if processedData[0] == "DC":
self.processFaults(processedData[1])
return self.dataDict,self.voltageDict
if "VG0" or "VG1" or "VG1" or "VG2" or "VG3" or "VG4" or "VG5" or "VG6" or "VG7" or "VG8" in processedData[0]:
self.processVoltages(processedData[0],processedData[1])
return self.dataDict,self.voltageDict