From 333b885d8bc41dc3b6aa4390510f4e6313e5d492 Mon Sep 17 00:00:00 2001 From: Kyle Krol Date: Thu, 15 Apr 2021 16:17:19 -0400 Subject: [PATCH 1/4] Add mission cases folder and remove boot cases --- .github/workflows/hootl.yml | 11 +++-- ptest/cases/__init__.py | 14 +++++-- ptest/cases/boot_to.py | 53 ------------------------ ptest/cases/mission/__init__.py | 3 ++ ptest/cases/mission/detumble.py | 45 +++++++++++++++++++++ ptest/cases/mission/standby.py | 59 +++++++++++++++++++++++++++ ptest/cases/mission/startup.py | 42 +++++++++++++++++++ ptest/cases/mission/utils.py | 71 +++++++++++++++++++++++++++++++++ 8 files changed, 237 insertions(+), 61 deletions(-) delete mode 100644 ptest/cases/boot_to.py create mode 100644 ptest/cases/mission/__init__.py create mode 100644 ptest/cases/mission/detumble.py create mode 100644 ptest/cases/mission/standby.py create mode 100644 ptest/cases/mission/startup.py create mode 100644 ptest/cases/mission/utils.py diff --git a/.github/workflows/hootl.yml b/.github/workflows/hootl.yml index 8b39e7e8e..4a7773b09 100644 --- a/.github/workflows/hootl.yml +++ b/.github/workflows/hootl.yml @@ -56,11 +56,14 @@ jobs: !(python -m ptest runsim -c ptest/configs/hootl_speedup.json -t FailingEmptyCase -ni) !(python -m ptest runsim -c ptest/configs/hootl_speedup.json -t FailingEmptySimCase -ni) - - name: Boot Utility Cases + - name: Mission Rehearsal Cases run: | - python -m ptest runsim -c ptest/configs/hootl.json -t BootToStartupCase -ni - python -m ptest runsim -c ptest/configs/hootl.json -t BootToDetumbleCase -ni - python -m ptest runsim -c ptest/configs/hootl.json -t BootToStandbyCase -ni + python -m ptest runsim -c ptest/configs/hootl.json -t SingleSatStartupCase -ni + python -m ptest runsim -c ptest/configs/hootl_hootl.json -t DualSatStartupCase -ni + python -m ptest runsim -c ptest/configs/hootl.json -t SingleSatStartupCase -ni + python -m ptest runsim -c ptest/configs/hootl_hootl.json -t DualSatStartupCase -ni + python -m ptest runsim -c ptest/configs/hootl.json -t SingleSatStartupCase -ni + python -m ptest runsim -c ptest/configs/hootl_hootl.json -t DualSatStartupCase -ni - name: Hardware Checkout Cases run: | diff --git a/ptest/cases/__init__.py b/ptest/cases/__init__.py index cf20229fc..25e3f3513 100644 --- a/ptest/cases/__init__.py +++ b/ptest/cases/__init__.py @@ -2,19 +2,25 @@ # - tools/alltest.sh # - .github/workflows/hootl.yml -# Testcases that require simulation from .empty_case import EmptySimCase, FailingEmptySimCase from .dual_empty_case import DualEmptySimCase from .piksi_fault_handler import PiksiFaultHandler from .autonomous_mission_manager_pure_radio import AutonomousMissionController -# from .base import * +# Testcases intended for use with mission rehearsals and general telemetry +# testing. +from .mission import ( + SingleSatStartupCase, + DualSatStartupCase, + SingleSatDetumbleCase, + DualSatDetumbleCase, + SingleSatStandbyCase, + DualSatStandbyCase +) from .psim_debug import PSimDebug from .dual_psim import DualPSim -# Testcases that don't require simulation -from .boot_to import BootToStartupCase, BootToDetumbleCase, BootToStandbyCase from .empty_case import EmptyCase, FailingEmptyCase from .dual_empty_case import DualEmptyCase from .ditl_case import DitlCase diff --git a/ptest/cases/boot_to.py b/ptest/cases/boot_to.py deleted file mode 100644 index a0bb16d34..000000000 --- a/ptest/cases/boot_to.py +++ /dev/null @@ -1,53 +0,0 @@ -from .base import SingleSatCase, PSimCase -from .utils import TestCaseFailure -import lin - -class BootToStartupCase(SingleSatCase, PSimCase): - - def __init__(self, *args, **kwargs): - super(BootToStartupCase, self).__init__(*args, **kwargs) - - self.psim_configs += ["truth/deployment"] - self.initial_state = "startup" - - def run(self): - if self.mission_state != "startup": - raise TestCaseFailure("Testcase failed to boot into startup") - - self.finish() - - -class BootToDetumbleCase(SingleSatCase, PSimCase): - - def __init__(self, *args, **kwargs): - super(BootToDetumbleCase, self).__init__(*args, **kwargs) - - self.psim_configs += ["truth/detumble"] - self.initial_state = "detumble" - self.skip_deployment_wait = True - - def run(self): - if self.mission_state != "detumble": - raise TestCaseFailure("Testcase failed to boot into detumble") - - self.finish() - - -class BootToStandbyCase(SingleSatCase, PSimCase): - - def __init__(self, *args, **kwargs): - super(BootToStandbyCase, self).__init__(*args, **kwargs) - - self.psim_configs += ["truth/standby"] - self.psim_config_overrides["truth.leader.attitude.w"] = lin.Vector3([0.01,0.071,-0.01]) - - self.initial_state = "standby" - self.skip_deployment_wait = True - - def run(self): - if self.mission_state != "standby": - raise TestCaseFailure("Testcase failed to boot into standby") - if not self.rs("attitude_estimator.valid"): - raise TestCaseFailure("Attitude estimator never became valid") - - self.finish() diff --git a/ptest/cases/mission/__init__.py b/ptest/cases/mission/__init__.py new file mode 100644 index 000000000..07c1bf01e --- /dev/null +++ b/ptest/cases/mission/__init__.py @@ -0,0 +1,3 @@ +from .startup import SingleSatStartupCase, DualSatStartupCase +from .detumble import SingleSatDetumbleCase, DualSatDetumbleCase +from .standby import SingleSatStandbyCase, DualSatStandbyCase diff --git a/ptest/cases/mission/detumble.py b/ptest/cases/mission/detumble.py new file mode 100644 index 000000000..642ba0272 --- /dev/null +++ b/ptest/cases/mission/detumble.py @@ -0,0 +1,45 @@ +from ..base import DualSatCase, SingleSatCase, PSimCase +from .utils import log_fc_data, log_psim_data + + +class SingleSatDetumbleCase(SingleSatCase, PSimCase): + + def __init__(self, *args, **kwargs): + super(SingleSatDetumbleCase, self).__init__(*args, **kwargs) + + self.psim_configs += ["truth/detumble"] + self.initial_state = "detumble" + self.skip_deployment_wait = True + + def run(self): + if not self.is_interactive: + self.finish() + return + + log_fc_data(self.flight_controller) + log_psim_data(self, "leader") + + self.cycle() + + +class DualSatDetumbleCase(DualSatCase, PSimCase): + + def __init__(self, *args, **kwargs): + super(DualSatDetumbleCase, self).__init__(*args, **kwargs) + + self.psim_configs += ["truth/detumble"] + self.leader_initial_state = "detumble" + self.follower_initial_state = "detumble" + self.leader_skip_deployment_wait = True + self.follower_skip_deployment_wait = True + + def run(self): + if not self.is_interactive: + self.finish() + return + + log_fc_data(self.flight_controller_leader) + log_fc_data(self.flight_controller_follower) + log_psim_data(self, "leader", "follower") + + self.cycle() diff --git a/ptest/cases/mission/standby.py b/ptest/cases/mission/standby.py new file mode 100644 index 000000000..e3a712c39 --- /dev/null +++ b/ptest/cases/mission/standby.py @@ -0,0 +1,59 @@ +from ..base import DualSatCase, SingleSatCase, PSimCase +from ..utils import TestCaseFailure +from .utils import log_fc_data, log_psim_data + +import lin + + +class SingleSatStandbyCase(SingleSatCase, PSimCase): + + def __init__(self, *args, **kwargs): + super(SingleSatStandbyCase, self).__init__(*args, **kwargs) + + self.psim_configs += ["truth/standby"] + self.psim_config_overrides["truth.leader.attitude.w"] = lin.Vector3([0.01,0.0711,-0.01]) + self.initial_state = "standby" + self.skip_deployment_wait = True + + def run(self): + if not self.is_interactive: + if not self.flight_controller.smart_read("attitude_estimator.valid"): + raise TestCaseFailure("Attitude estimator failed to initialize.") + + self.finish() + return + + log_fc_data(self.flight_controller) + log_psim_data(self, "leader") + + self.cycle() + + +class DualSatStandbyCase(DualSatCase, PSimCase): + + def __init__(self, *args, **kwargs): + super(DualSatStandbyCase, self).__init__(*args, **kwargs) + + self.psim_configs += ["truth/standby"] + self.psim_config_overrides["truth.leader.attitude.w"] = lin.Vector3([0.01,0.0711,-0.01]) + self.psim_config_overrides["truth.follower.attitude.w"] = lin.Vector3([0.01,0.0711,-0.01]) + self.leader_initial_state = "standby" + self.follower_initial_state = "standby" + self.leader_skip_deployment_wait = True + self.follower_skip_deployment_wait = True + + def run(self): + if not self.is_interactive: + if not self.flight_controller_leader.smart_read("attitude_estimator.valid"): + raise TestCaseFailure("Leader attitude estimator failed to initialize.") + if not self.flight_controller_follower.smart_read("attitude_estimator.valid"): + raise TestCaseFailure("Follower attitude estimator failed to initialize.") + + self.finish() + return + + log_fc_data(self.flight_controller_leader) + log_fc_data(self.flight_controller_follower) + log_psim_data(self, "leader", "follower") + + self.cycle() diff --git a/ptest/cases/mission/startup.py b/ptest/cases/mission/startup.py new file mode 100644 index 000000000..32265cd05 --- /dev/null +++ b/ptest/cases/mission/startup.py @@ -0,0 +1,42 @@ +from ..base import DualSatCase, SingleSatCase, PSimCase +from .utils import log_fc_data, log_psim_data + + +class SingleSatStartupCase(SingleSatCase, PSimCase): + + def __init__(self, *args, **kwargs): + super(SingleSatStartupCase, self).__init__(*args, **kwargs) + + self.psim_configs += ["truth/deployment"] + self.initial_state = "startup" + + def run(self): + if not self.is_interactive: + self.finish() + return + + log_fc_data(self.flight_controller) + log_psim_data(self, "leader") + + self.cycle() + + +class DualSatStartupCase(DualSatCase, PSimCase): + + def __init__(self, *args, **kwargs): + super(DualSatStartupCase, self).__init__(*args, **kwargs) + + self.psim_configs += ["truth/deployment"] + self.leader_initial_state = "startup" + self.follower_initial_state = "startup" + + def run(self): + if not self.is_interactive: + self.finish() + return + + log_fc_data(self.flight_controller_leader) + log_fc_data(self.flight_controller_follower) + log_psim_data(self, "leader", "follower") + + self.cycle() diff --git a/ptest/cases/mission/utils.py b/ptest/cases/mission/utils.py new file mode 100644 index 000000000..1ed2d3b72 --- /dev/null +++ b/ptest/cases/mission/utils.py @@ -0,0 +1,71 @@ +"""Utility functions specific to full mission cases. + +Full mission cases here refers to those intended to be used for mission +rehearsals. +""" + +fc_fields = [ + # Core state information + "pan.state", + "pan.bootcount", + "pan.cycle_no", + "pan.deployment.elapsed", + # Other state machine states + "adcs.state", + "piksi.state", + "radio.state", + # Estimator information + "time.valid", + "time.gps", + "orbit.valid", + "orbit.pos", + "orbit.vel", + "rel_orbit.state", + "rel_orbit.rel_pos", + "rel_orbit.rel_vel", + "attitude_estimator.valid", + "attitude_estimator.q_body_eci", + "attitude_estimator.L_body", + "attitude_estimator.w_bias_body", + # Attitude control commands + "adcs_cmd.mtr_cmd", + "adcs_cmd.rwa_torque_cmd", + # PSim sensor debugging information +# "piksi.time" +# "adcs_monitor.ssa_vec", +# "adcs_monitor.mag1_vec", +# "adcs_monitor.gyr_vec", +# "adcs_monitor.ssa_mode", +] + +psim_fields_per_satellite = [ + "truth.{}.attitude.w", + "truth.{}.attitude.L", + "truth.{}.wheels.t", + "truth.{}.wheels.w", + "truth.{}.orbit.r.ecef", + "truth.{}.orbit.v.ecef", + "sensors.{}.gyroscope.w.bias" +] + +psim_fields = [ + "truth.t.ns", + "truth.dt.ns" +] + + +def log_fc_data(fc): + for field in fc_fields: + fc.smart_read(field) + + +def log_psim_data(case, *satellites): + """Logs a collection of PSim associated with a testcase for the satellite(s) + specified. + """ + for satellite in satellites: + for field in psim_fields_per_satellite: + case.rs_psim(field.format(satellite)) + + for field in psim_fields: + case.rs_psim(field) From 27440e510bc01c898139b54953c66764a5031fc9 Mon Sep 17 00:00:00 2001 From: Kyle Krol Date: Fri, 16 Apr 2021 18:30:17 -0400 Subject: [PATCH 2/4] removing dualpsim and psimdebug --- ptest/cases/__init__.py | 3 -- ptest/cases/dual_psim.py | 79 --------------------------------------- ptest/cases/psim_debug.py | 60 ----------------------------- 3 files changed, 142 deletions(-) delete mode 100644 ptest/cases/dual_psim.py delete mode 100644 ptest/cases/psim_debug.py diff --git a/ptest/cases/__init__.py b/ptest/cases/__init__.py index 25e3f3513..d68e6c763 100644 --- a/ptest/cases/__init__.py +++ b/ptest/cases/__init__.py @@ -18,9 +18,6 @@ DualSatStandbyCase ) -from .psim_debug import PSimDebug -from .dual_psim import DualPSim - from .empty_case import EmptyCase, FailingEmptyCase from .dual_empty_case import DualEmptyCase from .ditl_case import DitlCase diff --git a/ptest/cases/dual_psim.py b/ptest/cases/dual_psim.py deleted file mode 100644 index ebf0e8a02..000000000 --- a/ptest/cases/dual_psim.py +++ /dev/null @@ -1,79 +0,0 @@ -from .base import DualSatCase -from .base import PSimCase -import time -from psim.sims import DualAttitudeOrbitGnc -import lin -from .utils import str_to_val, Enums -from ..usb_session import USBSession - -class DualPSim(DualSatCase, PSimCase): - - def __init__(self, *args, **kwargs): - super(DualPSim, self).__init__(*args, **kwargs) - - self.debug_to_console = True - self.psim_configs += ["truth/deployment"] - - def log_fc_data(self, usb_device: USBSession): - - fc_states = ["pan.deployment.elapsed", - "pan.state", - "radio.state", - "piksi.state", - "pan.cycle_no", - "pan.bootcount", - "adcs.state", - "piksi.time", - "orbit.pos", - "orbit.vel", - "adcs_monitor.ssa_vec", - "adcs_monitor.mag1_vec", - "adcs_monitor.gyr_vec", - - 'adcs_monitor.ssa_mode', - - "attitude_estimator.q_body_eci", - "attitude_estimator.L_body", - # "attitude_estimator.fro_P", - "adcs_cmd.mtr_cmd", - "adcs_cmd.rwa_torque_cmd", - - "attitude_estimator.valid", - "attitude_estimator.w_bias_body", - "orbit.valid" - ] - - for fc_state in fc_states: - usb_device.smart_read(fc_state) - - def rs_psim_data(self): - - psim_states = [ - "truth.t.ns", - "truth.dt.ns"] - - psim_per_sat_states = [ - 'truth.{sat}.attitude.w', - 'truth.{sat}.attitude.L', - 'truth.{sat}.wheels.t', - 'truth.{sat}.wheels.w', - 'truth.{sat}.orbit.r.ecef', - 'truth.{sat}.orbit.v.ecef', - ] - - sats = ['follower', 'leader'] - - for sat_name in sats: - for psim_fn in psim_per_sat_states: - psim_full_name = psim_fn.format(sat = sat_name) - self.rs_psim(psim_full_name) - - for psim_state in psim_states: - self.rs_psim(psim_state) - - def run(self): - self.cycle() - - self.log_fc_data(self.flight_controller_leader) - self.log_fc_data(self.flight_controller_follower) - self.rs_psim_data() diff --git a/ptest/cases/psim_debug.py b/ptest/cases/psim_debug.py deleted file mode 100644 index b919618c7..000000000 --- a/ptest/cases/psim_debug.py +++ /dev/null @@ -1,60 +0,0 @@ -# Runs mission from startup state to standby state. -from .base import SingleSatCase -from .base import PSimCase -from psim.sims import SingleAttitudeOrbitGnc -from .utils import Enums, mag_of, sum_of_differentials -import lin - -class PSimDebug(SingleSatCase, PSimCase): - """ - comments - """ - def __init__(self, *args, **kwargs): - super(PSimDebug, self).__init__(*args, **kwargs) - self.initial_state = "startup" - self.psim_configs += ['truth/deployment'] - self.psim_config_overrides["truth.leader.attitude.w"] = lin.Vector3([0.01,0.0738,-0.01]) - - def data_logs(self): - - self.rs("pan.deployment.elapsed") - self.rs("pan.state") - self.rs("radio.state") - self.rs("pan.cycle_no") - self.rs("pan.bootcount") - self.rs("adcs.state") - self.rs("piksi.time") - self.rs("orbit.pos") - self.rs("orbit.vel") - self.rs('adcs_monitor.ssa_vec') - self.rs('adcs_monitor.mag1_vec') - self.rs('adcs_monitor.gyr_vec') - - self.rs('adcs_monitor.ssa_mode') - - self.rs("attitude_estimator.q_body_eci") - self.rs("attitude_estimator.L_body") - - self.rs("adcs_cmd.mtr_cmd") - self.rs("adcs_cmd.rwa_torque_cmd") - self.rs("attitude_estimator.valid"), - self.rs("attitude_estimator.w_bias_body"), - self.rs("orbit.valid") - - - def run(self): - """ - Log/compute all the things necessary to monitor performance - """ - - """ - The below call is necessary to step FSW, simulate psim, - as well as call any autotelem/dbtelem - """ - self.cycle() - - self.rs_psim("truth.leader.attitude.w") - self.rs_psim("truth.t.ns") - self.rs_psim("truth.dt.ns") - - self.data_logs() From 511a93217d3697e5741523b3a99197ed716ca311 Mon Sep 17 00:00:00 2001 From: Kyle Krol Date: Sat, 17 Apr 2021 10:06:30 -0400 Subject: [PATCH 3/4] update ci --- .github/workflows/hootl.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/hootl.yml b/.github/workflows/hootl.yml index c28fe4dcb..21ceefec0 100644 --- a/.github/workflows/hootl.yml +++ b/.github/workflows/hootl.yml @@ -62,10 +62,10 @@ jobs: run: | python -m ptest runsim -c ptest/configs/hootl.json -t SingleSatStartupCase -ni python -m ptest runsim -c ptest/configs/hootl_hootl.json -t DualSatStartupCase -ni - python -m ptest runsim -c ptest/configs/hootl.json -t SingleSatStartupCase -ni - python -m ptest runsim -c ptest/configs/hootl_hootl.json -t DualSatStartupCase -ni - python -m ptest runsim -c ptest/configs/hootl.json -t SingleSatStartupCase -ni - python -m ptest runsim -c ptest/configs/hootl_hootl.json -t DualSatStartupCase -ni + python -m ptest runsim -c ptest/configs/hootl.json -t SingleSatDetumbleCase -ni + python -m ptest runsim -c ptest/configs/hootl_hootl.json -t DualSatDetumbleCase -ni + python -m ptest runsim -c ptest/configs/hootl.json -t SingleSatStandbyCase -ni + python -m ptest runsim -c ptest/configs/hootl_hootl.json -t DualSatStandbyCase -ni - name: Hardware Checkout Cases run: | From c6cbee8d094587738127540e0f2245cd947e9450 Mon Sep 17 00:00:00 2001 From: Kyle Krol Date: Sat, 17 Apr 2021 10:09:16 -0400 Subject: [PATCH 4/4] cycle slip to make sure all plotted data is good --- ptest/cases/mission/detumble.py | 8 ++++---- ptest/cases/mission/standby.py | 8 ++++---- ptest/cases/mission/startup.py | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ptest/cases/mission/detumble.py b/ptest/cases/mission/detumble.py index 642ba0272..590984cf7 100644 --- a/ptest/cases/mission/detumble.py +++ b/ptest/cases/mission/detumble.py @@ -12,6 +12,8 @@ def __init__(self, *args, **kwargs): self.skip_deployment_wait = True def run(self): + self.cycle() + if not self.is_interactive: self.finish() return @@ -19,8 +21,6 @@ def run(self): log_fc_data(self.flight_controller) log_psim_data(self, "leader") - self.cycle() - class DualSatDetumbleCase(DualSatCase, PSimCase): @@ -34,6 +34,8 @@ def __init__(self, *args, **kwargs): self.follower_skip_deployment_wait = True def run(self): + self.cycle() + if not self.is_interactive: self.finish() return @@ -41,5 +43,3 @@ def run(self): log_fc_data(self.flight_controller_leader) log_fc_data(self.flight_controller_follower) log_psim_data(self, "leader", "follower") - - self.cycle() diff --git a/ptest/cases/mission/standby.py b/ptest/cases/mission/standby.py index e3a712c39..74b22ae4a 100644 --- a/ptest/cases/mission/standby.py +++ b/ptest/cases/mission/standby.py @@ -16,6 +16,8 @@ def __init__(self, *args, **kwargs): self.skip_deployment_wait = True def run(self): + self.cycle() + if not self.is_interactive: if not self.flight_controller.smart_read("attitude_estimator.valid"): raise TestCaseFailure("Attitude estimator failed to initialize.") @@ -26,8 +28,6 @@ def run(self): log_fc_data(self.flight_controller) log_psim_data(self, "leader") - self.cycle() - class DualSatStandbyCase(DualSatCase, PSimCase): @@ -43,6 +43,8 @@ def __init__(self, *args, **kwargs): self.follower_skip_deployment_wait = True def run(self): + self.cycle() + if not self.is_interactive: if not self.flight_controller_leader.smart_read("attitude_estimator.valid"): raise TestCaseFailure("Leader attitude estimator failed to initialize.") @@ -55,5 +57,3 @@ def run(self): log_fc_data(self.flight_controller_leader) log_fc_data(self.flight_controller_follower) log_psim_data(self, "leader", "follower") - - self.cycle() diff --git a/ptest/cases/mission/startup.py b/ptest/cases/mission/startup.py index 32265cd05..b41ba4f35 100644 --- a/ptest/cases/mission/startup.py +++ b/ptest/cases/mission/startup.py @@ -11,6 +11,8 @@ def __init__(self, *args, **kwargs): self.initial_state = "startup" def run(self): + self.cycle() + if not self.is_interactive: self.finish() return @@ -18,8 +20,6 @@ def run(self): log_fc_data(self.flight_controller) log_psim_data(self, "leader") - self.cycle() - class DualSatStartupCase(DualSatCase, PSimCase): @@ -31,6 +31,8 @@ def __init__(self, *args, **kwargs): self.follower_initial_state = "startup" def run(self): + self.cycle() + if not self.is_interactive: self.finish() return @@ -38,5 +40,3 @@ def run(self): log_fc_data(self.flight_controller_leader) log_fc_data(self.flight_controller_follower) log_psim_data(self, "leader", "follower") - - self.cycle()