Skip to content

New State of Health #235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

New State of Health #235

wants to merge 15 commits into from

Conversation

JamesDCowley
Copy link
Member

@JamesDCowley JamesDCowley commented Apr 17, 2025

Summary

Closes #159 (finally). Created a new State of Health class to hold information from a bunch of sensors such as temperatures, voltage, current, etc. Will be used for upcoming Mode Manager to manage power states.

How was this tested

  • Added new unit tests
  • Ran code on hardware (screenshots are helpful)
    image
    (Power monitor stuff is null but does work with a working battery board, but ours blew up)
    Works on v4 flight boards with v2 battery boards. Make sure to import and add the INA219Manager and StateOfHealth into main.py on whatever version repo.

main.py For v4 flight + v2 battery (will be added in upcoming PR to v4 and v5 boards):

from lib.pysquared.hardware.power_monitor.manager.ina219 import INA219Manager
...
from lib.pysquared.state_of_health import StateOfHealth
...
# v4 only -- use i2c1 for v5
i2c0 = initialize_i2c_bus(
        logger,
        board.I2C0_SCL,
        board.I2C0_SDA,
        100000,
)
...
battery_power_monitor = INA219Manager(logger, i2c0, 0x40) # address and bus may be different depending on your board
soh = StateOfHealth(
        logger,
        battery_power_monitor,
        solar_power_monitor,
        radio,
        imu,
        Counter(index=register.BOOTCNT, datastore=microcontroller.nvm), # boot count
        Flag(index=register.FLAG, bit_index=6, datastore=microcontroller.nvm), # burned
        Flag(index=register.FLAG, bit_index=3, datastore=microcontroller.nvm), # brownout
        Flag(index=register.FLAG, bit_index=7, datastore=microcontroller.nvm), # fsk
)
# you can put None in place of the power monitors if you don't have a battery board and are using a v4 flight board
...
def main():
...
        state_of_health.update()
...
  • Other (Please describe)

@JamesDCowley JamesDCowley marked this pull request as ready for review April 18, 2025 23:05
@Mikefly123 Mikefly123 requested a review from Copilot April 19, 2025 00:56
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a new State of Health class for aggregating sensor data, including voltage, current, and temperature measurements from various monitoring components. Key changes include the addition of a new StateOfHealth class, comprehensive unit tests covering its behavior, and the removal of legacy state-of-health formatting functions from pysquared/functions.py.

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
tests/unit/test_state_of_health.py New unit tests validating sensor readings and state update functionality.
pysquared/state_of_health.py New StateOfHealth class implementing sensor value aggregation and state update.
pysquared/functions.py Removal of obsolete state-of-health methods in favor of the new implementation.

Copy link

Copy link
Member

@nateinaction nateinaction left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pretty great refactor from the old state of health. Thank you for extracting this functionality from functions.py. This feels like the start of a new "services" layer in pysquared.

While you were still building out the ina219 power monitor manager I remember us talking about how useful the protos could be in creating a generic state of health service. While not as customized as this implementation, in #240 I took a swing at spinning up a generic state of health service just to see what it could look like. How do you think of the generic model compares to what you have here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that you're removing things from functions.py. Thank you!

"""
Update the state of health
"""
try:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking over the calls in this try/except I think that none of these calls have the possibility of raising an exception. What are you seeing?

Comment on lines 101 to 102
self.battery_power_monitor.get_bus_voltage()
+ self.battery_power_monitor.get_shunt_voltage()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this idea for adding these two voltages together come from?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was based on the legacy implementation that we took from Max Holliday's PyCubed!

Good flag on this Nate, because looking at it again I realized that the implementation of system_voltage() and battery_voltage() is incorrect. The legacy PyCubed implementation uses an ADM1176 power monitor chip whereas our PySquared boards use the INA219 power monitor chip.

This code should actually be changed so the bus_voltage() + shunt_voltage() call is in the battery_voltage() instead. This is explained a bit in Adafruit's guide for the INA219:

    # INA219 measure bus voltage on the load side. So PSU voltage = bus_voltage + shunt_voltage
    print("Voltage (VIN+) : {:6.3f}   V".format(bus_voltage + shunt_voltage))

system_voltage() should just be based on bus_voltage, which is the actual amount of voltage available to the system vs what the voltage of the batteries is.

Copy link
Member

@Mikefly123 Mikefly123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noticed based on Nate's comments that there should be a slight change to the implementation of the system_voltage() and battery_voltage() calls!

Comment on lines 101 to 102
self.battery_power_monitor.get_bus_voltage()
+ self.battery_power_monitor.get_shunt_voltage()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was based on the legacy implementation that we took from Max Holliday's PyCubed!

Good flag on this Nate, because looking at it again I realized that the implementation of system_voltage() and battery_voltage() is incorrect. The legacy PyCubed implementation uses an ADM1176 power monitor chip whereas our PySquared boards use the INA219 power monitor chip.

This code should actually be changed so the bus_voltage() + shunt_voltage() call is in the battery_voltage() instead. This is explained a bit in Adafruit's guide for the INA219:

    # INA219 measure bus voltage on the load side. So PSU voltage = bus_voltage + shunt_voltage
    print("Voltage (VIN+) : {:6.3f}   V".format(bus_voltage + shunt_voltage))

system_voltage() should just be based on bus_voltage, which is the actual amount of voltage available to the system vs what the voltage of the batteries is.

Copy link
Member

@nateinaction nateinaction left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is on a good track. Talking with Michael, since there is nothing we can do on the satellite to fix an overheating condition we should slim this down so that we only care about battery charge.

@Mikefly123
Copy link
Member

@nateinaction I think it could go either way with keeping the temperature monitoring in here for flavor or splitting it off into a dedicated thermal manager / interface. It is true that right now there is not actually much we can do in response to our of range temperatures and it is mostly just a nice FYI for the ground operators.

If you'd like I can see if someone on my team has some time to address the test and typecheck errors so we can more forward with this.

@yudataguy yudataguy self-assigned this Jun 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[TASK] Create a state_of_health Interface to Monitor Power Modes
4 participants