This repository has been archived by the owner on Feb 4, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
battery.py
117 lines (107 loc) · 5.35 KB
/
battery.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
from smbus2 import SMBus
import time
import math
# Datasheet https://drive.google.com/file/d/13GKtzXyufFxrbeQ7wEGgo796i91W1dQt/view
class Battery:
"""
Class to interface with Clydespace battery TTC node
"""
def __init__(self):
self.addr = 0x2a
self.bus = SMBus(1)
#Refer to datasheet section 12.3 for a list of commands
self.commands = {
# Board info commands: Basic board info
"Board Status": lambda: self.request(0x01, [0x00], 2),
# Reads and returns board status
"Last Error": lambda: self.request(0x03, [0x00], 2), # Reads and returns last error
"Firmware Version": lambda: self.request(0x04, [0x00], 2),
# Reads and returns firmware version
"Checksum": lambda: self.request(0x05, [0x00], 2),
# Reads and returns generated checksum of ROM contents
"Brownout Resets": lambda: self.request(0x31, [0x00], 2),
# Number of Brown-out resets
"Software Resets": lambda: self.request(0x32, [0x00], 2),
# Number of automatic software resets
"Manual Resets": lambda: self.request(0x33, [0x00], 2),
# Number of manual resets
"Manual Reset": lambda: self.request(0x80, [0x00], 2),
# Manually reset to initial state
"Get Heater Controller Status": lambda: self.request(0x90, [0x00], 2),
# Heater Controller status, 0 = disabled, 1 = enabled (automatic)
"Set Heater Controller Status": lambda mode: self.request(0x91, [mode], 2),
# Set Heater Controller Status
}
self.telemetry = {
"VBAT": lambda: self.telemetry_request([0xE2, 0x80], 0.008993),
"IBAT": lambda: self.telemetry_request([0xE2, 0x84], 14.662757), # RETURNS IN MILLIAMPS
"IDIRBAT": lambda: int(self.telemetry_request([0xE2, 0x8E], 1 / 512)), # 1 = discharging, 0 = charging
"TBRD": lambda: self.telemetry_request([0xE3, 0x08], 0.372434), # temperature in K
"IPCM5V": lambda: self.telemetry_request([0xE2, 0x14], 1.327547), # 5V current consumption in mA
"VPCM5V": lambda: self.telemetry_request([0xE2, 0x10], 0.005865), # 5V voltage
"IPCM3V3": lambda: self.telemetry_request([0xE2, 0x04], 1.327547), # 3V3 current consumption in mA
"VPCM3V3": lambda: self.telemetry_request([0xE2, 0x00], 0.004311), # 3V3 voltage
"TBAT1": lambda: self.telemetry_request([0xE3, 0x98], 0.397600), # Batt1 temperature in K
"HBAT1": lambda: int(self.telemetry_request([0xE3, 0x9F], 1 / 512)), # 1 = heater on, 0 = heater off
"TBAT2": lambda: self.telemetry_request([0xE3, 0xA8], 0.397600), # Batt2 temperature in K
"HBAT2": lambda: int(self.telemetry_request([0xE3, 0xAF], 1 / 512)), # 1 = heater on, 0 = heater off
"TBAT3": lambda: self.telemetry_request([0xE3, 0xB8], 0.397600), # Batt3 temperature in K
"HBAT3": lambda: int(self.telemetry_request([0xE3, 0xBF], 1 / 512)), # 1 = heater on, 0 = heater off
"TBAT4": lambda: self.telemetry_request([0xE3, 0xC8], 0.397600), # Batt4 temperature in K
"HBAT4": lambda: int(self.telemetry_request([0xE3, 0xCF], 1 / 512)) # 1 = heater on, 0 = heater off
}
def request(self, register, data, length) -> bytes:
"""
Requests and returns uninterpreted bytes object
:param register: register
:param data: data
:param length: number of bytes to read
:return: (byte) response from EPS
"""
self.bus.write_i2c_block_data(self.addr, register, data)
time.sleep(.25)
result = self.bus.read_i2c_block_data(self.addr, 0, length)
time.sleep(.25)
return result
def command(self, register, data) -> bool:
"""
Sends command to EPS
:param register: register
:param data: data
:return: (bool) whether command was successful
"""
result = self.bus.write_i2c_block_data(self.addr, register, data)
time.sleep(.25)
return result
def telemetry_request(self, tle, multiplier) -> float:
"""
Requests and returns interpreted telemetry data
:param tle: TLE code
:parm multiplier: = multiplier
:return: (float) telemetry value
"""
result = []
for i in range(5): #avg filter
raw = self.request(0x10, tle, 2)
result.append((raw[0] << 8 | raw[1]) * multiplier)
return sum(result)/len(result)
def charging_power(self) -> float:
"""
Returns total power going into the battery or out of
:return: (float) power in watts, if positive, battery is charging, if negative, battery is discharging
"""
pwr = self.telemetry["VBAT"]() * self.telemetry["IBAT"]() / 1000
if self.telemetry["IDIRBAT"]() != 0:
pwr *= -1
return pwr
def telem_summary(self) -> tuple:
v = self.telemetry["VBAT"]()
i = self.telemetry["IBAT"]() / 1000
if self.telemetry["IDIRBAT"]() != 0:
i *= -1
tbat1 = self.telemetry["TBAT1"]()
tbat2 = self.telemetry["TBAT2"]()
tbat3 = self.telemetry["TBAT3"]()
tbat4 = self.telemetry["TBAT4"]()
tbrd = self.telemetry["TBRD"]()
return v, i, tbat1, tbat2, tbat3, tbat4, tbrd