From f0523a1a739296ad70880fd2922f019c5d071cfa Mon Sep 17 00:00:00 2001 From: keithmk Date: Tue, 26 Sep 2023 16:25:05 -0400 Subject: [PATCH 01/26] Created Preflight node and checks if running in simulation --- mil_common/utils/mil_tools/scripts/preflight.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 mil_common/utils/mil_tools/scripts/preflight.py diff --git a/mil_common/utils/mil_tools/scripts/preflight.py b/mil_common/utils/mil_tools/scripts/preflight.py new file mode 100755 index 000000000..185c5d21c --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/preflight.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +import rospy + +# Use Rich for nice printing +if __name__ == "__main__": + # Initialize the Preflight Node + rospy.init_node("preflight") + + print("Checking for Gazebo") + # Check if the Gazebo Node exists + if rospy.get_param("/is_simulation", None): + print("Running a Simulation") + else: + print("Running for real") From 498a693853a2714edf2e24224ba281550718088b Mon Sep 17 00:00:00 2001 From: Anthony Liao Date: Thu, 5 Oct 2023 12:34:28 -0400 Subject: [PATCH 02/26] added test file --- .../utils/mil_tools/scripts/preflightUI.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100755 mil_common/utils/mil_tools/scripts/preflightUI.py diff --git a/mil_common/utils/mil_tools/scripts/preflightUI.py b/mil_common/utils/mil_tools/scripts/preflightUI.py new file mode 100755 index 000000000..7f7e9127a --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/preflightUI.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +import blessed + +inp = "" +term = blessed.Terminal() +pos = 0 + +while inp != "q": + maxPos = 3 + height, width = term.height, term.width + + # reprint line selected -> term.on_green"message" + + print(term.home + term.clear + term.blink + term.on_green("pressed ") + repr(inp)) + + print("testing screen\n") + print("checklist") + print("hiiardware checklist") + + print(term.move_y(term.height // 2)) + print(term.black_on_darkkhaki(term.center("press any key"))) + + with term.cbreak(): + inp = term.inkey() + if inp == "k" or inp == "KEY_UP": + if pos == 0: + pos = maxPos + else: + pos -= 1 + + if inp == "j" or inp == "KEY_DOWN": + if pos == maxPos: + pos = 0 + else: + pos += 1 From 00236569dbb5c5e612832237caf39d07d44b7345 Mon Sep 17 00:00:00 2001 From: keithmk Date: Thu, 5 Oct 2023 13:12:42 -0400 Subject: [PATCH 03/26] Moved Preflight files to their own folder --- .../utils/mil_tools/scripts/preflight/SubChecklist.txt | 1 + .../utils/mil_tools/scripts/{ => preflight}/preflight.py | 1 - .../utils/mil_tools/scripts/preflight/preflightFileIO.py | 8 ++++++++ .../mil_tools/scripts/{ => preflight}/preflightUI.py | 0 requirements.txt | 3 +++ 5 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt rename mil_common/utils/mil_tools/scripts/{ => preflight}/preflight.py (99%) create mode 100755 mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py rename mil_common/utils/mil_tools/scripts/{ => preflight}/preflightUI.py (100%) diff --git a/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt b/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt new file mode 100644 index 000000000..0527e6bd2 --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt @@ -0,0 +1 @@ +This is a test diff --git a/mil_common/utils/mil_tools/scripts/preflight.py b/mil_common/utils/mil_tools/scripts/preflight/preflight.py similarity index 99% rename from mil_common/utils/mil_tools/scripts/preflight.py rename to mil_common/utils/mil_tools/scripts/preflight/preflight.py index 185c5d21c..2ef27716f 100755 --- a/mil_common/utils/mil_tools/scripts/preflight.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflight.py @@ -5,7 +5,6 @@ if __name__ == "__main__": # Initialize the Preflight Node rospy.init_node("preflight") - print("Checking for Gazebo") # Check if the Gazebo Node exists if rospy.get_param("/is_simulation", None): diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py new file mode 100755 index 000000000..85e357b07 --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 + +SubCheckList = open("SubChecklist.txt", "a+") +line = ["This is a test\n"] +SubCheckList.writelines(line) + + +SubCheckList.close() diff --git a/mil_common/utils/mil_tools/scripts/preflightUI.py b/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py similarity index 100% rename from mil_common/utils/mil_tools/scripts/preflightUI.py rename to mil_common/utils/mil_tools/scripts/preflight/preflightUI.py diff --git a/requirements.txt b/requirements.txt index 90237fb22..eefa4a3e7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,6 +31,9 @@ breathe==4.34.0 myst-parser==0.18.0 sphinx-copybutton==0.5.0 +# Terminal +blessed==1.20.0 + # External Devices pyserial==3.5 From 7e68619f347d3b62267e0a2f98009d0373250020 Mon Sep 17 00:00:00 2001 From: Anthony Liao Date: Tue, 10 Oct 2023 15:46:12 -0400 Subject: [PATCH 04/26] menu add --- .../scripts/preflight/preflightUI.py | 58 ++++++++++++++----- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py b/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py index 7f7e9127a..389fb6bb0 100755 --- a/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py @@ -5,31 +5,63 @@ term = blessed.Terminal() pos = 0 -while inp != "q": - maxPos = 3 - height, width = term.height, term.width +machine = ["SubjuGator", "NaviGator", "Exit"] +options = [ + "Hardware Checklist", + "Software Checklist", + "Rosnode Command", + "Back", + "Exit", +] +currmenu = machine - # reprint line selected -> term.on_green"message" +while inp != "q": + maxPos = len(currmenu) + # reprint line selected -> term.on_green"message" print(term.home + term.clear + term.blink + term.on_green("pressed ") + repr(inp)) - print("testing screen\n") - print("checklist") - print("hiiardware checklist") + print("Preflight Checklist\n") - print(term.move_y(term.height // 2)) - print(term.black_on_darkkhaki(term.center("press any key"))) + for x in range(0, maxPos): + if x == pos: + print(term.blink + term.on_green(currmenu[x])) + else: + print(currmenu[x]) with term.cbreak(): inp = term.inkey() - if inp == "k" or inp == "KEY_UP": + if inp == "k" or inp.name == "KEY_UP": if pos == 0: - pos = maxPos + pos = maxPos - 1 else: pos -= 1 - if inp == "j" or inp == "KEY_DOWN": - if pos == maxPos: + if inp == "j" or inp.name == "KEY_DOWN": + if pos == maxPos - 1: pos = 0 else: pos += 1 + if inp.name == "KEY_ENTER": + if pos == maxPos - 1: + inp = "q" + continue + if currmenu == machine: + currmenu = options + elif currmenu == options: + pass + else: + pass + + +def hardware_test(terminal): + pass + + +def software_test(terminal): + # this should run ros and do all the init tests + pass + + +def run_command(terminal): + pass From 76a802428acba9ed7435602c26e2563e21ed789b Mon Sep 17 00:00:00 2001 From: Josht8601 Date: Tue, 17 Oct 2023 14:10:29 -0400 Subject: [PATCH 05/26] Added File IO --- .../scripts/preflight/SubChecklist.txt | 2 +- .../scripts/preflight/preflightFileIO.py | 62 +++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt b/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt index 0527e6bd2..345e6aef7 100644 --- a/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt +++ b/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt @@ -1 +1 @@ -This is a test +Test diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py index 85e357b07..272c56678 100755 --- a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py @@ -1,8 +1,62 @@ #!/usr/bin/env python3 -SubCheckList = open("SubChecklist.txt", "a+") -line = ["This is a test\n"] -SubCheckList.writelines(line) +# Systems[] +# Global variable that contains all the systems. Used to standardized file name. Ex Subjugator or Navigator +# writeTests(fileName, topicsToCheck[]) +# fileName should standardized, this input should be from a selected number of names +# topicsToCheck[] this array should only contain valid topics that we will make sure data is in. +# What ever program calls this function should only pass in valid topics. This will be a list of strings. +# This should not delete old topicsToCheck only add new ones. -SubCheckList.close() +# deleteTests(fileName, topicsToCheck[]) +# fileName should standardized, this input should be from a selected number of names +# topicsToCheck[] this array should only contain valid topics that we will make sure data is in. +# What ever program calls this function should only pass in valid topics. This will be a list of strings. +# delete tests from the file. + +# readTests(filename) +# reads and runs all the tests in the file. +# returns whether each test pass or fail + + +def writeTests(filename, topicsToCheck): + tests = open(filename, "a+") + lines = tests.readlines() + + # If the topic to add is not already in the list add it + for topic in topicsToCheck: + topic += "\n" + if topic not in lines: + tests.write(topic) + tests.close() + + +def deleteTests(filename, topicsToCheck): + tests = open(filename) + lines = tests.readlines() + tests.close() + + # If the topic to add is not already in the list add it + for topic in topicsToCheck: + topic += "\n" + if topic in lines: + lines.remove(topic) + + tests = open(filename, "w") + tests.writelines(lines) + + +def readTests(filename): + tests = open(filename) + lines = tests.readlines() + for i in range(len(lines)): + lines[i] = lines[i][:-1] + + print(lines) + # We need to call the ros topic and verify the data WIP + + +writeTests("SubChecklist.txt", ["Test", "testing"]) +deleteTests("SubChecklist.txt", ["testing"]) +readTests("SubChecklist.txt") From 8c6b83e60801b33de5b83ca6c734c5f442103651 Mon Sep 17 00:00:00 2001 From: Josht8601 Date: Tue, 17 Oct 2023 14:57:53 -0400 Subject: [PATCH 06/26] Working on Read function --- .../scripts/preflight/preflightFileIO.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py index 272c56678..436767a28 100755 --- a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py @@ -18,6 +18,8 @@ # readTests(filename) # reads and runs all the tests in the file. # returns whether each test pass or fail +import rospy +import rostopic def writeTests(filename, topicsToCheck): @@ -50,13 +52,23 @@ def deleteTests(filename, topicsToCheck): def readTests(filename): tests = open(filename) lines = tests.readlines() + dataTypes = [] for i in range(len(lines)): lines[i] = lines[i][:-1] + TopicType, topic_str, _ = rostopic.get_topic_class(lines[i]) + dataTypes.append(TopicType) + lines[i] = topic_str + rospy.Subscriber(lines[i], dataTypes[i], some_callback) + + +def some_callback(msg): + rospy.loginfo("Got the message: " + str(msg)) - print(lines) # We need to call the ros topic and verify the data WIP -writeTests("SubChecklist.txt", ["Test", "testing"]) -deleteTests("SubChecklist.txt", ["testing"]) -readTests("SubChecklist.txt") +if __name__ == "__main__": + rospy.init_node("topic_publisher_checker") + writeTests("SubChecklist.txt", ["dvl", "odom"]) + deleteTests("SubChecklist.txt", ["testing"]) + readTests("SubChecklist.txt") From e7a4f265370f5e94397f03fa43f251b4dfdcc064 Mon Sep 17 00:00:00 2001 From: Josht8601 Date: Thu, 19 Oct 2023 18:58:59 -0400 Subject: [PATCH 07/26] Added the functionality to test topics --- .../scripts/preflight/SubChecklist.txt | 3 +- .../scripts/preflight/preflightFileIO.py | 39 +++++++++++++------ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt b/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt index 345e6aef7..2d9664d4a 100644 --- a/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt +++ b/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt @@ -1 +1,2 @@ -Test +dvl +odom diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py index 436767a28..7a339641a 100755 --- a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py @@ -23,8 +23,15 @@ def writeTests(filename, topicsToCheck): + lines = [] + try: + tests = open(filename) # open file for reading + lines = tests.readlines() + tests.close() + except OSError: + pass + tests = open(filename, "a+") - lines = tests.readlines() # If the topic to add is not already in the list add it for topic in topicsToCheck: @@ -50,25 +57,35 @@ def deleteTests(filename, topicsToCheck): def readTests(filename): - tests = open(filename) - lines = tests.readlines() - dataTypes = [] + tests = open(filename) # Read the file + lines = tests.readlines() # Store all tests from file into array + dataTypes = [] # Create list to store topic datatypes + results = [] # list to store the results of all the tests + + print(lines) + # Loop through all the tests for i in range(len(lines)): + # Fix the formatting of the tests to match topic names lines[i] = lines[i][:-1] + lines[i] = f"/{lines[i]}" + + # Get the topic types TopicType, topic_str, _ = rostopic.get_topic_class(lines[i]) dataTypes.append(TopicType) - lines[i] = topic_str - rospy.Subscriber(lines[i], dataTypes[i], some_callback) - + lines[i] = topic_str # Fix the topic names -def some_callback(msg): - rospy.loginfo("Got the message: " + str(msg)) + # Try calling the topic + try: + rospy.wait_for_message(lines[i], dataTypes[i]) + results.append(True) + except Exception: + results.append(False) - # We need to call the ros topic and verify the data WIP + return results if __name__ == "__main__": rospy.init_node("topic_publisher_checker") writeTests("SubChecklist.txt", ["dvl", "odom"]) deleteTests("SubChecklist.txt", ["testing"]) - readTests("SubChecklist.txt") + print(readTests("SubChecklist.txt")) From f4877b443e31f81b169bc187d698b65e51d248cf Mon Sep 17 00:00:00 2001 From: Josht8601 Date: Thu, 19 Oct 2023 19:07:11 -0400 Subject: [PATCH 08/26] Imported File IO into main preflight script --- .../mil_tools/scripts/preflight/preflight.py | 5 +++++ .../scripts/preflight/preflightFileIO.py | 15 +++------------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflight.py b/mil_common/utils/mil_tools/scripts/preflight/preflight.py index 2ef27716f..3eb514692 100755 --- a/mil_common/utils/mil_tools/scripts/preflight/preflight.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflight.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import preflightFileIO import rospy # Use Rich for nice printing @@ -11,3 +12,7 @@ print("Running a Simulation") else: print("Running for real") + + preflightFileIO.writeTests("SubChecklist.txt", ["dvl", "odom", "testing"]) + preflightFileIO.deleteTests("SubChecklist.txt", ["testing"]) + print(preflightFileIO.readTests("SubChecklist.txt")) diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py index 7a339641a..768586b95 100755 --- a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py @@ -1,8 +1,5 @@ #!/usr/bin/env python3 -# Systems[] -# Global variable that contains all the systems. Used to standardized file name. Ex Subjugator or Navigator - # writeTests(fileName, topicsToCheck[]) # fileName should standardized, this input should be from a selected number of names # topicsToCheck[] this array should only contain valid topics that we will make sure data is in. @@ -18,6 +15,8 @@ # readTests(filename) # reads and runs all the tests in the file. # returns whether each test pass or fail + + import rospy import rostopic @@ -62,7 +61,6 @@ def readTests(filename): dataTypes = [] # Create list to store topic datatypes results = [] # list to store the results of all the tests - print(lines) # Loop through all the tests for i in range(len(lines)): # Fix the formatting of the tests to match topic names @@ -81,11 +79,4 @@ def readTests(filename): except Exception: results.append(False) - return results - - -if __name__ == "__main__": - rospy.init_node("topic_publisher_checker") - writeTests("SubChecklist.txt", ["dvl", "odom"]) - deleteTests("SubChecklist.txt", ["testing"]) - print(readTests("SubChecklist.txt")) + return [lines, results] From 3cd9717e114a559dfbbc98f2ef8cd03e37698a1c Mon Sep 17 00:00:00 2001 From: Anthony Liao Date: Tue, 24 Oct 2023 15:21:46 -0400 Subject: [PATCH 09/26] added UI functionality --- .../scripts/preflight/preflightUI.py | 184 +++++++++++++----- 1 file changed, 131 insertions(+), 53 deletions(-) diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py b/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py index 389fb6bb0..82c5e5075 100755 --- a/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py @@ -1,67 +1,145 @@ #!/usr/bin/env python3 import blessed -inp = "" -term = blessed.Terminal() -pos = 0 - -machine = ["SubjuGator", "NaviGator", "Exit"] -options = [ - "Hardware Checklist", - "Software Checklist", - "Rosnode Command", - "Back", - "Exit", -] -currmenu = machine - - -while inp != "q": - maxPos = len(currmenu) - # reprint line selected -> term.on_green"message" - print(term.home + term.clear + term.blink + term.on_green("pressed ") + repr(inp)) - - print("Preflight Checklist\n") - - for x in range(0, maxPos): - if x == pos: - print(term.blink + term.on_green(currmenu[x])) - else: - print(currmenu[x]) - - with term.cbreak(): - inp = term.inkey() - if inp == "k" or inp.name == "KEY_UP": - if pos == 0: - pos = maxPos - 1 - else: - pos -= 1 - if inp == "j" or inp.name == "KEY_DOWN": - if pos == maxPos - 1: - pos = 0 - else: - pos += 1 - if inp.name == "KEY_ENTER": - if pos == maxPos - 1: - inp = "q" - continue - if currmenu == machine: - currmenu = options - elif currmenu == options: - pass +def main(): + inp = "" + term = blessed.Terminal() + pos = 0 + + # TESTING VARS BEFORE REAL FUNCTIONS WORK + hwtest = [ + "test 1", + "test 2", + "test 3", + "test 4", + "test 5", + "test 6", + "test 7", + "test 8", + "test 9", + "test 10", + "test 11", + ] + + # ================ + + machine = ["SubjuGator", "NaviGator", "Exit"] + options = [ + "Hardware Checklist", + "Software Checklist", + "Rosnode Command", + "Add Software Test", + "Remove Software Test", + "Back", + "Exit", + ] + currMenu = machine + + hardwarePass = False + softwarePass = False + + while inp != "q": + maxPos = len(currMenu) + # reprint line selected -> term.on_green"message" + print(term.home + term.clear + term.center("Preflight Checklist\n")) + + for x in range(0, maxPos): + if x == pos: + print(term.blink + term.center(term.on_yellow(currMenu[x]))) else: - pass + if currMenu == options: + # if menu is options, set hardware/software to red or green depending on if it's completed + if x == 0: + # pass + print( + term.center(term.on_green(currMenu[x])) + if hardwarePass + else term.center(term.on_red(currMenu[x])), + ) + elif x == 1: + print( + term.center(term.on_green(currMenu[x])) + if softwarePass + else term.center(term.on_red(currMenu[x])), + ) + else: + print(term.center(currMenu[x])) + else: + print(term.center(currMenu[x])) + + with term.cbreak(), term.hidden_cursor(): + inp = term.inkey() + if inp == "k" or inp.name == "KEY_UP": + if pos == 0: + pos = maxPos - 1 + else: + pos -= 1 + + if inp == "j" or inp.name == "KEY_DOWN": + if pos == maxPos - 1: + pos = 0 + else: + pos += 1 + if inp.name == "KEY_ENTER" or inp == " ": + # if selection is exit + if pos == maxPos - 1: + inp = "q" + continue + # if in first screen go to second + if currMenu == machine: + currMenu = options + machine[pos] + # if in second menu + elif currMenu == options: + # Hardware Check + if pos == 0: + hardware_test(term, hwtest) + # Software Check + if pos == 1: + software_test(term) + # ROSnode command + if pos == 2: + run_command(term) + # add test to the checklist + if pos == 3: + write_test(term) + # if back selected + if pos == 5: + currMenu = machine + pos = 0 + else: + pass -def hardware_test(terminal): - pass +def hardware_test(term, hwtest): + inp = "" + while inp != "q": + print(term.clear + term.center("Hardware Tests\n")) + for x in hwtest: + print(term.on_red(x)) -def software_test(terminal): + with term.cbreak(), term.hidden_cursor(): + inp = term.inkey() + + +def software_test(term): # this should run ros and do all the init tests pass -def run_command(terminal): +def run_command(term): + pass + + +def write_test(term): pass + + +def delete_test(term): + pass + + +if __name__ == "__main__": + main() From 305ea935c2a72a144fe196a202454f0419d5d9e4 Mon Sep 17 00:00:00 2001 From: Josht8601 Date: Tue, 24 Oct 2023 16:08:26 -0400 Subject: [PATCH 10/26] Updated File IO for hardware and Software --- .../scripts/preflight/SubChecklist.txt | 5 +- .../mil_tools/scripts/preflight/preflight.py | 8 +- .../scripts/preflight/preflightFileIO.py | 158 +++++++++++------- 3 files changed, 109 insertions(+), 62 deletions(-) diff --git a/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt b/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt index 2d9664d4a..fa85c8443 100644 --- a/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt +++ b/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt @@ -1,2 +1,3 @@ -dvl -odom +=== Hardware Checks === +check valve +=== Software Checks === diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflight.py b/mil_common/utils/mil_tools/scripts/preflight/preflight.py index 3eb514692..a1870cfa8 100755 --- a/mil_common/utils/mil_tools/scripts/preflight/preflight.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflight.py @@ -13,6 +13,10 @@ else: print("Running for real") - preflightFileIO.writeTests("SubChecklist.txt", ["dvl", "odom", "testing"]) - preflightFileIO.deleteTests("SubChecklist.txt", ["testing"]) + preflightFileIO.writeTests( + "SubChecklist.txt", + ["h check safety", "s TOPIC /dvl", "h check valve"], + ) + preflightFileIO.deleteTests("SubChecklist.txt", ["check safety"]) print(preflightFileIO.readTests("SubChecklist.txt")) + print(preflightFileIO.runTests("SubChecklist.txt", 1)) diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py index 768586b95..426f512a5 100755 --- a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py @@ -1,82 +1,124 @@ #!/usr/bin/env python3 -# writeTests(fileName, topicsToCheck[]) -# fileName should standardized, this input should be from a selected number of names -# topicsToCheck[] this array should only contain valid topics that we will make sure data is in. -# What ever program calls this function should only pass in valid topics. This will be a list of strings. -# This should not delete old topicsToCheck only add new ones. - -# deleteTests(fileName, topicsToCheck[]) -# fileName should standardized, this input should be from a selected number of names -# topicsToCheck[] this array should only contain valid topics that we will make sure data is in. -# What ever program calls this function should only pass in valid topics. This will be a list of strings. -# delete tests from the file. - -# readTests(filename) -# reads and runs all the tests in the file. -# returns whether each test pass or fail - +import contextlib import rospy import rostopic -def writeTests(filename, topicsToCheck): - lines = [] +def writeTests(filename, testsToAdd): + hardwareLines = [] + softwareLines = [] try: - tests = open(filename) # open file for reading - lines = tests.readlines() - tests.close() + hardwareLines = getHardwareChecks(filename) + softwareLines = getSoftwareChecks(filename) except OSError: pass - tests = open(filename, "a+") + tests = open(filename, "w") + tests.write("=== Hardware Checks ===\n") + + # If the hardware topic to add is not already in the list add it + for test in testsToAdd: + if test[0] == "h": + test = test[2:] + test += "\n" + if test not in hardwareLines: + tests.write(test) + + tests.write("=== Software Checks ===\n") + + # If the software topic to add is not already in the list add it + for test in testsToAdd: + if test[0] == "s": + test = test[2:] + test += "\n" + if test not in softwareLines: + tests.write(test) - # If the topic to add is not already in the list add it - for topic in topicsToCheck: - topic += "\n" - if topic not in lines: - tests.write(topic) tests.close() -def deleteTests(filename, topicsToCheck): - tests = open(filename) - lines = tests.readlines() - tests.close() +def deleteTests(filename, testsToDelete): + hardwareLines = [] + softwareLines = [] + + try: + hardwareLines = getHardwareChecks(filename) + softwareLines = getSoftwareChecks(filename) + except OSError: + return False + + for test in testsToDelete: + test += "\n" + with contextlib.suppress(Exception): + hardwareLines.remove(test) - # If the topic to add is not already in the list add it - for topic in topicsToCheck: - topic += "\n" - if topic in lines: - lines.remove(topic) + with contextlib.suppress(Exception): + softwareLines.remove(test) tests = open(filename, "w") - tests.writelines(lines) + tests.write("=== Hardware Checks ===\n") + tests.writelines(hardwareLines) + tests.write("=== Software Checks ===\n") + tests.writelines(softwareLines) def readTests(filename): - tests = open(filename) # Read the file - lines = tests.readlines() # Store all tests from file into array - dataTypes = [] # Create list to store topic datatypes - results = [] # list to store the results of all the tests - - # Loop through all the tests - for i in range(len(lines)): - # Fix the formatting of the tests to match topic names - lines[i] = lines[i][:-1] - lines[i] = f"/{lines[i]}" - - # Get the topic types - TopicType, topic_str, _ = rostopic.get_topic_class(lines[i]) - dataTypes.append(TopicType) - lines[i] = topic_str # Fix the topic names - - # Try calling the topic + return [getHardwareChecks(filename), getSoftwareChecks(filename)] + + +def runTests(filename, index): + sChecks = getSoftwareChecks(filename) + + testType = sChecks[index].split()[0] + testTopic = sChecks[index].split()[1] + + if testType == "TOPIC": + TopicType, topic_str, _ = rostopic.get_topic_class(testTopic) + try: - rospy.wait_for_message(lines[i], dataTypes[i]) - results.append(True) + rospy.wait_for_message(topic_str, TopicType) + return True except Exception: - results.append(False) + return False + + +def getHardwareChecks(filename): + checks = open(filename) + foundHardware = False + hardwareChecks = [] + for index, line in enumerate(checks): + if "=== Hardware Checks ===" in line: + foundHardware = True + continue + + if "=== Software Checks ===" in line: + foundHardware = False + continue + + if foundHardware: + hardwareChecks.append(line) + + checks.close() + return hardwareChecks + + +def getSoftwareChecks(filename): + checks = open(filename) + foundSoftware = False + softwareChecks = [] + for index, line in enumerate(checks): + if "=== Hardware Checks ===" in line: + foundSoftware = False + continue + + if "=== Software Checks ===" in line: + foundSoftware = True + continue + + if foundSoftware: + softwareChecks.append(line) - return [lines, results] + checks.close() + return softwareChecks From f5e5a08f0e4d33e84ad7db21a2a21b5bd9ac9cfc Mon Sep 17 00:00:00 2001 From: keithmk Date: Sun, 21 Jan 2024 23:52:55 -0500 Subject: [PATCH 11/26] converted to typer, for a more cli solution --- .../scripts/preflight/SubChecklist.txt | 3 - .../mil_tools/scripts/preflight/preflight.py | 111 +++++++++++--- .../scripts/preflight/preflightFileIO.py | 124 --------------- .../scripts/preflight/preflightUI.py | 145 ------------------ requirements.txt | 3 +- 5 files changed, 94 insertions(+), 292 deletions(-) delete mode 100644 mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt mode change 100755 => 100644 mil_common/utils/mil_tools/scripts/preflight/preflight.py delete mode 100755 mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py delete mode 100755 mil_common/utils/mil_tools/scripts/preflight/preflightUI.py diff --git a/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt b/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt deleted file mode 100644 index fa85c8443..000000000 --- a/mil_common/utils/mil_tools/scripts/preflight/SubChecklist.txt +++ /dev/null @@ -1,3 +0,0 @@ -=== Hardware Checks === -check valve -=== Software Checks === diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflight.py b/mil_common/utils/mil_tools/scripts/preflight/preflight.py old mode 100755 new mode 100644 index a1870cfa8..f49cc02f6 --- a/mil_common/utils/mil_tools/scripts/preflight/preflight.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflight.py @@ -1,22 +1,95 @@ -#!/usr/bin/env python3 -import preflightFileIO +import subprocess + +import rosnode import rospy +import rostopic +import typer +from PyInquirer import prompt -# Use Rich for nice printing -if __name__ == "__main__": - # Initialize the Preflight Node +app = typer.Typer() + +hardwareChecklist = [ + { + "type": "checkbox", + "message": "Hardware Checklist:", + "name": "HardwareTests", + "choices": [ + {"name": "check thing 1"}, + {"name": "check thing 2"}, + {"name": "check thing 3"}, + {"name": "check thing 4"}, + {"name": "check thing 5"}, + ], + }, +] +mechanicalChecklist = [ + { + "type": "list", + "message": "Select which system you want to run. BE CAREFUL make sure everyone's fingures are secured.", + "name": "Mechanical Systems Check:", + "choices": ["thrusters", "Gripper"], + }, +] + +topics = [ + "/camera/front/right/image_raw", + "/camera/down/image_raw", + "/camera/front/left/image_raw", + "/dvl", + "/depth", + "/imu/data_raw", + "/imu/mag", +] + +nodes = ["/odom_estimator"] + +run = ["/thrusters/thrust"] + + +@app.command("Start") +def main(): + subprocess.run("clear", shell=True) + answers = prompt(hardwareChecklist) + while len(answers["HardwareTests"]) != 5: + subprocess.run("clear", shell=True) + answers = prompt(hardwareChecklist) + print(answers) + + +@app.command("Topic") +def topic(): rospy.init_node("preflight") - print("Checking for Gazebo") - # Check if the Gazebo Node exists - if rospy.get_param("/is_simulation", None): - print("Running a Simulation") - else: - print("Running for real") - - preflightFileIO.writeTests( - "SubChecklist.txt", - ["h check safety", "s TOPIC /dvl", "h check valve"], - ) - preflightFileIO.deleteTests("SubChecklist.txt", ["check safety"]) - print(preflightFileIO.readTests("SubChecklist.txt")) - print(preflightFileIO.runTests("SubChecklist.txt", 1)) + answers = [] + for topic in topics: + try: + topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class + rospy.wait_for_message( + topicStr, + topicType, + 5, + ) # try to get a message from that topic + answers.append({topic: True}) + except Exception: + answers.append({topic: False}) + print(answers) + + +@app.command("Node") +def node(): + rospy.init_node("preflight") + answers = [] + for node in nodes: + try: + answers.append({node: rosnode.rosnode_ping(node, 5)}) + except Exception: + answers.append({node: False}) + print(answers) + + +@app.command("Run") +def Run(): + rospy.init_node("preflight") + + +if __name__ == "__main__": + app() diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py b/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py deleted file mode 100755 index 426f512a5..000000000 --- a/mil_common/utils/mil_tools/scripts/preflight/preflightFileIO.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env python3 - -import contextlib - -import rospy -import rostopic - - -def writeTests(filename, testsToAdd): - hardwareLines = [] - softwareLines = [] - try: - hardwareLines = getHardwareChecks(filename) - softwareLines = getSoftwareChecks(filename) - except OSError: - pass - - tests = open(filename, "w") - tests.write("=== Hardware Checks ===\n") - - # If the hardware topic to add is not already in the list add it - for test in testsToAdd: - if test[0] == "h": - test = test[2:] - test += "\n" - if test not in hardwareLines: - tests.write(test) - - tests.write("=== Software Checks ===\n") - - # If the software topic to add is not already in the list add it - for test in testsToAdd: - if test[0] == "s": - test = test[2:] - test += "\n" - if test not in softwareLines: - tests.write(test) - - tests.close() - - -def deleteTests(filename, testsToDelete): - hardwareLines = [] - softwareLines = [] - - try: - hardwareLines = getHardwareChecks(filename) - softwareLines = getSoftwareChecks(filename) - except OSError: - return False - - for test in testsToDelete: - test += "\n" - with contextlib.suppress(Exception): - hardwareLines.remove(test) - - with contextlib.suppress(Exception): - softwareLines.remove(test) - - tests = open(filename, "w") - tests.write("=== Hardware Checks ===\n") - tests.writelines(hardwareLines) - tests.write("=== Software Checks ===\n") - tests.writelines(softwareLines) - - -def readTests(filename): - return [getHardwareChecks(filename), getSoftwareChecks(filename)] - - -def runTests(filename, index): - sChecks = getSoftwareChecks(filename) - - testType = sChecks[index].split()[0] - testTopic = sChecks[index].split()[1] - - if testType == "TOPIC": - TopicType, topic_str, _ = rostopic.get_topic_class(testTopic) - - try: - rospy.wait_for_message(topic_str, TopicType) - return True - except Exception: - return False - - -def getHardwareChecks(filename): - checks = open(filename) - foundHardware = False - hardwareChecks = [] - for index, line in enumerate(checks): - if "=== Hardware Checks ===" in line: - foundHardware = True - continue - - if "=== Software Checks ===" in line: - foundHardware = False - continue - - if foundHardware: - hardwareChecks.append(line) - - checks.close() - return hardwareChecks - - -def getSoftwareChecks(filename): - checks = open(filename) - foundSoftware = False - softwareChecks = [] - for index, line in enumerate(checks): - if "=== Hardware Checks ===" in line: - foundSoftware = False - continue - - if "=== Software Checks ===" in line: - foundSoftware = True - continue - - if foundSoftware: - softwareChecks.append(line) - - checks.close() - return softwareChecks diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py b/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py deleted file mode 100755 index 82c5e5075..000000000 --- a/mil_common/utils/mil_tools/scripts/preflight/preflightUI.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python3 -import blessed - - -def main(): - inp = "" - term = blessed.Terminal() - pos = 0 - - # TESTING VARS BEFORE REAL FUNCTIONS WORK - hwtest = [ - "test 1", - "test 2", - "test 3", - "test 4", - "test 5", - "test 6", - "test 7", - "test 8", - "test 9", - "test 10", - "test 11", - ] - - # ================ - - machine = ["SubjuGator", "NaviGator", "Exit"] - options = [ - "Hardware Checklist", - "Software Checklist", - "Rosnode Command", - "Add Software Test", - "Remove Software Test", - "Back", - "Exit", - ] - currMenu = machine - - hardwarePass = False - softwarePass = False - - while inp != "q": - maxPos = len(currMenu) - # reprint line selected -> term.on_green"message" - print(term.home + term.clear + term.center("Preflight Checklist\n")) - - for x in range(0, maxPos): - if x == pos: - print(term.blink + term.center(term.on_yellow(currMenu[x]))) - else: - if currMenu == options: - # if menu is options, set hardware/software to red or green depending on if it's completed - if x == 0: - # pass - print( - term.center(term.on_green(currMenu[x])) - if hardwarePass - else term.center(term.on_red(currMenu[x])), - ) - elif x == 1: - print( - term.center(term.on_green(currMenu[x])) - if softwarePass - else term.center(term.on_red(currMenu[x])), - ) - else: - print(term.center(currMenu[x])) - - else: - print(term.center(currMenu[x])) - - with term.cbreak(), term.hidden_cursor(): - inp = term.inkey() - if inp == "k" or inp.name == "KEY_UP": - if pos == 0: - pos = maxPos - 1 - else: - pos -= 1 - - if inp == "j" or inp.name == "KEY_DOWN": - if pos == maxPos - 1: - pos = 0 - else: - pos += 1 - if inp.name == "KEY_ENTER" or inp == " ": - # if selection is exit - if pos == maxPos - 1: - inp = "q" - continue - # if in first screen go to second - if currMenu == machine: - currMenu = options - machine[pos] - # if in second menu - elif currMenu == options: - # Hardware Check - if pos == 0: - hardware_test(term, hwtest) - # Software Check - if pos == 1: - software_test(term) - # ROSnode command - if pos == 2: - run_command(term) - # add test to the checklist - if pos == 3: - write_test(term) - # if back selected - if pos == 5: - currMenu = machine - pos = 0 - else: - pass - - -def hardware_test(term, hwtest): - inp = "" - while inp != "q": - print(term.clear + term.center("Hardware Tests\n")) - for x in hwtest: - print(term.on_red(x)) - - with term.cbreak(), term.hidden_cursor(): - inp = term.inkey() - - -def software_test(term): - # this should run ros and do all the init tests - pass - - -def run_command(term): - pass - - -def write_test(term): - pass - - -def delete_test(term): - pass - - -if __name__ == "__main__": - main() diff --git a/requirements.txt b/requirements.txt index eefa4a3e7..1a77082c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -32,7 +32,8 @@ myst-parser==0.18.0 sphinx-copybutton==0.5.0 # Terminal -blessed==1.20.0 +typer[all]==4.8.0 +PyInquirer==1.0.3 # External Devices pyserial==3.5 From 93fd1c68cc4c2e759383b8b5a33ca5cc49b3551d Mon Sep 17 00:00:00 2001 From: keithmk Date: Mon, 29 Jan 2024 14:24:42 -0500 Subject: [PATCH 12/26] converted to typer, for a more cli solution --- .../scripts/preflight/Tests/RunTests.py | 11 + .../scripts/preflight/Tests/TestLib.py | 93 +++++++ scripts/SubChecklist.txt | 2 + services.txt | 165 ++++++++++++ topics.txt | 254 ++++++++++++++++++ 5 files changed, 525 insertions(+) create mode 100644 mil_common/utils/mil_tools/scripts/preflight/Tests/RunTests.py create mode 100644 mil_common/utils/mil_tools/scripts/preflight/Tests/TestLib.py create mode 100644 scripts/SubChecklist.txt create mode 100644 services.txt create mode 100644 topics.txt diff --git a/mil_common/utils/mil_tools/scripts/preflight/Tests/RunTests.py b/mil_common/utils/mil_tools/scripts/preflight/Tests/RunTests.py new file mode 100644 index 000000000..54d2940d4 --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/preflight/Tests/RunTests.py @@ -0,0 +1,11 @@ +import importlib + + +def getHardWareCheckist(robotName): + robotName += ".hardware" + module = importlib.import_module(robotName) + + if hasattr(module, "hardwareTests"): + return module.hardwareTests + else: + return [] diff --git a/mil_common/utils/mil_tools/scripts/preflight/Tests/TestLib.py b/mil_common/utils/mil_tools/scripts/preflight/Tests/TestLib.py new file mode 100644 index 000000000..4670e8781 --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/preflight/Tests/TestLib.py @@ -0,0 +1,93 @@ +import rospy +import rosservice +import rostopic + + +class Test: + # Constructor + def __init__(self, name, description, communicationType, address): + self.name = name + self.description = description + self.communicationType = communicationType + self.address = address + self.needsHumanAuthorization = False + + # Check if the communication interface is up and running + def isActive(self): + # Check if the topic is up + if self.communicationType == "Topic": + topicType, topicStr, _ = rostopic.get_topic_class( + self.address, + ) # get topic class + try: + rospy.wait_for_message( + topicStr, + topicType, + ) # try to get a message from that topic + return True + except Exception: + return False + + # Check if the service is up + if self.communicationType == "Service": + return rosservice.waitForService( + self.address, + ) # Wait for the service to be up + + # Check if the action server is up + if self.communicationType == "Action": + # action client + topicType, topicStr, _ = rostopic.get_topic_class( + self.address + "/feedback", + ) + try: + # Wait for a message from the topic + rospy.wait_for_message(topicStr, topicType) + return True + except Exception: + return False + + # Send data over the communication interface and pass in the return values into the check function + def VerifyData(self, args, checkFunction): + result = "" + + if self.communicationType == "Topic": + # Get the class of the topic + topicType, topicStr, _ = rostopic.get_topic_class(self.address) + try: + # Get a message from the topic + result = rospy.wait_for_message(topicStr, topicType) + except Exception: + return False + + if self.communicationType == "Service": + try: + # Get a message form the service + result = rosservice.call_service(self.address, args) + except Exception: + return False + + if self.communicationType == "Action": + # Get the class of the topic, remember an action will publish its results to a topic with /goal at the end + topicType, topicStr, _ = rostopic.get_topic_class( + self.address + "/feedback", + ) + try: + # Wait for a message from the topic + result = rospy.wait_for_message(topicStr, topicType) + except Exception: + return False + + return checkFunction(args, result) + + def runCommand(self, args): + # use a dictionary + if self.communicationType == "Topic": + topicType, topicStr, _ = rostopic.get_topic_class(self.address) + if self.communicationType == "Service": + # Do something + self + if self.communicationType == "Action": + # Do something + self + return False diff --git a/scripts/SubChecklist.txt b/scripts/SubChecklist.txt new file mode 100644 index 000000000..2d9664d4a --- /dev/null +++ b/scripts/SubChecklist.txt @@ -0,0 +1,2 @@ +dvl +odom diff --git a/services.txt b/services.txt new file mode 100644 index 000000000..ff8f96b88 --- /dev/null +++ b/services.txt @@ -0,0 +1,165 @@ +/adaptive_controller/get_loggers +/adaptive_controller/set_logger_level +/adaptive_controller/set_parameters +/alarm/get +/alarm/set +/alarm_sever/get_loggers +/alarm_sever/set_logger_level +/b_matrix +/c3_trajectory_generator/get_loggers +/c3_trajectory_generator/set_logger_level +/camera/down/down_image_proc/get_loggers +/camera/down/down_image_proc/set_logger_level +/camera/down/down_image_proc_debayer/set_parameters +/camera/down/down_image_proc_rectify_color/set_parameters +/camera/down/down_image_proc_rectify_mono/set_parameters +/camera/down/image_color/compressed/set_parameters +/camera/down/image_color/compressedDepth/set_parameters +/camera/down/image_color/theora/set_parameters +/camera/down/image_mono/compressed/set_parameters +/camera/down/image_mono/compressedDepth/set_parameters +/camera/down/image_mono/theora/set_parameters +/camera/down/image_raw/compressed/set_parameters +/camera/down/image_raw/compressedDepth/set_parameters +/camera/down/image_raw/theora/set_parameters +/camera/down/image_rect/compressed/set_parameters +/camera/down/image_rect/compressedDepth/set_parameters +/camera/down/image_rect/theora/set_parameters +/camera/down/image_rect_color/compressed/set_parameters +/camera/down/image_rect_color/compressedDepth/set_parameters +/camera/down/image_rect_color/theora/set_parameters +/camera/down/set_camera_info +/camera/down/set_parameters +/camera/front/camera_nodelet_manager/get_loggers +/camera/front/camera_nodelet_manager/list +/camera/front/camera_nodelet_manager/load_nodelet +/camera/front/camera_nodelet_manager/set_logger_level +/camera/front/camera_nodelet_manager/unload_nodelet +/camera/front/left/image_color/compressed/set_parameters +/camera/front/left/image_color/compressedDepth/set_parameters +/camera/front/left/image_color/theora/set_parameters +/camera/front/left/image_mono/compressed/set_parameters +/camera/front/left/image_mono/compressedDepth/set_parameters +/camera/front/left/image_mono/theora/set_parameters +/camera/front/left/image_raw/compressed/set_parameters +/camera/front/left/image_raw/compressedDepth/set_parameters +/camera/front/left/image_raw/theora/set_parameters +/camera/front/left/image_rect/compressed/set_parameters +/camera/front/left/image_rect/compressedDepth/set_parameters +/camera/front/left/image_rect/theora/set_parameters +/camera/front/left/image_rect_color/compressed/set_parameters +/camera/front/left/image_rect_color/compressedDepth/set_parameters +/camera/front/left/image_rect_color/theora/set_parameters +/camera/front/left/seecam_image_proc/get_loggers +/camera/front/left/seecam_image_proc/set_logger_level +/camera/front/left/seecam_image_proc_debayer/set_parameters +/camera/front/left/seecam_image_proc_rectify_color/set_parameters +/camera/front/left/seecam_image_proc_rectify_mono/set_parameters +/camera/front/left/set_camera_info +/camera/front/left/set_parameters +/camera/front/right/image_color/compressed/set_parameters +/camera/front/right/image_color/compressedDepth/set_parameters +/camera/front/right/image_color/theora/set_parameters +/camera/front/right/image_mono/compressed/set_parameters +/camera/front/right/image_mono/compressedDepth/set_parameters +/camera/front/right/image_mono/theora/set_parameters +/camera/front/right/image_raw/compressed/set_parameters +/camera/front/right/image_raw/compressedDepth/set_parameters +/camera/front/right/image_raw/theora/set_parameters +/camera/front/right/image_rect/compressed/set_parameters +/camera/front/right/image_rect/compressedDepth/set_parameters +/camera/front/right/image_rect/theora/set_parameters +/camera/front/right/image_rect_color/compressed/set_parameters +/camera/front/right/image_rect_color/compressedDepth/set_parameters +/camera/front/right/image_rect_color/theora/set_parameters +/camera/front/right/set_camera_info +/camera/front/right/set_parameters +/camera/front/right_image_proc_debayer/get_loggers +/camera/front/right_image_proc_debayer/set_logger_level +/camera/front/right_image_proc_debayer/set_parameters +/camera/front/right_image_proc_rect/get_loggers +/camera/front/right_image_proc_rect/set_logger_level +/camera/front/right_image_proc_rect/set_parameters +/camera/front/right_image_proc_rect_color/get_loggers +/camera/front/right_image_proc_rect_color/set_logger_level +/camera/front/right_image_proc_rect_color/set_parameters +/gazebo/apply_body_wrench +/gazebo/apply_joint_effort +/gazebo/clear_body_wrenches +/gazebo/clear_joint_forces +/gazebo/delete_light +/gazebo/delete_model +/gazebo/get_joint_properties +/gazebo/get_light_properties +/gazebo/get_link_properties +/gazebo/get_link_state +/gazebo/get_loggers +/gazebo/get_model_properties +/gazebo/get_model_state +/gazebo/get_physics_properties +/gazebo/get_world_properties +/gazebo/pause_physics +/gazebo/reset_simulation +/gazebo/reset_world +/gazebo/set_joint_properties +/gazebo/set_light_properties +/gazebo/set_link_properties +/gazebo/set_link_state +/gazebo/set_logger_level +/gazebo/set_model_configuration +/gazebo/set_model_state +/gazebo/set_parameters +/gazebo/set_physics_properties +/gazebo/spawn_sdf_model +/gazebo/spawn_urdf_model +/gazebo/unpause_physics +/hydrophones/hydrophones_visualization/get_loggers +/hydrophones/hydrophones_visualization/set_logger_level +/hydrophones/ping_locator/cross_correlation_debug_enable +/hydrophones/ping_locator/enable +/hydrophones/ping_locator/get_loggers +/hydrophones/ping_locator/samples_debug_enable +/hydrophones/ping_locator/set_logger_level +/hydrophones/triggering/enable +/hydrophones/triggering/filter_debug_enable +/hydrophones/triggering/filter_debug_trigger +/hydrophones/triggering/get_loggers +/hydrophones/triggering/reset +/hydrophones/triggering/sample_at_trigger_debug_enable +/hydrophones/triggering/set_logger_level +/hydrophones/triggering/trigger_debug_enable +/magnetometer_vis/get_loggers +/magnetometer_vis/set_logger_level +/mission_runner/get_loggers +/mission_runner/refresh_missions +/mission_runner/set_logger_level +/odom_estimator/get_loggers +/odom_estimator/set_ignore_magnetometer +/odom_estimator/set_logger_level +/odometry_to_tf/get_loggers +/odometry_to_tf/set_logger_level +/poi_server/add +/poi_server/delete +/poi_server/get_loggers +/poi_server/move +/poi_server/save_to_param +/poi_server/set_logger_level +/poi_server/tf2_frames +/robot_state_publisher/get_loggers +/robot_state_publisher/set_logger_level +/rosout/get_loggers +/rosout/set_logger_level +/set_mobo_kill +/set_valve +/simulate_go +/simulate_hard_kill +/simulate_soft_kill +/tf_republisher/get_loggers +/tf_republisher/set_logger_level +/thruster_mapper/get_loggers +/thruster_mapper/set_logger_level +/transform_odometry/get_loggers +/transform_odometry/set_logger_level +/update_thruster_layout +/usb_to_can_driver/get_loggers +/usb_to_can_driver/set_logger_level diff --git a/topics.txt b/topics.txt new file mode 100644 index 000000000..d85bb2a17 --- /dev/null +++ b/topics.txt @@ -0,0 +1,254 @@ +/absodom +/adaptive_controller/adaptation +/adaptive_controller/dist +/adaptive_controller/drag +/adaptive_controller/parameter_descriptions +/adaptive_controller/parameter_updates +/adaptive_controller/pose_error +/adaptive_controller/twist_error +/alarm/updates +/c3_trajectory_generator/sub_ogrid +/c3_trajectory_generator/trajectory_v +/c3_trajectory_generator/waypoint +/c3_trajectory_generator/waypoint_ogrid +/camera/down/camera_info +/camera/down/down_image_proc_debayer/parameter_descriptions +/camera/down/down_image_proc_debayer/parameter_updates +/camera/down/down_image_proc_rectify_color/parameter_descriptions +/camera/down/down_image_proc_rectify_color/parameter_updates +/camera/down/down_image_proc_rectify_mono/parameter_descriptions +/camera/down/down_image_proc_rectify_mono/parameter_updates +/camera/down/image_color +/camera/down/image_color/compressed +/camera/down/image_color/compressed/parameter_descriptions +/camera/down/image_color/compressed/parameter_updates +/camera/down/image_color/compressedDepth +/camera/down/image_color/compressedDepth/parameter_descriptions +/camera/down/image_color/compressedDepth/parameter_updates +/camera/down/image_color/theora +/camera/down/image_color/theora/parameter_descriptions +/camera/down/image_color/theora/parameter_updates +/camera/down/image_mono +/camera/down/image_mono/compressed +/camera/down/image_mono/compressed/parameter_descriptions +/camera/down/image_mono/compressed/parameter_updates +/camera/down/image_mono/compressedDepth +/camera/down/image_mono/compressedDepth/parameter_descriptions +/camera/down/image_mono/compressedDepth/parameter_updates +/camera/down/image_mono/theora +/camera/down/image_mono/theora/parameter_descriptions +/camera/down/image_mono/theora/parameter_updates +/camera/down/image_raw +/camera/down/image_raw/compressed +/camera/down/image_raw/compressed/parameter_descriptions +/camera/down/image_raw/compressed/parameter_updates +/camera/down/image_raw/compressedDepth +/camera/down/image_raw/compressedDepth/parameter_descriptions +/camera/down/image_raw/compressedDepth/parameter_updates +/camera/down/image_raw/theora +/camera/down/image_raw/theora/parameter_descriptions +/camera/down/image_raw/theora/parameter_updates +/camera/down/image_rect +/camera/down/image_rect/compressed +/camera/down/image_rect/compressed/parameter_descriptions +/camera/down/image_rect/compressed/parameter_updates +/camera/down/image_rect/compressedDepth +/camera/down/image_rect/compressedDepth/parameter_descriptions +/camera/down/image_rect/compressedDepth/parameter_updates +/camera/down/image_rect/theora +/camera/down/image_rect/theora/parameter_descriptions +/camera/down/image_rect/theora/parameter_updates +/camera/down/image_rect_color +/camera/down/image_rect_color/compressed +/camera/down/image_rect_color/compressed/parameter_descriptions +/camera/down/image_rect_color/compressed/parameter_updates +/camera/down/image_rect_color/compressedDepth +/camera/down/image_rect_color/compressedDepth/parameter_descriptions +/camera/down/image_rect_color/compressedDepth/parameter_updates +/camera/down/image_rect_color/theora +/camera/down/image_rect_color/theora/parameter_descriptions +/camera/down/image_rect_color/theora/parameter_updates +/camera/down/parameter_descriptions +/camera/down/parameter_updates +/camera/front/camera_nodelet_manager/bond +/camera/front/left/camera_info +/camera/front/left/image_color +/camera/front/left/image_color/compressed +/camera/front/left/image_color/compressed/parameter_descriptions +/camera/front/left/image_color/compressed/parameter_updates +/camera/front/left/image_color/compressedDepth +/camera/front/left/image_color/compressedDepth/parameter_descriptions +/camera/front/left/image_color/compressedDepth/parameter_updates +/camera/front/left/image_color/theora +/camera/front/left/image_color/theora/parameter_descriptions +/camera/front/left/image_color/theora/parameter_updates +/camera/front/left/image_mono +/camera/front/left/image_mono/compressed +/camera/front/left/image_mono/compressed/parameter_descriptions +/camera/front/left/image_mono/compressed/parameter_updates +/camera/front/left/image_mono/compressedDepth +/camera/front/left/image_mono/compressedDepth/parameter_descriptions +/camera/front/left/image_mono/compressedDepth/parameter_updates +/camera/front/left/image_mono/theora +/camera/front/left/image_mono/theora/parameter_descriptions +/camera/front/left/image_mono/theora/parameter_updates +/camera/front/left/image_raw +/camera/front/left/image_raw/compressed +/camera/front/left/image_raw/compressed/parameter_descriptions +/camera/front/left/image_raw/compressed/parameter_updates +/camera/front/left/image_raw/compressedDepth +/camera/front/left/image_raw/compressedDepth/parameter_descriptions +/camera/front/left/image_raw/compressedDepth/parameter_updates +/camera/front/left/image_raw/theora +/camera/front/left/image_raw/theora/parameter_descriptions +/camera/front/left/image_raw/theora/parameter_updates +/camera/front/left/image_rect +/camera/front/left/image_rect/compressed +/camera/front/left/image_rect/compressed/parameter_descriptions +/camera/front/left/image_rect/compressed/parameter_updates +/camera/front/left/image_rect/compressedDepth +/camera/front/left/image_rect/compressedDepth/parameter_descriptions +/camera/front/left/image_rect/compressedDepth/parameter_updates +/camera/front/left/image_rect/theora +/camera/front/left/image_rect/theora/parameter_descriptions +/camera/front/left/image_rect/theora/parameter_updates +/camera/front/left/image_rect_color +/camera/front/left/image_rect_color/compressed +/camera/front/left/image_rect_color/compressed/parameter_descriptions +/camera/front/left/image_rect_color/compressed/parameter_updates +/camera/front/left/image_rect_color/compressedDepth +/camera/front/left/image_rect_color/compressedDepth/parameter_descriptions +/camera/front/left/image_rect_color/compressedDepth/parameter_updates +/camera/front/left/image_rect_color/theora +/camera/front/left/image_rect_color/theora/parameter_descriptions +/camera/front/left/image_rect_color/theora/parameter_updates +/camera/front/left/parameter_descriptions +/camera/front/left/parameter_updates +/camera/front/left/seecam_image_proc_debayer/parameter_descriptions +/camera/front/left/seecam_image_proc_debayer/parameter_updates +/camera/front/left/seecam_image_proc_rectify_color/parameter_descriptions +/camera/front/left/seecam_image_proc_rectify_color/parameter_updates +/camera/front/left/seecam_image_proc_rectify_mono/parameter_descriptions +/camera/front/left/seecam_image_proc_rectify_mono/parameter_updates +/camera/front/right/camera_info +/camera/front/right/image_color +/camera/front/right/image_color/compressed +/camera/front/right/image_color/compressed/parameter_descriptions +/camera/front/right/image_color/compressed/parameter_updates +/camera/front/right/image_color/compressedDepth +/camera/front/right/image_color/compressedDepth/parameter_descriptions +/camera/front/right/image_color/compressedDepth/parameter_updates +/camera/front/right/image_color/theora +/camera/front/right/image_color/theora/parameter_descriptions +/camera/front/right/image_color/theora/parameter_updates +/camera/front/right/image_mono +/camera/front/right/image_mono/compressed +/camera/front/right/image_mono/compressed/parameter_descriptions +/camera/front/right/image_mono/compressed/parameter_updates +/camera/front/right/image_mono/compressedDepth +/camera/front/right/image_mono/compressedDepth/parameter_descriptions +/camera/front/right/image_mono/compressedDepth/parameter_updates +/camera/front/right/image_mono/theora +/camera/front/right/image_mono/theora/parameter_descriptions +/camera/front/right/image_mono/theora/parameter_updates +/camera/front/right/image_raw +/camera/front/right/image_raw/compressed +/camera/front/right/image_raw/compressed/parameter_descriptions +/camera/front/right/image_raw/compressed/parameter_updates +/camera/front/right/image_raw/compressedDepth +/camera/front/right/image_raw/compressedDepth/parameter_descriptions +/camera/front/right/image_raw/compressedDepth/parameter_updates +/camera/front/right/image_raw/theora +/camera/front/right/image_raw/theora/parameter_descriptions +/camera/front/right/image_raw/theora/parameter_updates +/camera/front/right/image_rect +/camera/front/right/image_rect/compressed +/camera/front/right/image_rect/compressed/parameter_descriptions +/camera/front/right/image_rect/compressed/parameter_updates +/camera/front/right/image_rect/compressedDepth +/camera/front/right/image_rect/compressedDepth/parameter_descriptions +/camera/front/right/image_rect/compressedDepth/parameter_updates +/camera/front/right/image_rect/theora +/camera/front/right/image_rect/theora/parameter_descriptions +/camera/front/right/image_rect/theora/parameter_updates +/camera/front/right/image_rect_color +/camera/front/right/image_rect_color/compressed +/camera/front/right/image_rect_color/compressed/parameter_descriptions +/camera/front/right/image_rect_color/compressed/parameter_updates +/camera/front/right/image_rect_color/compressedDepth +/camera/front/right/image_rect_color/compressedDepth/parameter_descriptions +/camera/front/right/image_rect_color/compressedDepth/parameter_updates +/camera/front/right/image_rect_color/theora +/camera/front/right/image_rect_color/theora/parameter_descriptions +/camera/front/right/image_rect_color/theora/parameter_updates +/camera/front/right/parameter_descriptions +/camera/front/right/parameter_updates +/camera/front/right_image_proc_debayer/parameter_descriptions +/camera/front/right_image_proc_debayer/parameter_updates +/camera/front/right_image_proc_rect/parameter_descriptions +/camera/front/right_image_proc_rect/parameter_updates +/camera/front/right_image_proc_rect_color/parameter_descriptions +/camera/front/right_image_proc_rect_color/parameter_updates +/clock +/contact_bumper +/depth +/dvl +/dvl/range +/gazebo/link_states +/gazebo/model_states +/gazebo/parameter_descriptions +/gazebo/parameter_updates +/gazebo/performance_metrics +/gazebo/set_link_state +/gazebo/set_model_state +/hydrophones/direction +/hydrophones/direction_marker +/hydrophones/ping_locator/cross_correlation_debug +/hydrophones/ping_locator/samples_debug +/hydrophones/pings +/hydrophones/processed +/hydrophones/samples +/hydrophones/triggering/filter_debug +/hydrophones/triggering/sample_at_trigger_debug +/hydrophones/triggering/trigger_debug +/hydrophones/visualization +/imu/data_raw +/imu/inclinometer +/imu/mag +/imu/marker +/imu_odom +/joint_states +/mission/cancel +/mission/feedback +/mission/goal +/mission/result +/mission/status +/moveto/cancel +/moveto/feedback +/moveto/goal +/moveto/result +/moveto/status +/network +/odom +/odom_estimator/info +/ogrid_pointcloud/ogrid +/online_bagger/bag/cancel +/online_bagger/bag/feedback +/online_bagger/bag/goal +/online_bagger/bag/result +/online_bagger/bag/status +/points_of_interest +/points_of_interest/feedback +/points_of_interest/update +/points_of_interest/update_full +/rosout +/rosout_agg +/tf +/tf_static +/thrusters/thrust +/trajectory +/visualization +/wrench +/wrench_actual +/wrench_error +/yolov7/detections From 99a7aa60398050f00e3c49aa105c660b15d4dccd Mon Sep 17 00:00:00 2001 From: keithmk Date: Fri, 2 Feb 2024 14:50:27 -0500 Subject: [PATCH 13/26] Created Program flow and menus --- .../mil_tools/scripts/preflight/preflight.py | 71 +++++++++++++------ .../scripts/preflight/preflight_menus.py | 42 +++++++++++ 2 files changed, 91 insertions(+), 22 deletions(-) create mode 100644 mil_common/utils/mil_tools/scripts/preflight/preflight_menus.py diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflight.py b/mil_common/utils/mil_tools/scripts/preflight/preflight.py index f49cc02f6..ba1fef7ce 100644 --- a/mil_common/utils/mil_tools/scripts/preflight/preflight.py +++ b/mil_common/utils/mil_tools/scripts/preflight/preflight.py @@ -1,10 +1,12 @@ import subprocess +import preflight_menus import rosnode import rospy import rostopic import typer from PyInquirer import prompt +from rich.progress import track app = typer.Typer() @@ -12,7 +14,7 @@ { "type": "checkbox", "message": "Hardware Checklist:", - "name": "HardwareTests", + "name": "HardwareTests: \nPlease check that all of the following are in working order. \nYou cannot continue until everything has been checked.", "choices": [ {"name": "check thing 1"}, {"name": "check thing 2"}, @@ -22,7 +24,7 @@ ], }, ] -mechanicalChecklist = [ +actuatorChecklist = [ { "type": "list", "message": "Select which system you want to run. BE CAREFUL make sure everyone's fingures are secured.", @@ -43,24 +45,50 @@ nodes = ["/odom_estimator"] -run = ["/thrusters/thrust"] +actuatorsList = ["/thrusters/thrust"] @app.command("Start") def main(): + # Display Modes/Options + subprocess.run("clear", shell=True) + mode = preflight_menus.display_start_menu() + + if mode == "Run Preflight Full Test": + hardware() + software() + actuators() + + # Complete the actuator tests + subprocess.run("clear", shell=True) + + +def hardware(): + # Complete the hardware tests subprocess.run("clear", shell=True) answers = prompt(hardwareChecklist) - while len(answers["HardwareTests"]) != 5: + while len(next(iter(answers.values()))) != 5: subprocess.run("clear", shell=True) answers = prompt(hardwareChecklist) - print(answers) -@app.command("Topic") -def topic(): +def software(): + # Complete the software tests + subprocess.run("clear", shell=True) rospy.init_node("preflight") + + # Check Nodes answers = [] - for topic in topics: + for node in track(nodes, description="Checking Nodes..."): + try: + answers.append({node: rosnode.rosnode_ping(node, 5)}) + except Exception: + answers.append({node: False}) + print(answers) + + # Check Topics + answers = [] + for topic in track(topics, description="Checking Topics..."): try: topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class rospy.wait_for_message( @@ -73,22 +101,21 @@ def topic(): answers.append({topic: False}) print(answers) - -@app.command("Node") -def node(): - rospy.init_node("preflight") - answers = [] - for node in nodes: - try: - answers.append({node: rosnode.rosnode_ping(node, 5)}) - except Exception: - answers.append({node: False}) - print(answers) + print( + prompt( + [ + { + "type": "confirm", + "name": "continue", + "message": "Continue?", + }, + ], + ), + ) -@app.command("Run") -def Run(): - rospy.init_node("preflight") +def actuators(): + subprocess.run("clear", shell=True) if __name__ == "__main__": diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflight_menus.py b/mil_common/utils/mil_tools/scripts/preflight/preflight_menus.py new file mode 100644 index 000000000..db5be62d2 --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/preflight/preflight_menus.py @@ -0,0 +1,42 @@ +from PyInquirer import prompt +from rich.console import Console + + +def display_start_menu(): + console = Console() + + # Title + console.print( + "[bold green]Preflight Program - Autonomous Robot Verification[/bold green]\n", + ) + + # Description + console.print( + "Welcome to the Preflight Program, a tool inspired by the preflight checklists used by pilots before " + "flying a plane. This program is designed to verify the functionality of all software and hardware " + "systems on your autonomous robot. It ensures that everything is in working order, allowing you to " + "safely deploy your robot with confidence.\n", + ) + + # Authors section + console.print("\n[italic]Authors:[/italic]") + console.print("Keith Khadar") + console.print("Anthony Liao") + console.print("Joshua Thomas\n") + + # Menu options + start_menu = [ + { + "type": "list", + "name": "mode selection", + "message": "Menu", + "choices": [ + "Run Preflight Full Test", + "View Report", + "Run Specific Test", + "View Documentation", + ], + }, + ] + option = prompt(start_menu) + return next(iter(option.values())) From 2d0956b74667247f7cd582fc7e760e146d88aae5 Mon Sep 17 00:00:00 2001 From: Anthony Liao Date: Tue, 6 Feb 2024 15:13:59 -0500 Subject: [PATCH 14/26] reorganized preflight for pip package --- .../mil-preflight/mil_preflight/__init__.py | 0 .../mil-preflight/mil_preflight/main.py | 207 ++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/mil_preflight/__init__.py create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/mil_preflight/main.py diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/mil_preflight/__init__.py b/mil_common/utils/mil_tools/scripts/mil-preflight/mil_preflight/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/mil_preflight/main.py b/mil_common/utils/mil_tools/scripts/mil-preflight/mil_preflight/main.py new file mode 100644 index 000000000..d33e751a8 --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/mil_preflight/main.py @@ -0,0 +1,207 @@ +import subprocess + +import rosnode +import rospy +import rostopic +import typer +from PyInquirer import prompt +from rich.console import Console +from rich.progress import track + +app = typer.Typer() + + +def display_start_menu(): + console = Console() + + # Title + console.print( + "[bold green]Preflight Program - Autonomous Robot Verification[/bold green]", + ) + + # Description + console.print( + "Welcome to the Preflight Program, a tool inspired by the preflight checklists used by pilots before " + "flying a plane. This program is designed to verify the functionality of all software and hardware " + "systems on your autonomous robot. It ensures that everything is in working order, allowing you to " + "safely deploy your robot with confidence.\n", + ) + + # Authors section + console.print("\n[italic]Authors:[/italic]") + console.print("Keith Khadar") + console.print("Anthony Liao") + console.print("Joshua Thomas\n") + + # Menu options + start_menu = [ + { + "type": "list", + "name": "mode selection", + "message": "Menu", + "choices": [ + "Run Preflight Full Test", + "View Report", + "Run Specific Test", + "View Documentation", + "Exit", + ], + }, + ] + option = prompt(start_menu) + return next(iter(option.values())) + + +hardwareChecklist = [ + { + "type": "checkbox", + "message": "Hardware Checklist:", + "name": "HardwareTests: \nPlease check that all of the following are in working order. \nYou cannot continue until everything has been checked.", + "choices": [ + {"name": "check thing 1"}, + {"name": "check thing 2"}, + {"name": "check thing 3"}, + {"name": "check thing 4"}, + {"name": "check thing 5"}, + ], + }, +] + +topics = [ + "/camera/front/right/image_raw", + "/camera/down/image_raw", + "/camera/front/left/image_raw", + "/dvl", + "/depth", + "/imu/data_raw", + "/imu/mag", +] + +nodes = ["/odom_estimator"] + +actuatorsList = {"/thrusters/thrust": ["FLH", 25.0]} + + +@app.command("Start") +def main(): + # Display Modes/Options + subprocess.run("clear", shell=True) + mode = display_start_menu() + + if mode == "Run Preflight Full Test": + hardware() + software() + actuators() + if mode == "Exit": + subprocess.run("clear", shell=True) + return + main() + + +def hardware(): + # Complete the hardware tests + subprocess.run("clear", shell=True) + answers = prompt(hardwareChecklist) + while len(next(iter(answers.values()))) != 5: + subprocess.run("clear", shell=True) + answers = prompt(hardwareChecklist) + + +def software(): + # Complete the software tests + subprocess.run("clear", shell=True) + rospy.init_node("preflight") + + # Check Nodes + answers = [] + for node in track(nodes, description="Checking Nodes..."): + try: + answers.append({node: rosnode.rosnode_ping(node, 5)}) + except Exception: + answers.append({node: False}) + print(answers) + + # Check Topics + answers = [] + for topic in track(topics, description="Checking Topics..."): + try: + topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class + rospy.wait_for_message( + topicStr, + topicType, + 5, + ) # try to get a message from that topic + answers.append({topic: True}) + except Exception: + answers.append({topic: False}) + print(answers) + + print( + prompt( + [ + { + "type": "confirm", + "name": "continue", + "message": "Continue?", + }, + ], + ), + ) + + +def actuators(): + subprocess.run("clear", shell=True) + print("test") + answers = [] + try: + prompt( + [ + { + "type": "confirm", + "name": "runActuator", + "message": "Are your sure you want to run " + + actuatorsList.keys[0] + + "? BE CAREFUL make sure everyone's fingures are secured.", + }, + ], + ) + topicType, topicStr, _ = rostopic.get_topic_class( + actuatorsList.keys[0], + ) # get topic class + pub = rospy.Publisher(topicStr, topicType, queue_size=10) + rostopic.publish_message(pub, topicType, actuatorsList.values[0]) + + answers.append( + prompt( + [ + { + "type": "confirm", + "name": "worked?", + "message": "Did " + + actuatorsList.keys[0] + + " work as expected?", + }, + ], + ), + ) + except Exception as e: + print(e) + answers.append(False) + + print(answers) + + print( + prompt( + [ + { + "type": "confirm", + "name": "continue", + "message": "Continue?", + }, + ], + ), + ) + + +if __name__ == "__main__": + app() From 871984e2bd9353c34b50fa96d01d2c60423a5dbd Mon Sep 17 00:00:00 2001 From: Anthony Liao Date: Tue, 6 Feb 2024 15:17:48 -0500 Subject: [PATCH 15/26] reorganized preflight package --- .../mil_tools/scripts/mil-preflight/README.md | 1 + .../dist/mil_preflight-0.1.2-py3-none-any.whl | Bin 0 -> 3168 bytes .../dist/mil_preflight-0.1.2.tar.gz | Bin 0 -> 2409 bytes .../old-code}/RunTests.py | 0 .../old-code}/TestLib.py | 0 .../scripts/mil-preflight/poetry.lock | 146 ++++++++++++++++++ .../scripts/mil-preflight/pyproject.toml | 17 ++ .../scripts/mil-preflight/tests/__init__.py | 0 .../mil_tools/scripts/preflight/preflight.py | 122 --------------- .../scripts/preflight/preflight_menus.py | 42 ----- preflight-test/bin/python | 1 + preflight-test/bin/python3 | 1 + preflight-test/lib64 | 1 + preflight-test/pyvenv.cfg | 3 + requirements.txt | 1 + 15 files changed, 171 insertions(+), 164 deletions(-) create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/README.md create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2-py3-none-any.whl create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2.tar.gz rename mil_common/utils/mil_tools/scripts/{preflight/Tests => mil-preflight/old-code}/RunTests.py (100%) rename mil_common/utils/mil_tools/scripts/{preflight/Tests => mil-preflight/old-code}/TestLib.py (100%) create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/poetry.lock create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/pyproject.toml create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/tests/__init__.py delete mode 100644 mil_common/utils/mil_tools/scripts/preflight/preflight.py delete mode 100644 mil_common/utils/mil_tools/scripts/preflight/preflight_menus.py create mode 120000 preflight-test/bin/python create mode 120000 preflight-test/bin/python3 create mode 120000 preflight-test/lib64 create mode 100644 preflight-test/pyvenv.cfg diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/README.md b/mil_common/utils/mil_tools/scripts/mil-preflight/README.md new file mode 100644 index 000000000..88a138a4c --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/README.md @@ -0,0 +1 @@ +#Preflight diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2-py3-none-any.whl b/mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..0689d158c314c2caded2c9c7f01d8adf7d532dbd GIT binary patch literal 3168 zcmai$cT`i^7KcMGMx@CgAXN|ogb)I#G{Mjby|q*KlXR_+UM-Ef9A#vjJyBFh3Hgejc%I%nShN(paaz3-rJ0 zjiLq3+fAUyRXA_#A_InmecW?MLEXu8dEJAIpB|#L9|rN0Ea&*H$I1myjDwUGXD@GV;66$sOkyhjxv^&uxSnN{%u*l3QBp!kmhKH}`XCss-v-+12^v=gvV2HI9rUg_UWhk<5KQacp%C2V;s*I%`s z_^Ot3M~@A8Mcf2m1%hUH3(h-d%yvdFQhed^0y4Nb)+s`KrF2buTrit=`yYV?FBtoE zzzTgZq}L3n7Ne(EEff_;7zC9B+6Y{*ll34oj9!z!<{5vl+hGmY4+?KXl<8^D7DIT5=F9YVvXz0_9cms2bj_}q@cTZ2C(yfHfwg-&4}E0%9@r!&}`q8%B!p%5Q`Rp7i* z*5xkT44;NaAv9xwIW5j8UBG@p9}xv4r!avLi4D;{{9to04=X5F3KzGE5pu|ADQ-ok z#759DPaRrSap!rcEtx6F#Ktw(ieB)lRp2+rbIxzo_oZV?)ZV>ipM3=KZ&{~AhcJoE zTiQ28MmQ+-J*W<2aM#34%b%}BTV+5rdIF>^el44}hA8)JG(x>QA$lM$W+LijR07+n zF3AT0PA+HNW)z%?NOj0wU2B6sgy_4{Kd{InUXTU?;Q$=`qf1qHx;t03Y`cNV>b+TO zwm9B%3NKkxLtMLD!*bIywSU^r5lh{Uoff>Xz{q^%=X+bt(~2Y0vryNPdU%Ds3g%3E zP=thEWo_j9fC*}!@$P7&;Ka&+KdFJ#Zi;pCVY@dqR#nMrb9kAOho-_ zSmwQovrF*@NW&}Fl1Dic2Y@CNsQk3b8dinQf2_mIlS5?Q;cXUKSUFmygCS zSMR7~zPEnBy8dAp$=mOBzNjJ>L2lEg?0@0lIkfX5k4|o@P;@NF>(ofOjmbrN=weE+X6P$b(yAc4 zj33-ak>i7Rsc&nq5G9s7xINZ*N)fX|e+dCumYS?8t&}2+)-+`@(7!=_g|Y=?3X`( z(ics+tFS-$kaw5Wo`u8gZHzWSr0v#k&Y{t_IlSiCoh*_jDy&AU$yS}l!e=%Vko#Lr zqho^Z>^GX)_?*$%Q!2fxw$O_7nsM+W=wU_)9LO?QL@Yc(pZIuqw?9G2j~72F9fwKiPaT00$&Fe5;Kx7Mhq z@%1-r;%a6qb;sY-oMm|i2+$UiTMp)e$vrtZ@TEado6BSnmN!V}mW4McMk;a^NQ z9c@>I<$O?`x5eDNinXMIRiqs{A8L5|irslw?Qg0t0-JheIni;7@enQDPk)9;wu9<6 z5VP@Po;x>1vgq{&?wq&SB!+>1svb$P_VW_eTW0P4AVtx$D^r0EHbeNY-|*o{hMO=Be%F>vyQl^S*@iTqI#8BON%@%YtkV;*bkVln z#yD_d5j`*P^4Cxph9WU& zZxjv-#)aULO?&%fd;1Ji6imTga?&!X^B`#>M0cl2pL7+G*pryBxfRHxv{}Y|g1x@} zsE9Eb2Li0*=>PyS&CdOBWlP;FW|r`HA~8e98~~V(?2Cb`I`*_8i&0-xuVL>p&kpJy zCKct{ESQwKPVcccKP^O53my{pBz5XrHFQjrEL?=KZkx4y)P*ZLwMpVuR z?1}}z+5)YU9QWzWjp^ul8UDB2q}BYdCqMd6cVy%LTYMhJ92cMega82f(HFnN{7Z@+ zM;yOF{zkl{soEo%e0K!@eV-g>9&fL|nV(sH#Qdw-jsuT(#^1m=ntcENNgnT$W9;wF g{(snXhd*ThvlGmXnP{Z~0GMg-1g(So+5i0e2Y1>u1ONa4 literal 0 HcmV?d00001 diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2.tar.gz b/mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..1752f2d48add3079c3db749dc0a3f16a3767386c GIT binary patch literal 2409 zcmV-v36}OBiwFn+00002|7~e(UvP3|W^8F^Xml+wE-@}LE_7jX0PP!VbKAJlpZP0L z-iJt2i6ZszLlY(OIZl(t$$1<%osOg9z$9ehOaeRtjI3tz-@5?#k}NxRCh=Sv?gxti z7Q2hZzCh4U&*?oo##b*14oSN8UBESP)356ehSjs`_q^e#zlE;09sn{SaSH6e^&)=| z=`|pe~J7*xSs#LCjUQ3{@+>2|HIwE zj&_nl<%ah?ProR9`j6~6MoJmdQVb1qXCwbv$I}p zwp}uNPDGH>L}6@Tsk;=||0YquV}c|{a!$}S_8o*_j7Nwvk${pzbiUM>rN5$JPJ+vb z3Mo(~3_?O94$X5i<0(OQ#cmcYDZ2ogpgu+%bULR3CHYF>F(iUsFdzc*d{nD6%w`!2 z)KYLnRg8CvozMYz&qs`TifR}v8>GO!I` zgP{RDmvXK|1Ysyc3!Yx87EhsA=_s~*q1r%CiCAZbXCzv}0+NU?4L{8UEvTF;_0MQX zSU{W)%*XD==Nl%xCW`IrISz5U8DpOT zA+|(E6!Xm(|KwtxVb~)cV*z590>1%+M_e11&|Q@ufZ?B&O8HbiX%#6)vd73)wvy|h z9Ah}vV=+VkP()-@v5pmk6XOewsAO0l4(6OfNP*$Al>t3?lChe3zsSIXPRTVvH0paw z7U+biV6bUeQF@n6V9G@kPy1FcBBVKEx(@QO-%rF&XoeKwC%{nw}))N7(!t5Uhy zyOhW*Wr&e0*`g9cm6_mt#8E~>tKEj(vkEUcC|tJOu4=2wZPI>y&aY~6*Eis0;c+Fg zaUHYR&;m{ANsQ44b{r8bh>04;>y$HtPisf#g@-B1>kjC^^#6e81(-4LEHGC|Sw>I> zzfs+J=U4?F!VDJ@I(5lzvXW1w%!O=Bz)qb*ja-KphMN*MJsSSPf;^^h0 z4(g8_clsF&{u!ijNbhkBIih91Q$7P>Or>yDWfn;r(xpl0=#7%0_gg)*m4%9vW~^lg zV7{r{L1Ip#XmXln#Q2{MT$7EJfeD**mg7urjz!~gHw#Z~wacy|-_^QGt>k@m9y+vC z1n;_zDwddKX*Gc+wbCl73dJ2jFp7vI+I!0+ES0n0OMRG$1#D#%->!u!gSVJdsIDTy zT2-XW=hi}98~ts9Mqju1yGUZRQEkXZZIt!N{k5TMUq`Oqb)8I8>+_+=_rleNq(1 zMdj|~zkUMrG_wvGwLe#?C07B&1azo>fcsr&zrc|oISo^nQrY>U&1b3vr9pZp-gLKv=XB{YoWBI%J8x@Pwm7h}uOgE2c$*v8JR=cz?urgK6Dw#0K*&%&A()rn(yl&enjWI^bfWLaXa~faT z@3jL=?xQP|uNQxxuJx=|I;uKP;|&GcN-0y+8#m$Ailc)Z_2~xOwbWiK_}b;cK*yI_ zbRXX+HN$|4caK{on3S}6>i zOR^Ma?iBj%r|8#1bg+MN_~Ktjkj5^Fp`oip&d4KyX5i}j?5Bb>9KPUrrBb}ZhFM=9 z3pNUVYivleb3+iK!*O;Fsb~(_uVPn|;m?d@#256xWa7EC#9j!KnCWF~f%eM$RpCrx zRpOPDtQ*|;Ax%l04M_O(4rcV6hPNAwK4%~}HIOSf*vZXQZ?OZTnDv0C3D(_Ax#jgz zqtKlWeJf$^XAFH%!}`AB>-)Nn^?g-?`hH%^g05Qa<~4fr{YUft$B+O0M}GvWA339) zz3owR{rA(}|0PSvWq&~4btI3YZ{z>BegCoJ_SgJ>G<3b@{_i2+Ox-3q2`6v@nOZ8( zLrrUgRdlO&92V5*!o2OawT0ML?VPT9Z42j@ChC1*{VD@J#-ZsUPYHE7u+9@gKS=b*n;~S}7zhBXs%MvTa%QWjP^H^&DXVC1PqNOC^t*@cY2o zwJm+0s9s@`E16=m0vtv5w1aBv{@r!<9M}H5M%rjWQ7vB|8ue99<*0gT40Vzc>pY`T z*flp{N_KryYIquo-GHYAmSqsnac~KuE1Ee&H4GF5XVAb2wXJXO|HrTY(S7yy#c$s- z|KH;Oo;zH>{~wID2aW$f1iT>Wk)OS4VEyRH_T8RQyiJ*ikYn^@0{+-}Jak;^KpnK{j1nN5-+agFMc@%; z7nyn+HimxV$M7_`FTS&T?-_gdp5eLopW@wrO21O%b9L!wzK=MA2sTBnClejEI*(z` zT*qx&weJwR>SRcm?5bA`Fb%?A4|eoYT{l@){r>`*O0a=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "pygments" +version = "2.17.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "rich" +version = "13.7.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, + {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "typer" +version = "0.9.0" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.6" +files = [ + {file = "typer-0.9.0-py3-none-any.whl", hash = "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee"}, + {file = "typer-0.9.0.tar.gz", hash = "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2"}, +] + +[package.dependencies] +click = ">=7.1.1,<9.0.0" +colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\""} +rich = {version = ">=10.11.0,<14.0.0", optional = true, markers = "extra == \"all\""} +shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""} +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] +dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] +doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] +test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] + +[[package]] +name = "typing-extensions" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "7e4e54aaa562d12214312d56749ecc2f12e61a29eedb2de9b72dd3f0c48541ad" diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/pyproject.toml b/mil_common/utils/mil_tools/scripts/mil-preflight/pyproject.toml new file mode 100644 index 000000000..262030cba --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/pyproject.toml @@ -0,0 +1,17 @@ +[tool.poetry] +name = "mil-preflight" +version = "0.1.2" +description = "" +authors = ["Anthony Liao ","Keith Khadar ","Joshua Thomas "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.8" +typer = {extras = ["all"], version = "^0.9.0"} + +[tool.poetry.scripts] +preflight = "mil_preflight.main:app" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/tests/__init__.py b/mil_common/utils/mil_tools/scripts/mil-preflight/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflight.py b/mil_common/utils/mil_tools/scripts/preflight/preflight.py deleted file mode 100644 index ba1fef7ce..000000000 --- a/mil_common/utils/mil_tools/scripts/preflight/preflight.py +++ /dev/null @@ -1,122 +0,0 @@ -import subprocess - -import preflight_menus -import rosnode -import rospy -import rostopic -import typer -from PyInquirer import prompt -from rich.progress import track - -app = typer.Typer() - -hardwareChecklist = [ - { - "type": "checkbox", - "message": "Hardware Checklist:", - "name": "HardwareTests: \nPlease check that all of the following are in working order. \nYou cannot continue until everything has been checked.", - "choices": [ - {"name": "check thing 1"}, - {"name": "check thing 2"}, - {"name": "check thing 3"}, - {"name": "check thing 4"}, - {"name": "check thing 5"}, - ], - }, -] -actuatorChecklist = [ - { - "type": "list", - "message": "Select which system you want to run. BE CAREFUL make sure everyone's fingures are secured.", - "name": "Mechanical Systems Check:", - "choices": ["thrusters", "Gripper"], - }, -] - -topics = [ - "/camera/front/right/image_raw", - "/camera/down/image_raw", - "/camera/front/left/image_raw", - "/dvl", - "/depth", - "/imu/data_raw", - "/imu/mag", -] - -nodes = ["/odom_estimator"] - -actuatorsList = ["/thrusters/thrust"] - - -@app.command("Start") -def main(): - # Display Modes/Options - subprocess.run("clear", shell=True) - mode = preflight_menus.display_start_menu() - - if mode == "Run Preflight Full Test": - hardware() - software() - actuators() - - # Complete the actuator tests - subprocess.run("clear", shell=True) - - -def hardware(): - # Complete the hardware tests - subprocess.run("clear", shell=True) - answers = prompt(hardwareChecklist) - while len(next(iter(answers.values()))) != 5: - subprocess.run("clear", shell=True) - answers = prompt(hardwareChecklist) - - -def software(): - # Complete the software tests - subprocess.run("clear", shell=True) - rospy.init_node("preflight") - - # Check Nodes - answers = [] - for node in track(nodes, description="Checking Nodes..."): - try: - answers.append({node: rosnode.rosnode_ping(node, 5)}) - except Exception: - answers.append({node: False}) - print(answers) - - # Check Topics - answers = [] - for topic in track(topics, description="Checking Topics..."): - try: - topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class - rospy.wait_for_message( - topicStr, - topicType, - 5, - ) # try to get a message from that topic - answers.append({topic: True}) - except Exception: - answers.append({topic: False}) - print(answers) - - print( - prompt( - [ - { - "type": "confirm", - "name": "continue", - "message": "Continue?", - }, - ], - ), - ) - - -def actuators(): - subprocess.run("clear", shell=True) - - -if __name__ == "__main__": - app() diff --git a/mil_common/utils/mil_tools/scripts/preflight/preflight_menus.py b/mil_common/utils/mil_tools/scripts/preflight/preflight_menus.py deleted file mode 100644 index db5be62d2..000000000 --- a/mil_common/utils/mil_tools/scripts/preflight/preflight_menus.py +++ /dev/null @@ -1,42 +0,0 @@ -from PyInquirer import prompt -from rich.console import Console - - -def display_start_menu(): - console = Console() - - # Title - console.print( - "[bold green]Preflight Program - Autonomous Robot Verification[/bold green]\n", - ) - - # Description - console.print( - "Welcome to the Preflight Program, a tool inspired by the preflight checklists used by pilots before " - "flying a plane. This program is designed to verify the functionality of all software and hardware " - "systems on your autonomous robot. It ensures that everything is in working order, allowing you to " - "safely deploy your robot with confidence.\n", - ) - - # Authors section - console.print("\n[italic]Authors:[/italic]") - console.print("Keith Khadar") - console.print("Anthony Liao") - console.print("Joshua Thomas\n") - - # Menu options - start_menu = [ - { - "type": "list", - "name": "mode selection", - "message": "Menu", - "choices": [ - "Run Preflight Full Test", - "View Report", - "Run Specific Test", - "View Documentation", - ], - }, - ] - option = prompt(start_menu) - return next(iter(option.values())) diff --git a/preflight-test/bin/python b/preflight-test/bin/python new file mode 120000 index 000000000..b8a0adbbb --- /dev/null +++ b/preflight-test/bin/python @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/preflight-test/bin/python3 b/preflight-test/bin/python3 new file mode 120000 index 000000000..ae65fdaa1 --- /dev/null +++ b/preflight-test/bin/python3 @@ -0,0 +1 @@ +/usr/bin/python3 \ No newline at end of file diff --git a/preflight-test/lib64 b/preflight-test/lib64 new file mode 120000 index 000000000..7951405f8 --- /dev/null +++ b/preflight-test/lib64 @@ -0,0 +1 @@ +lib \ No newline at end of file diff --git a/preflight-test/pyvenv.cfg b/preflight-test/pyvenv.cfg new file mode 100644 index 000000000..853404e23 --- /dev/null +++ b/preflight-test/pyvenv.cfg @@ -0,0 +1,3 @@ +home = /usr/bin +include-system-site-packages = false +version = 3.8.10 diff --git a/requirements.txt b/requirements.txt index 1a77082c7..d32a3e353 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,6 +34,7 @@ sphinx-copybutton==0.5.0 # Terminal typer[all]==4.8.0 PyInquirer==1.0.3 +~/catkin_ws/src/mil/mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2-py3-none-any.whl==0.1.2 # External Devices pyserial==3.5 From 51be3b61a593e56597b79f1dd41a4af4479cbd28 Mon Sep 17 00:00:00 2001 From: keithmk Date: Wed, 7 Feb 2024 11:29:21 -0500 Subject: [PATCH 16/26] Fix actuators and switched to alias instead of pip package --- .../mil_tools/scripts/mil-preflight/README.md | 1 - .../dist/mil_preflight-0.1.2-py3-none-any.whl | Bin 3168 -> 0 bytes .../dist/mil_preflight-0.1.2.tar.gz | Bin 2409 -> 0 bytes .../mil-preflight/{mil_preflight => }/main.py | 35 ++++- .../mil-preflight/mil_preflight/__init__.py | 0 .../scripts/mil-preflight/poetry.lock | 146 ------------------ .../scripts/mil-preflight/pyproject.toml | 17 -- .../scripts/mil-preflight/tests/__init__.py | 0 requirements.txt | 1 - scripts/setup.bash | 3 + 10 files changed, 30 insertions(+), 173 deletions(-) delete mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/README.md delete mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2-py3-none-any.whl delete mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2.tar.gz rename mil_common/utils/mil_tools/scripts/mil-preflight/{mil_preflight => }/main.py (84%) delete mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/mil_preflight/__init__.py delete mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/poetry.lock delete mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/pyproject.toml delete mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/tests/__init__.py diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/README.md b/mil_common/utils/mil_tools/scripts/mil-preflight/README.md deleted file mode 100644 index 88a138a4c..000000000 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/README.md +++ /dev/null @@ -1 +0,0 @@ -#Preflight diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2-py3-none-any.whl b/mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2-py3-none-any.whl deleted file mode 100644 index 0689d158c314c2caded2c9c7f01d8adf7d532dbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3168 zcmai$cT`i^7KcMGMx@CgAXN|ogb)I#G{Mjby|q*KlXR_+UM-Ef9A#vjJyBFh3Hgejc%I%nShN(paaz3-rJ0 zjiLq3+fAUyRXA_#A_InmecW?MLEXu8dEJAIpB|#L9|rN0Ea&*H$I1myjDwUGXD@GV;66$sOkyhjxv^&uxSnN{%u*l3QBp!kmhKH}`XCss-v-+12^v=gvV2HI9rUg_UWhk<5KQacp%C2V;s*I%`s z_^Ot3M~@A8Mcf2m1%hUH3(h-d%yvdFQhed^0y4Nb)+s`KrF2buTrit=`yYV?FBtoE zzzTgZq}L3n7Ne(EEff_;7zC9B+6Y{*ll34oj9!z!<{5vl+hGmY4+?KXl<8^D7DIT5=F9YVvXz0_9cms2bj_}q@cTZ2C(yfHfwg-&4}E0%9@r!&}`q8%B!p%5Q`Rp7i* z*5xkT44;NaAv9xwIW5j8UBG@p9}xv4r!avLi4D;{{9to04=X5F3KzGE5pu|ADQ-ok z#759DPaRrSap!rcEtx6F#Ktw(ieB)lRp2+rbIxzo_oZV?)ZV>ipM3=KZ&{~AhcJoE zTiQ28MmQ+-J*W<2aM#34%b%}BTV+5rdIF>^el44}hA8)JG(x>QA$lM$W+LijR07+n zF3AT0PA+HNW)z%?NOj0wU2B6sgy_4{Kd{InUXTU?;Q$=`qf1qHx;t03Y`cNV>b+TO zwm9B%3NKkxLtMLD!*bIywSU^r5lh{Uoff>Xz{q^%=X+bt(~2Y0vryNPdU%Ds3g%3E zP=thEWo_j9fC*}!@$P7&;Ka&+KdFJ#Zi;pCVY@dqR#nMrb9kAOho-_ zSmwQovrF*@NW&}Fl1Dic2Y@CNsQk3b8dinQf2_mIlS5?Q;cXUKSUFmygCS zSMR7~zPEnBy8dAp$=mOBzNjJ>L2lEg?0@0lIkfX5k4|o@P;@NF>(ofOjmbrN=weE+X6P$b(yAc4 zj33-ak>i7Rsc&nq5G9s7xINZ*N)fX|e+dCumYS?8t&}2+)-+`@(7!=_g|Y=?3X`( z(ics+tFS-$kaw5Wo`u8gZHzWSr0v#k&Y{t_IlSiCoh*_jDy&AU$yS}l!e=%Vko#Lr zqho^Z>^GX)_?*$%Q!2fxw$O_7nsM+W=wU_)9LO?QL@Yc(pZIuqw?9G2j~72F9fwKiPaT00$&Fe5;Kx7Mhq z@%1-r;%a6qb;sY-oMm|i2+$UiTMp)e$vrtZ@TEado6BSnmN!V}mW4McMk;a^NQ z9c@>I<$O?`x5eDNinXMIRiqs{A8L5|irslw?Qg0t0-JheIni;7@enQDPk)9;wu9<6 z5VP@Po;x>1vgq{&?wq&SB!+>1svb$P_VW_eTW0P4AVtx$D^r0EHbeNY-|*o{hMO=Be%F>vyQl^S*@iTqI#8BON%@%YtkV;*bkVln z#yD_d5j`*P^4Cxph9WU& zZxjv-#)aULO?&%fd;1Ji6imTga?&!X^B`#>M0cl2pL7+G*pryBxfRHxv{}Y|g1x@} zsE9Eb2Li0*=>PyS&CdOBWlP;FW|r`HA~8e98~~V(?2Cb`I`*_8i&0-xuVL>p&kpJy zCKct{ESQwKPVcccKP^O53my{pBz5XrHFQjrEL?=KZkx4y)P*ZLwMpVuR z?1}}z+5)YU9QWzWjp^ul8UDB2q}BYdCqMd6cVy%LTYMhJ92cMega82f(HFnN{7Z@+ zM;yOF{zkl{soEo%e0K!@eV-g>9&fL|nV(sH#Qdw-jsuT(#^1m=ntcENNgnT$W9;wF g{(snXhd*ThvlGmXnP{Z~0GMg-1g(So+5i0e2Y1>u1ONa4 diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2.tar.gz b/mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2.tar.gz deleted file mode 100644 index 1752f2d48add3079c3db749dc0a3f16a3767386c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2409 zcmV-v36}OBiwFn+00002|7~e(UvP3|W^8F^Xml+wE-@}LE_7jX0PP!VbKAJlpZP0L z-iJt2i6ZszLlY(OIZl(t$$1<%osOg9z$9ehOaeRtjI3tz-@5?#k}NxRCh=Sv?gxti z7Q2hZzCh4U&*?oo##b*14oSN8UBESP)356ehSjs`_q^e#zlE;09sn{SaSH6e^&)=| z=`|pe~J7*xSs#LCjUQ3{@+>2|HIwE zj&_nl<%ah?ProR9`j6~6MoJmdQVb1qXCwbv$I}p zwp}uNPDGH>L}6@Tsk;=||0YquV}c|{a!$}S_8o*_j7Nwvk${pzbiUM>rN5$JPJ+vb z3Mo(~3_?O94$X5i<0(OQ#cmcYDZ2ogpgu+%bULR3CHYF>F(iUsFdzc*d{nD6%w`!2 z)KYLnRg8CvozMYz&qs`TifR}v8>GO!I` zgP{RDmvXK|1Ysyc3!Yx87EhsA=_s~*q1r%CiCAZbXCzv}0+NU?4L{8UEvTF;_0MQX zSU{W)%*XD==Nl%xCW`IrISz5U8DpOT zA+|(E6!Xm(|KwtxVb~)cV*z590>1%+M_e11&|Q@ufZ?B&O8HbiX%#6)vd73)wvy|h z9Ah}vV=+VkP()-@v5pmk6XOewsAO0l4(6OfNP*$Al>t3?lChe3zsSIXPRTVvH0paw z7U+biV6bUeQF@n6V9G@kPy1FcBBVKEx(@QO-%rF&XoeKwC%{nw}))N7(!t5Uhy zyOhW*Wr&e0*`g9cm6_mt#8E~>tKEj(vkEUcC|tJOu4=2wZPI>y&aY~6*Eis0;c+Fg zaUHYR&;m{ANsQ44b{r8bh>04;>y$HtPisf#g@-B1>kjC^^#6e81(-4LEHGC|Sw>I> zzfs+J=U4?F!VDJ@I(5lzvXW1w%!O=Bz)qb*ja-KphMN*MJsSSPf;^^h0 z4(g8_clsF&{u!ijNbhkBIih91Q$7P>Or>yDWfn;r(xpl0=#7%0_gg)*m4%9vW~^lg zV7{r{L1Ip#XmXln#Q2{MT$7EJfeD**mg7urjz!~gHw#Z~wacy|-_^QGt>k@m9y+vC z1n;_zDwddKX*Gc+wbCl73dJ2jFp7vI+I!0+ES0n0OMRG$1#D#%->!u!gSVJdsIDTy zT2-XW=hi}98~ts9Mqju1yGUZRQEkXZZIt!N{k5TMUq`Oqb)8I8>+_+=_rleNq(1 zMdj|~zkUMrG_wvGwLe#?C07B&1azo>fcsr&zrc|oISo^nQrY>U&1b3vr9pZp-gLKv=XB{YoWBI%J8x@Pwm7h}uOgE2c$*v8JR=cz?urgK6Dw#0K*&%&A()rn(yl&enjWI^bfWLaXa~faT z@3jL=?xQP|uNQxxuJx=|I;uKP;|&GcN-0y+8#m$Ailc)Z_2~xOwbWiK_}b;cK*yI_ zbRXX+HN$|4caK{on3S}6>i zOR^Ma?iBj%r|8#1bg+MN_~Ktjkj5^Fp`oip&d4KyX5i}j?5Bb>9KPUrrBb}ZhFM=9 z3pNUVYivleb3+iK!*O;Fsb~(_uVPn|;m?d@#256xWa7EC#9j!KnCWF~f%eM$RpCrx zRpOPDtQ*|;Ax%l04M_O(4rcV6hPNAwK4%~}HIOSf*vZXQZ?OZTnDv0C3D(_Ax#jgz zqtKlWeJf$^XAFH%!}`AB>-)Nn^?g-?`hH%^g05Qa<~4fr{YUft$B+O0M}GvWA339) zz3owR{rA(}|0PSvWq&~4btI3YZ{z>BegCoJ_SgJ>G<3b@{_i2+Ox-3q2`6v@nOZ8( zLrrUgRdlO&92V5*!o2OawT0ML?VPT9Z42j@ChC1*{VD@J#-ZsUPYHE7u+9@gKS=b*n;~S}7zhBXs%MvTa%QWjP^H^&DXVC1PqNOC^t*@cY2o zwJm+0s9s@`E16=m0vtv5w1aBv{@r!<9M}H5M%rjWQ7vB|8ue99<*0gT40Vzc>pY`T z*flp{N_KryYIquo-GHYAmSqsnac~KuE1Ee&H4GF5XVAb2wXJXO|HrTY(S7yy#c$s- z|KH;Oo;zH>{~wID2aW$f1iT>Wk)OS4VEyRH_T8RQyiJ*ikYn^@0{+-}Jak;^KpnK{j1nN5-+agFMc@%; z7nyn+HimxV$M7_`FTS&T?-_gdp5eLopW@wrO21O%b9L!wzK=MA2sTBnClejEI*(z` zT*qx&weJwR>SRcm?5bA`Fb%?A4|eoYT{l@){r>`*O0a=3.0,<4.0)"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] -linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins"] -profiling = ["gprof2dot"] -rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] - -[[package]] -name = "mdurl" -version = "0.1.2" -description = "Markdown URL utilities" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, - {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, -] - -[[package]] -name = "pygments" -version = "2.17.2" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, -] - -[package.extras] -plugins = ["importlib-metadata"] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "rich" -version = "13.7.0" -description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, - {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, -] - -[package.dependencies] -markdown-it-py = ">=2.2.0" -pygments = ">=2.13.0,<3.0.0" -typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} - -[package.extras] -jupyter = ["ipywidgets (>=7.5.1,<9)"] - -[[package]] -name = "shellingham" -version = "1.5.4" -description = "Tool to Detect Surrounding Shell" -optional = false -python-versions = ">=3.7" -files = [ - {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, - {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, -] - -[[package]] -name = "typer" -version = "0.9.0" -description = "Typer, build great CLIs. Easy to code. Based on Python type hints." -optional = false -python-versions = ">=3.6" -files = [ - {file = "typer-0.9.0-py3-none-any.whl", hash = "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee"}, - {file = "typer-0.9.0.tar.gz", hash = "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2"}, -] - -[package.dependencies] -click = ">=7.1.1,<9.0.0" -colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\""} -rich = {version = ">=10.11.0,<14.0.0", optional = true, markers = "extra == \"all\""} -shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""} -typing-extensions = ">=3.7.4.3" - -[package.extras] -all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] -dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] -doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] -test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] - -[[package]] -name = "typing-extensions" -version = "4.9.0" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, -] - -[metadata] -lock-version = "2.0" -python-versions = "^3.8" -content-hash = "7e4e54aaa562d12214312d56749ecc2f12e61a29eedb2de9b72dd3f0c48541ad" diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/pyproject.toml b/mil_common/utils/mil_tools/scripts/mil-preflight/pyproject.toml deleted file mode 100644 index 262030cba..000000000 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/pyproject.toml +++ /dev/null @@ -1,17 +0,0 @@ -[tool.poetry] -name = "mil-preflight" -version = "0.1.2" -description = "" -authors = ["Anthony Liao ","Keith Khadar ","Joshua Thomas "] -readme = "README.md" - -[tool.poetry.dependencies] -python = "^3.8" -typer = {extras = ["all"], version = "^0.9.0"} - -[tool.poetry.scripts] -preflight = "mil_preflight.main:app" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/tests/__init__.py b/mil_common/utils/mil_tools/scripts/mil-preflight/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/requirements.txt b/requirements.txt index d32a3e353..1a77082c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,7 +34,6 @@ sphinx-copybutton==0.5.0 # Terminal typer[all]==4.8.0 PyInquirer==1.0.3 -~/catkin_ws/src/mil/mil_common/utils/mil_tools/scripts/mil-preflight/dist/mil_preflight-0.1.2-py3-none-any.whl==0.1.2 # External Devices pyserial==3.5 diff --git a/scripts/setup.bash b/scripts/setup.bash index 97d54f7da..5e0bb5b04 100755 --- a/scripts/setup.bash +++ b/scripts/setup.bash @@ -89,6 +89,9 @@ alias fd="fdfind" # Gazebo aliases alias gazebogui="rosrun gazebo_ros gzclient __name:=gzclient" +# Preflight aliases +alias preflight='python3 $MIL_REPO/mil_common/utils/mil_tools/scripts/mil-preflight/main.py' + # Process killing aliases alias killgazebo="killall -9 gzserver && killall -9 gzclient" alias killros='$MIL_REPO/scripts/kill_ros.sh' From cdad43f93eb9097d5713458d2013306e77c8d216 Mon Sep 17 00:00:00 2001 From: keithmk Date: Fri, 16 Feb 2024 11:33:38 -0500 Subject: [PATCH 17/26] Added more UI --- .../mil_tools/scripts/mil-preflight/main.py | 247 ++++++++---------- .../mil_tools/scripts/mil-preflight/menus.py | 72 +++++ .../mil-preflight/old-code/RunTests.py | 11 - .../scripts/mil-preflight/old-code/TestLib.py | 93 ------- 4 files changed, 184 insertions(+), 239 deletions(-) create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/menus.py delete mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/old-code/RunTests.py delete mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/old-code/TestLib.py diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py index 4d773cb8a..5bd578b4d 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py @@ -1,59 +1,20 @@ import subprocess import time +import menus import rosnode import rospy import rostopic -import typer from PyInquirer import prompt from rich.console import Console -from rich.progress import track +from rich.progress import Progress, track # Custom message imports from subjugator_msgs.msg import ThrusterCmd -app = typer.Typer() - - -def display_start_menu(): - console = Console() - - # Title - console.print( - "[bold green]Preflight Program - Autonomous Robot Verification[/bold green]", - ) - - # Description - console.print( - "Welcome to the Preflight Program, a tool inspired by the preflight checklists used by pilots before " - "flying a plane. This program is designed to verify the functionality of all software and hardware " - "systems on your autonomous robot. It ensures that everything is in working order, allowing you to " - "safely deploy your robot with confidence.\n", - ) - - # Authors section - console.print("\n[italic]Authors:[/italic]") - console.print("Keith Khadar") - console.print("Anthony Liao") - console.print("Joshua Thomas\n") - - # Menu options - start_menu = [ - { - "type": "list", - "name": "mode selection", - "message": "Menu", - "choices": [ - "Run Preflight Full Test", - "View Report", - "Run Specific Test", - "View Documentation", - "Exit", - ], - }, - ] - option = prompt(start_menu) - return next(iter(option.values())) +node_timout = 5 # seconds +topic_timout = 5 # seconds +actuator_timout = 5 # seconds hardwareChecklist = [ @@ -72,13 +33,13 @@ def display_start_menu(): ] topics = [ - "/camera/front/right/image_raw", - "/camera/down/image_raw", - "/camera/front/left/image_raw", - "/dvl", - "/depth", - "/imu/data_raw", - "/imu/mag", + # "/camera/front/right/image_raw", + # "/camera/down/image_raw", + # "/camera/front/left/image_raw", + # "/dvl", + # "/depth", + # "/imu/data_raw", + # "/imu/mag", ] nodes = ["/odom_estimator"] @@ -100,127 +61,143 @@ def display_start_menu(): ] -@app.command("Start") def main(): - # Display Modes/Options + # Clear Screen and Display Start menu subprocess.run("clear", shell=True) - mode = display_start_menu() + # Print Info about Preflight + Console().print(menus.info_page) + + # Print start select menu + option = prompt(menus.start_menu) + mode = next(iter(option.values())) + + # Select the mode and run it if mode == "Run Preflight Full Test": - hardware() - software() - actuators() + fullTest() if mode == "Exit": subprocess.run("clear", shell=True) return + + # Return to this screen after running the selected mode main() -def hardware(): - # Complete the hardware tests - subprocess.run("clear", shell=True) - answers = prompt(hardwareChecklist) - while len(next(iter(answers.values()))) != 5: +def fullTest(): + ### Complete the hardware tests ### + + while True: subprocess.run("clear", shell=True) answers = prompt(hardwareChecklist) + # If everything has been checked off + if len(next(iter(answers.values()))) == 5: + break + else: + menu_ans = prompt(menus.incomplete_continue) + if next(iter(menu_ans.values())) is True: + # Continue even though everything has not been checked off + break + else: + # Go back to main menu + return + + ### Complete Software Tests ### -def software(): - # Complete the software tests subprocess.run("clear", shell=True) + try: + rostopic._check_master() + except Exception: + Console().print("[bold] ROS not running! Please try again later[/]") + menu_ans = prompt(menus.press_anykey) + return + rospy.init_node("preflight") # Check Nodes answers = [] for node in track(nodes, description="Checking Nodes..."): + # Try and ping the nodes try: - answers.append({node: rosnode.rosnode_ping(node, 5)}) + answers.append((node, rosnode.rosnode_ping(node, node_timout))) except Exception: - answers.append({node: False}) - print(answers) + answers.append((node, False)) + + print_results(answers) + menu_ans = prompt(menus.continue_question) + if next(iter(menu_ans.values())) is False: + # Go back to main menu + return # Check Topics answers = [] for topic in track(topics, description="Checking Topics..."): + # Check for messages on the topics try: topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class rospy.wait_for_message( topicStr, topicType, - 5, + topic_timout, ) # try to get a message from that topic answers.append({topic: True}) except Exception: answers.append({topic: False}) - print(answers) - - print( - prompt( - [ - { - "type": "confirm", - "name": "continue", - "message": "Continue?", - }, - ], - ), - ) - - -def actuators(): + print_results(answers) + + menu_ans = prompt(menus.continue_question) + if next(iter(menu_ans.values())) is False: + # Go back to main menu + return + + ### Actuators Test ### subprocess.run("clear", shell=True) - print("test") + answers = [] - try: - prompt( - [ - { - "type": "confirm", - "name": "runActuator", - "message": "Are your sure you want to run " - + actuatorsList[0][0] - + "? BE CAREFUL make sure everyone's fingures are secured.", - }, - ], - ) - topicType, topicStr, _ = rostopic.get_topic_class( - actuatorsList[0][0], - ) # get topic class - print(topicType) - pub = rospy.Publisher(topicStr, topicType, queue_size=10) - print(actuatorsList[0][1]) - t_end = time.time() + 5 - while time.time() < t_end: - pub.publish(actuatorsList[0][1]) - answers.append( - prompt( - [ - { - "type": "confirm", - "name": "worked?", - "message": "Did " + actuatorsList[0][0] + " work as expected?", - }, - ], - ), - ) - except Exception as e: - print(e) - answers.append(False) - - print(answers) - - print( - prompt( - [ - { - "type": "confirm", - "name": "continue", - "message": "Continue?", - }, - ], - ), - ) + for actuator in actuatorsList: + try: + # Confirm that it is safe to run this actuator + Console().print(menus.safety_check, actuator[0]) + menu_ans = prompt(menus.continue_question) + if next(iter(menu_ans.values())) is False: + # Go back to main menu + return + + # Create a publisher + topicType, topicStr, _ = rostopic.get_topic_class(actuator[0]) + pub = rospy.Publisher(topicStr, topicType, queue_size=10) + + # Publish to the topic for the specified timeout + with Progress() as progress: + t_start = time.time() + t_end = t_start + actuator_timout + t_prev = time.time() + task = progress.add_task("Running", total=(t_end - t_start)) + while time.time() <= t_end: + pub.publish(actuator[1]) + progress.update(task, advance=(time.time() - t_prev)) + t_prev = time.time() + progress.update(task, advance=t_end) + + # Ask if the actuator worked + Console().print(menus.actuator_check) + answers.append((actuator[0], next(iter(prompt(menus.yes_no).values())))) + except Exception: + answers.append((actuator[0], False)) + + print_results(answers) + menu_ans = prompt(menus.press_anykey) + return + + +def print_results(systems): + subprocess.run("clear", shell=True) + for name, status in systems: + if status: + Console().print(f"{name}: [green]✔[/] Working") + else: + Console().print(f"{name}: [red]❌[/] Not Working") if __name__ == "__main__": - app() + main() diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py b/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py new file mode 100644 index 000000000..01ab69f31 --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py @@ -0,0 +1,72 @@ +################################################################################ +# File name: menus.py +# Author: Keith Khadar +# Description: This file is used to store all the menus used by prefligh +################################################################################ + + +# ----- Home Page -----# +info_page = """ +[bold green]Preflight Program - Autonomous Robot Verification[/bold green] +Welcome to the Preflight Program, a tool inspired by the preflight checklists used by pilots before flying a plane. This program is designed to verify the functionality of all software and hardware systems on your autonomous robot. It ensures that everything is in working order, allowing you to safely deploy your robot with confidence.\n +[italic]Authors:[/italic] +Keith Khadar +Anthony Liao +Joshua Thomas\n +""" + + +start_menu = [ + { + "type": "list", + "name": "mode selection", + "message": "Menu", + "choices": [ + "Run Preflight Full Test", + "View Report", + "Run Specific Test", + "View Documentation", + "Exit", + ], + }, +] + +# ----- Loading Screen -----# +continue_question = [ + { + "type": "confirm", + "name": "continue", + "message": "Continue?", + }, +] +press_anykey = [ + { + "type": "confirm", + "name": "continue", + "message": "Press any key to continue.", + }, +] + +incomplete_continue = [ + { + "type": "confirm", + "name": "incomplete", + "message": "This checklist is incomplete. Do you wish to continue?", + }, +] +yes_no = [ + { + "type": "confirm", + "name": "yes_no", + "message": "Yes?", + }, +] + +# ----- Actuators Screen -----# +safety_check = """ +MAKE SURE THAT EVERYONE'S FINGERS ARE CLEAR!! Is it safe to run the following actuator? +""" + +actuator_check = """ +Did the actuator work? +""" diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/old-code/RunTests.py b/mil_common/utils/mil_tools/scripts/mil-preflight/old-code/RunTests.py deleted file mode 100644 index 54d2940d4..000000000 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/old-code/RunTests.py +++ /dev/null @@ -1,11 +0,0 @@ -import importlib - - -def getHardWareCheckist(robotName): - robotName += ".hardware" - module = importlib.import_module(robotName) - - if hasattr(module, "hardwareTests"): - return module.hardwareTests - else: - return [] diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/old-code/TestLib.py b/mil_common/utils/mil_tools/scripts/mil-preflight/old-code/TestLib.py deleted file mode 100644 index 4670e8781..000000000 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/old-code/TestLib.py +++ /dev/null @@ -1,93 +0,0 @@ -import rospy -import rosservice -import rostopic - - -class Test: - # Constructor - def __init__(self, name, description, communicationType, address): - self.name = name - self.description = description - self.communicationType = communicationType - self.address = address - self.needsHumanAuthorization = False - - # Check if the communication interface is up and running - def isActive(self): - # Check if the topic is up - if self.communicationType == "Topic": - topicType, topicStr, _ = rostopic.get_topic_class( - self.address, - ) # get topic class - try: - rospy.wait_for_message( - topicStr, - topicType, - ) # try to get a message from that topic - return True - except Exception: - return False - - # Check if the service is up - if self.communicationType == "Service": - return rosservice.waitForService( - self.address, - ) # Wait for the service to be up - - # Check if the action server is up - if self.communicationType == "Action": - # action client - topicType, topicStr, _ = rostopic.get_topic_class( - self.address + "/feedback", - ) - try: - # Wait for a message from the topic - rospy.wait_for_message(topicStr, topicType) - return True - except Exception: - return False - - # Send data over the communication interface and pass in the return values into the check function - def VerifyData(self, args, checkFunction): - result = "" - - if self.communicationType == "Topic": - # Get the class of the topic - topicType, topicStr, _ = rostopic.get_topic_class(self.address) - try: - # Get a message from the topic - result = rospy.wait_for_message(topicStr, topicType) - except Exception: - return False - - if self.communicationType == "Service": - try: - # Get a message form the service - result = rosservice.call_service(self.address, args) - except Exception: - return False - - if self.communicationType == "Action": - # Get the class of the topic, remember an action will publish its results to a topic with /goal at the end - topicType, topicStr, _ = rostopic.get_topic_class( - self.address + "/feedback", - ) - try: - # Wait for a message from the topic - result = rospy.wait_for_message(topicStr, topicType) - except Exception: - return False - - return checkFunction(args, result) - - def runCommand(self, args): - # use a dictionary - if self.communicationType == "Topic": - topicType, topicStr, _ = rostopic.get_topic_class(self.address) - if self.communicationType == "Service": - # Do something - self - if self.communicationType == "Action": - # Do something - self - return False From 47ef621dfba60138dd2451a2619c1b4f388cd689 Mon Sep 17 00:00:00 2001 From: keithmk Date: Fri, 16 Feb 2024 15:58:43 -0500 Subject: [PATCH 18/26] Organized files and added comments --- .../mil_tools/scripts/mil-preflight/main.py | 192 +++++++++++------- .../mil_tools/scripts/mil-preflight/menus.py | 41 +++- .../mil_tools/scripts/mil-preflight/tests.py | 62 ++++++ 3 files changed, 215 insertions(+), 80 deletions(-) create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/tests.py diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py index 5bd578b4d..2b980add0 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py @@ -1,69 +1,42 @@ +################################################################################ +# File name: main.py +# Author: Keith Khadar +# Description: This file is the entry point to preflight. +################################################################################ +# ----- Imports ----- # +# ----- Preflight -----# +# ----- Console -----# import subprocess import time import menus + +# ----- ROS -----# import rosnode import rospy import rostopic +import tests from PyInquirer import prompt from rich.console import Console from rich.progress import Progress, track +from rich.table import Table -# Custom message imports -from subjugator_msgs.msg import ThrusterCmd - +# ----- Variables ----- # +# ----- Timeouts -----# node_timout = 5 # seconds topic_timout = 5 # seconds actuator_timout = 5 # seconds +# ----- Reports -----# +report = [] -hardwareChecklist = [ - { - "type": "checkbox", - "message": "Hardware Checklist:", - "name": "HardwareTests: \nPlease check that all of the following are in working order. \nYou cannot continue until everything has been checked.", - "choices": [ - {"name": "check thing 1"}, - {"name": "check thing 2"}, - {"name": "check thing 3"}, - {"name": "check thing 4"}, - {"name": "check thing 5"}, - ], - }, -] - -topics = [ - # "/camera/front/right/image_raw", - # "/camera/down/image_raw", - # "/camera/front/left/image_raw", - # "/dvl", - # "/depth", - # "/imu/data_raw", - # "/imu/mag", -] - -nodes = ["/odom_estimator"] - -actuatorsList = [ - ( - "/thrusters/thrust", - [ - ThrusterCmd(name="FLH", thrust=60.0), - ThrusterCmd(name="FLV", thrust=60.0), - ThrusterCmd(name="FRH", thrust=60.0), - ThrusterCmd(name="FRV", thrust=60.0), - ThrusterCmd(name="BLH", thrust=60.0), - ThrusterCmd(name="BLV", thrust=60.0), - ThrusterCmd(name="BRH", thrust=60.0), - ThrusterCmd(name="BRV", thrust=60.0), - ], - ), -] + +# ----- Main Routine ----- # def main(): # Clear Screen and Display Start menu - subprocess.run("clear", shell=True) + clear_screen() # Print Info about Preflight Console().print(menus.info_page) @@ -75,6 +48,8 @@ def main(): # Select the mode and run it if mode == "Run Preflight Full Test": fullTest() + if mode == "View Report": + viewReport() if mode == "Exit": subprocess.run("clear", shell=True) return @@ -83,28 +58,40 @@ def main(): main() +# ----- Subroutines ----- # + +# ----- Modes -----# + + def fullTest(): ### Complete the hardware tests ### - while True: - subprocess.run("clear", shell=True) - answers = prompt(hardwareChecklist) + # Clear the screen and display the hardware checklist + clear_screen() + Console().print(menus.hardware_desc) + respond = prompt(menus.hardwareChecklist) - # If everything has been checked off - if len(next(iter(answers.values()))) == 5: - break + # Filter the response and store checklist to the report + answers = [] + for i in range(len(tests.hardware)): + if tests.hardware[i] in next(iter(respond.values())): + answers.append((tests.hardware[i], True)) else: - menu_ans = prompt(menus.incomplete_continue) - if next(iter(menu_ans.values())) is True: - # Continue even though everything has not been checked off - break - else: - # Go back to main menu - return + answers.append((tests.hardware[i], False)) + createResult(answers, "Hardware Checklist") + + # Check if the list is incomplete. If so prompt user for comfirmation to continue + if len(next(iter(respond.values()))) != len(tests.hardware): + menu_ans = prompt(menus.incomplete_continue) + if next(iter(menu_ans.values())) is False: + return ### Complete Software Tests ### - subprocess.run("clear", shell=True) + # Clear the screen + clear_screen() + + # Check that ROS is running! try: rostopic._check_master() except Exception: @@ -112,26 +99,37 @@ def fullTest(): menu_ans = prompt(menus.press_anykey) return + # Initialize the ROS node rospy.init_node("preflight") + # Print Node Screen description + Console().print(menus.node_desc) + # Check Nodes answers = [] - for node in track(nodes, description="Checking Nodes..."): + for node in track(tests.nodes, description="Checking Nodes..."): # Try and ping the nodes try: answers.append((node, rosnode.rosnode_ping(node, node_timout))) except Exception: answers.append((node, False)) - print_results(answers) + # Clear the screen, print and save the response to the report + print_results(answers, "Node Liveliness") + + # Prompt the user to continue to next test menu_ans = prompt(menus.continue_question) if next(iter(menu_ans.values())) is False: # Go back to main menu return + # Print Topic screen description + clear_screen() + Console().print(menus.topic_desc) + # Check Topics answers = [] - for topic in track(topics, description="Checking Topics..."): + for topic in track(tests.topics, description="Checking Topics..."): # Check for messages on the topics try: topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class @@ -140,21 +138,26 @@ def fullTest(): topicType, topic_timout, ) # try to get a message from that topic - answers.append({topic: True}) + answers.append((topic, True)) except Exception: - answers.append({topic: False}) - print_results(answers) + answers.append((topic, False)) + + # Clear the screen, print and save the response to the report + print_results(answers, "Topic Liveliness") + # Prompt the user to continue to next test menu_ans = prompt(menus.continue_question) if next(iter(menu_ans.values())) is False: # Go back to main menu return ### Actuators Test ### + # Print Actuators Screen description subprocess.run("clear", shell=True) + Console().print(menus.node_desc) answers = [] - for actuator in actuatorsList: + for actuator in tests.actuatorsList: try: # Confirm that it is safe to run this actuator Console().print(menus.safety_check, actuator[0]) @@ -185,18 +188,57 @@ def fullTest(): except Exception: answers.append((actuator[0], False)) - print_results(answers) - menu_ans = prompt(menus.press_anykey) + # Clear the screen, print and save the response to the report + print_results(answers, "Actuator Tests") + prompt(menus.press_anykey) + return + + +def viewReport(): + # Clear the screen + clear_screen() + + # Check that there is a report + if len(report) == 0: + Console().print( + "[bold]No report![/].\nPlease generate a report by running a full test.", + ) + prompt(menus.press_anykey) + return + # Generate the report + for result in report: + Console().print(result) + prompt(menus.press_anykey) return -def print_results(systems): +# ----- Helper -----# + + +def createResult(systems, name): + # Generates a table to hold information about each system + result = Table(title=f"[bold]{name}[/]") + result.add_column("System Name", justify="center", style="cyan", no_wrap=True) + result.add_column("Status", justify="center", style="magenta", no_wrap=True) + + # Populates the table + for system, status in systems: + status_text = "[green]✔[/] Working" if status else "[red]❌[/] Not Working" + result.add_row(system, status_text) + report.append(result) + + return result + + +def print_results(systems, name): + clear_screen() + result = createResult(systems, name) + Console().print(result) + + +def clear_screen(): subprocess.run("clear", shell=True) - for name, status in systems: - if status: - Console().print(f"{name}: [green]✔[/] Working") - else: - Console().print(f"{name}: [red]❌[/] Not Working") + Console().print(menus.title) if __name__ == "__main__": diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py b/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py index 01ab69f31..16940bc08 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py @@ -1,18 +1,22 @@ ################################################################################ # File name: menus.py # Author: Keith Khadar -# Description: This file is used to store all the menus used by prefligh +# Description: This file is used to store all the menus used by preflight ################################################################################ - +# ----- Imports -----# +import tests # ----- Home Page -----# -info_page = """ +title = """ [bold green]Preflight Program - Autonomous Robot Verification[/bold green] +""" +info_page = """ Welcome to the Preflight Program, a tool inspired by the preflight checklists used by pilots before flying a plane. This program is designed to verify the functionality of all software and hardware systems on your autonomous robot. It ensures that everything is in working order, allowing you to safely deploy your robot with confidence.\n [italic]Authors:[/italic] Keith Khadar Anthony Liao -Joshua Thomas\n +Joshua Thomas +Maanas Kotha\n """ @@ -44,6 +48,7 @@ "type": "confirm", "name": "continue", "message": "Press any key to continue.", + "confirm": False, }, ] @@ -62,9 +67,35 @@ }, ] + +# ----- Software Screen -----# +node_desc = """ +Welcome to the [bold]ROS Node Liveliness Test screen[/]. This screen allows you to verify the liveliness of ROS nodes within the system. ROS nodes are essential components responsible for communication and control within the robot\'s architecture. Use this screen to ensure that all necessary nodes are running and responsive for proper system functionality. +""" +topic_desc = """ +Welcome to the Topic Monitoring screen. This screen allows you to monitor the topics in the ROS system. In a ROS (Robot Operating System) environment, topics serve as channels through which nodes communicate by publishing and subscribing to messages. Monitoring topics enables you to verify that sensors are actively publishing their data. +""" + +# ----- Hardware Screen -----# +hardware_desc = """ +Welcome to the [bold]Hardware Inspection Checklist[/] page of our preflight app! This checklist is designed to ensure that all critical hardware components of your robot are thoroughly inspected before each operation. By completing this checklist, you contribute to the safety and reliability of the robot during its mission. Please carefully examine each item listed below to verify its condition and functionality. +""" +hardwareChecklist = [ + { + "type": "checkbox", + "message": "Hardware Checklist:", + "name": "HardwareTests: \nPlease check that all of the following are in working order.", + "choices": [{"name": item} for item in tests.hardware], + }, +] + # ----- Actuators Screen -----# +actuator_desc = """ +Welcome to the [bold]Actuator Test Screen[/]. This screen allows you to test the functionality of various actuators on the robot. Actuators play a crucial role in the movement and operation of the robot. Use this screen with caution and follow the instructions carefully to avoid any accidents or damage to the robot. +\n[bold red]Caution:[/bold red] Actuators can be dangerous if mishandled. Please be careful when testing them, as they have the potential to cause harm or injury. For example, thrusters, when spinning, could chop off someone's finger. Always follow safety protocol and guidelines. +""" safety_check = """ -MAKE SURE THAT EVERYONE'S FINGERS ARE CLEAR!! Is it safe to run the following actuator? +[bold][yellow]Ensure that all fingers are clear of the area![/yellow][/bold] Is it safe to operate the following actuator? """ actuator_check = """ diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py b/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py new file mode 100644 index 000000000..cd976c044 --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py @@ -0,0 +1,62 @@ +################################################################################ +# File name: tests.py +# Author: Keith Khadar +# Description: This file is used to store tests used by Preflight. If you want +# add tests you would add them here. +################################################################################ + +# ----- Actuator Tests ----- # +# Add tests here for actuators. These will be turned on and the user +# will confirm their operation. Also include any custom message +# imports here. + +# Thruster Messages +from subjugator_msgs.msg import ThrusterCmd + +actuatorsList = [ + ( + "/thrusters/thrust", + [ + ThrusterCmd(name="FLH", thrust=60.0), + ThrusterCmd(name="FLV", thrust=60.0), + ThrusterCmd(name="FRH", thrust=60.0), + ThrusterCmd(name="FRV", thrust=60.0), + ThrusterCmd(name="BLH", thrust=60.0), + ThrusterCmd(name="BLV", thrust=60.0), + ThrusterCmd(name="BRH", thrust=60.0), + ThrusterCmd(name="BRV", thrust=60.0), + ], + ), +] + +# ----- Hardware Tests ----- # +# Add tests here for things that need to be physically inspected +hardware = [ + "Setup and connect to Network Box.", + "Roll Tether and Connect it to network box. (DO NOT USE POE, Power-Over-Ethernet).", + "Connect Sub to the tether. (NOT POE).", + "Connect battery alarm. Power on Sub.", + "SSH into Sub.", + "Start tmux.", + "Grease O-rings with Molykote 55 every time a pressure vessel is closed.", + "Deploy sub. (Check for bubbles coming out of every pressure vessel, make sure buoyancy is correct)", +] + + +# ----- Software Tests ----- # +# Add tests here for software systems like sensors whose operations +# need to be verified. + +# ----- Nodes -----# +nodes = ["/odom_estimator"] + +# ----- Topics -----# +topics = [ + "/camera/front/right/image_raw", + "/camera/down/image_raw", + "/camera/front/left/image_raw", + "/dvl", + "/depth", + "/imu/data_raw", + "/imu/mag", +] From f85eddcf2bffb477203dfbdcbd7408a6f640d76c Mon Sep 17 00:00:00 2001 From: keithmk Date: Fri, 16 Feb 2024 16:01:44 -0500 Subject: [PATCH 19/26] Removed Typer from requirements.txt --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1a77082c7..c271ea760 100644 --- a/requirements.txt +++ b/requirements.txt @@ -32,7 +32,6 @@ myst-parser==0.18.0 sphinx-copybutton==0.5.0 # Terminal -typer[all]==4.8.0 PyInquirer==1.0.3 # External Devices From afc6e306897c0f4842af8ece4f696abf420a79e7 Mon Sep 17 00:00:00 2001 From: Anthony Liao Date: Tue, 20 Feb 2024 00:32:18 -0500 Subject: [PATCH 20/26] added readme, updated main to run documentation --- .../mil_tools/scripts/mil-preflight/README.md | 23 +++++++++++++++++++ .../mil_tools/scripts/mil-preflight/main.py | 22 +++++++++++++++++- .../mil_tools/scripts/mil-preflight/menus.py | 2 +- preflight-test/bin/python | 1 - preflight-test/bin/python3 | 1 - preflight-test/lib64 | 1 - preflight-test/pyvenv.cfg | 3 --- 7 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/README.md delete mode 120000 preflight-test/bin/python delete mode 120000 preflight-test/bin/python3 delete mode 120000 preflight-test/lib64 delete mode 100644 preflight-test/pyvenv.cfg diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/README.md b/mil_common/utils/mil_tools/scripts/mil-preflight/README.md new file mode 100644 index 000000000..830fc5f9b --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/README.md @@ -0,0 +1,23 @@ +# Preflight- Autonomous Robot Verification +## How to Use +Simply type "preflight" anywhere in the MIL directory. Make sure that a robot is connected and running or gazebo is running. To edit the hardware tests list and the automated software tests, edit the tests.py file in mil/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py +## Description +Preflight is an automated testing tool that should be run after turning on and connecting to the robot to run a prelaunch hardware checklist and automated software checklist. + +In the current version 1.0, Run Specific Test is not yet implemented. +### There are three types of automated software tests +#### Actuators +This test will prompt the user to enable physical moving actuators on the robot. Make sure that the area is cleared and the robot won't damage itself or others nearby. The user will have to watch and validate that they move as expected personally. + +To add an actuator test, add a topic with a list of commands and import the module it comes from. See the thrusters example for reference in tests.py +#### Nodes +A ROS Node is a live process currently running and performing a task. They communicate with each other through topics, services, and messages, etc. This test will ensure all listed ROS Nodes are running and alive as expected. + +To add a Node test, add a node to the list in tests.py +#### Topics +ROS Topics act as a channel for ROS Nodes to communicate by publishing and subscribing to messages. These tests check to verify that data is being published to these topics, ensuring that sensors under the listed topics are properly reading publishing data. + +To add a Topic test, add a topic to the list in tests.py + +### Dependencies +ROS, Rich, PyInquirer diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py index 2b980add0..0b8b14d29 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py @@ -1,13 +1,14 @@ ################################################################################ # File name: main.py # Author: Keith Khadar -# Description: This file is the entry point to preflight. +# Description: This file is the entry point to preflight. Version 1.0 ################################################################################ # ----- Imports ----- # # ----- Preflight -----# # ----- Console -----# import subprocess import time +from pathlib import Path import menus @@ -18,6 +19,7 @@ import tests from PyInquirer import prompt from rich.console import Console +from rich.markdown import Markdown from rich.progress import Progress, track from rich.table import Table @@ -50,6 +52,8 @@ def main(): fullTest() if mode == "View Report": viewReport() + if mode == "View Documentation": + viewDocumentation() if mode == "Exit": subprocess.run("clear", shell=True) return @@ -212,6 +216,22 @@ def viewReport(): return +def viewDocumentation(): + # Clear the screen + clear_screen() + + # Find path to README from current directory + mod_path = Path(__file__).parent + rel_path = "README.md" + src_path = (mod_path / rel_path).resolve() + # Print the documentation + with open(src_path, "r+") as help_file: + Console().print(Markdown(help_file.read())) + + prompt(menus.press_anykey) + return + + # ----- Helper -----# diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py b/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py index 16940bc08..111a987b9 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py @@ -1,7 +1,7 @@ ################################################################################ # File name: menus.py # Author: Keith Khadar -# Description: This file is used to store all the menus used by preflight +# Description: This file is used to store all the menus used by preflight. Version 1.0 ################################################################################ # ----- Imports -----# import tests diff --git a/preflight-test/bin/python b/preflight-test/bin/python deleted file mode 120000 index b8a0adbbb..000000000 --- a/preflight-test/bin/python +++ /dev/null @@ -1 +0,0 @@ -python3 \ No newline at end of file diff --git a/preflight-test/bin/python3 b/preflight-test/bin/python3 deleted file mode 120000 index ae65fdaa1..000000000 --- a/preflight-test/bin/python3 +++ /dev/null @@ -1 +0,0 @@ -/usr/bin/python3 \ No newline at end of file diff --git a/preflight-test/lib64 b/preflight-test/lib64 deleted file mode 120000 index 7951405f8..000000000 --- a/preflight-test/lib64 +++ /dev/null @@ -1 +0,0 @@ -lib \ No newline at end of file diff --git a/preflight-test/pyvenv.cfg b/preflight-test/pyvenv.cfg deleted file mode 100644 index 853404e23..000000000 --- a/preflight-test/pyvenv.cfg +++ /dev/null @@ -1,3 +0,0 @@ -home = /usr/bin -include-system-site-packages = false -version = 3.8.10 From da1528abe4e9c0db1433d637ab2cf1de983f2ad3 Mon Sep 17 00:00:00 2001 From: andrespulido8 Date: Fri, 23 Feb 2024 20:39:36 +0000 Subject: [PATCH 21/26] Testing changes --- mil_common/utils/mil_tools/scripts/mil-preflight/main.py | 2 +- .../utils/mil_tools/scripts/mil-preflight/tests.py | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py index 0b8b14d29..a8eeb6c12 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py @@ -27,7 +27,7 @@ # ----- Timeouts -----# node_timout = 5 # seconds topic_timout = 5 # seconds -actuator_timout = 5 # seconds +actuator_timout = 1.5 # seconds # ----- Reports -----# report = [] diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py b/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py index cd976c044..6edff2d11 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py @@ -17,14 +17,7 @@ ( "/thrusters/thrust", [ - ThrusterCmd(name="FLH", thrust=60.0), - ThrusterCmd(name="FLV", thrust=60.0), - ThrusterCmd(name="FRH", thrust=60.0), - ThrusterCmd(name="FRV", thrust=60.0), - ThrusterCmd(name="BLH", thrust=60.0), - ThrusterCmd(name="BLV", thrust=60.0), - ThrusterCmd(name="BRH", thrust=60.0), - ThrusterCmd(name="BRV", thrust=60.0), + ThrusterCmd(name="FLH", thrust=10.0), ], ), ] From 270a1ccb96eaa4693b2ab0c78a1936a572603431 Mon Sep 17 00:00:00 2001 From: keithmk Date: Sun, 17 Mar 2024 17:20:59 -0400 Subject: [PATCH 22/26] starting to add axros --- .../mil_tools/scripts/mil-preflight/main.py | 300 +++++++++++++----- .../mil_tools/scripts/mil-preflight/menus.py | 61 +++- .../mil_tools/scripts/mil-preflight/tests.py | 60 +++- 3 files changed, 316 insertions(+), 105 deletions(-) diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py index a8eeb6c12..7f5526c86 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py @@ -6,6 +6,8 @@ # ----- Imports ----- # # ----- Preflight -----# # ----- Console -----# +# ----- Async -----# +import asyncio import subprocess import time from pathlib import Path @@ -13,10 +15,10 @@ import menus # ----- ROS -----# -import rosnode import rospy import rostopic import tests +from axros import NodeHandle, Subscriber from PyInquirer import prompt from rich.console import Console from rich.markdown import Markdown @@ -24,19 +26,16 @@ from rich.table import Table # ----- Variables ----- # -# ----- Timeouts -----# -node_timout = 5 # seconds -topic_timout = 5 # seconds -actuator_timout = 1.5 # seconds - # ----- Reports -----# + + report = [] +nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) # ----- Main Routine ----- # +async def main(): - -def main(): # Clear Screen and Display Start menu clear_screen() @@ -45,21 +44,26 @@ def main(): # Print start select menu option = prompt(menus.start_menu) - mode = next(iter(option.values())) - - # Select the mode and run it - if mode == "Run Preflight Full Test": - fullTest() - if mode == "View Report": - viewReport() - if mode == "View Documentation": - viewDocumentation() - if mode == "Exit": - subprocess.run("clear", shell=True) - return + try: + mode = next(iter(option.values())) + # Select the mode and run it + if mode == "Run Preflight Full Test": + await fullTest() + if mode == "View Report": + viewReport() + if mode == "Run Specific Test": + await specificTest() + if mode == "View Documentation": + viewDocumentation() + if mode == "Exit": + subprocess.run("clear", shell=True) + return + + except Exception: + pass # Return to this screen after running the selected mode - main() + await main() # ----- Subroutines ----- # @@ -67,25 +71,28 @@ def main(): # ----- Modes -----# -def fullTest(): - ### Complete the hardware tests ### +async def fullTest(): + # Clear the report + report.clear() + + ### Complete the setup tests ### - # Clear the screen and display the hardware checklist + # Clear the screen and display the setup checklist clear_screen() - Console().print(menus.hardware_desc) - respond = prompt(menus.hardwareChecklist) + Console().print(menus.setup_desc) + respond = prompt(menus.setupChecklist) # Filter the response and store checklist to the report answers = [] - for i in range(len(tests.hardware)): - if tests.hardware[i] in next(iter(respond.values())): - answers.append((tests.hardware[i], True)) + for i in range(len(tests.setup)): + if tests.setup[i] in next(iter(respond.values())): + answers.append((tests.setup[i], True)) else: - answers.append((tests.hardware[i], False)) - createResult(answers, "Hardware Checklist") + answers.append((tests.setup[i], False)) + createResult(answers, "Setup Checklist") - # Check if the list is incomplete. If so prompt user for comfirmation to continue - if len(next(iter(respond.values()))) != len(tests.hardware): + # Check if the list is incomplete. If so prompt user for confirmation to continue + if len(next(iter(respond.values()))) != len(tests.setup): menu_ans = prompt(menus.incomplete_continue) if next(iter(menu_ans.values())) is False: return @@ -110,16 +117,20 @@ def fullTest(): Console().print(menus.node_desc) # Check Nodes - answers = [] - for node in track(tests.nodes, description="Checking Nodes..."): - # Try and ping the nodes - try: - answers.append((node, rosnode.rosnode_ping(node, node_timout))) - except Exception: - answers.append((node, False)) + + # Setup AXROS + async with nh: + answers = [] + tasks = [check_node(node, answers) for node in tests.nodes] + for task in track( + asyncio.as_completed(tasks), + description="Checking Nodes...", + total=len(tasks), + ): + await task # Clear the screen, print and save the response to the report - print_results(answers, "Node Liveliness") + # print_results(answers, "Node Liveliness") # Prompt the user to continue to next test menu_ans = prompt(menus.continue_question) @@ -135,16 +146,7 @@ def fullTest(): answers = [] for topic in track(tests.topics, description="Checking Topics..."): # Check for messages on the topics - try: - topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class - rospy.wait_for_message( - topicStr, - topicType, - topic_timout, - ) # try to get a message from that topic - answers.append((topic, True)) - except Exception: - answers.append((topic, False)) + await check_topic(topic, answers) # Clear the screen, print and save the response to the report print_results(answers, "Topic Liveliness") @@ -162,39 +164,113 @@ def fullTest(): answers = [] for actuator in tests.actuatorsList: - try: - # Confirm that it is safe to run this actuator - Console().print(menus.safety_check, actuator[0]) - menu_ans = prompt(menus.continue_question) - if next(iter(menu_ans.values())) is False: - # Go back to main menu - return - - # Create a publisher - topicType, topicStr, _ = rostopic.get_topic_class(actuator[0]) - pub = rospy.Publisher(topicStr, topicType, queue_size=10) - - # Publish to the topic for the specified timeout - with Progress() as progress: - t_start = time.time() - t_end = t_start + actuator_timout - t_prev = time.time() - task = progress.add_task("Running", total=(t_end - t_start)) - while time.time() <= t_end: - pub.publish(actuator[1]) - progress.update(task, advance=(time.time() - t_prev)) - t_prev = time.time() - progress.update(task, advance=t_end) - - # Ask if the actuator worked - Console().print(menus.actuator_check) - answers.append((actuator[0], next(iter(prompt(menus.yes_no).values())))) - except Exception: - answers.append((actuator[0], False)) + check_actuator(actuator, answers) # Clear the screen, print and save the response to the report print_results(answers, "Actuator Tests") - prompt(menus.press_anykey) + prompt(menus.press_anykey_menu_return) + return + + +async def specificTest(): + # Clear the report + report.clear() + + # Clear the screen and display the node checklist + clear_screen() + + # Check that ROS is running! + try: + rostopic._check_master() + except Exception: + Console().print("[bold] ROS not running! Please try again later[/]") + menu_ans = prompt(menus.press_anykey) + return + + # Initialize the ROS node + rospy.init_node("preflight") + + # Clear the screen and display the node checklist + clear_screen() + Console().print(menus.specific_desc) + respond = prompt(menus.nodeChecklist) + + # Filter the response and store checklist to the report + nodes = [] + for i in range(len(tests.nodes)): + if tests.nodes[i] in next(iter(respond.values())): + nodes.append(tests.nodes[i]) + + # Print Node Screen description + Console().print(menus.node_desc) + + # Check Nodes + answers = [] + for node in track(nodes, description="Checking Nodes..."): + # Try and ping the nodes + await check_node(node, answers) + + # Clear the screen, print and save the response to the report + print_results(answers, "Node Liveliness") + + # Prompt the user to continue to next test + menu_ans = prompt(menus.continue_question) + if next(iter(menu_ans.values())) is False: + # Go back to main menu + return + + # Clear the screen and display the topic checklist + clear_screen() + Console().print(menus.specific_desc) + respond = prompt(menus.topicChecklist) + + # Filter the response and store checklist to the report + topics = [] + for i in range(len(tests.topics)): + if tests.topics[i] in next(iter(respond.values())): + topics.append(tests.topics[i]) + + # Print Topic screen description + clear_screen() + Console().print(menus.topic_desc) + + # Check Topics + answers = [] + for topic in track(topics, description="Checking Topics..."): + # Check for messages on the topics + await check_topic(topic, answers) + + # Clear the screen, print and save the response to the report + print_results(answers, "Topic Liveliness") + + # Prompt the user to continue to next test + menu_ans = prompt(menus.continue_question) + if next(iter(menu_ans.values())) is False: + # Go back to main menu + return + + # Clear the screen and display the actuator checklist + clear_screen() + Console().print(menus.specific_desc) + respond = prompt(menus.actuatorChecklist) + + # Filter the response and store checklist to the report + actuators = [] + for i in range(len(tests.actuatorsList)): + if tests.actuatorsList[i][0] in next(iter(respond.values())): + actuators.append(tests.actuatorsList[i]) + + # Print Actuators Screen description + subprocess.run("clear", shell=True) + Console().print(menus.node_desc) + + answers = [] + for actuator in actuators: + check_actuator(actuator, answers) + + # Clear the screen, print and save the response to the report + print_results(answers, "Actuator Tests") + prompt(menus.press_anykey_menu_return) return @@ -212,7 +288,7 @@ def viewReport(): # Generate the report for result in report: Console().print(result) - prompt(menus.press_anykey) + prompt(menus.press_anykey_menu_return) return @@ -228,7 +304,7 @@ def viewDocumentation(): with open(src_path, "r+") as help_file: Console().print(Markdown(help_file.read())) - prompt(menus.press_anykey) + prompt(menus.press_anykey_menu_return) return @@ -243,7 +319,7 @@ def createResult(systems, name): # Populates the table for system, status in systems: - status_text = "[green]✔[/] Working" if status else "[red]❌[/] Not Working" + status_text = "[green]✔ Working[/]" if status else "[red]❌ Not Working[/]" result.add_row(system, status_text) report.append(result) @@ -261,5 +337,59 @@ def clear_screen(): Console().print(menus.title) +async def check_node(node, results): + try: + print(node) + print(nh.lookup_node(node)) + results.append((node, bool(nh.lookup_node(node)))) + except Exception: + results.append((node, False)) + + +async def check_topic(topic, results): + try: + topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class + sub = Subscriber(nh, topicStr, topicType) + + async with sub: + await asyncio.wait_for(sub.get_next_message(), tests.topic_timeout) + results.append((topic, True)) + except Exception: + results.append((topic, False)) + + +def check_actuator(actuator, results): + try: + # Confirm that it is safe to run this actuator + Console().print(menus.safety_check, actuator[0]) + menu_ans = prompt(menus.continue_question) + if next(iter(menu_ans.values())) is False: + # Go back to main menu + return + + # Create a publisher + topicType, topicStr, _ = rostopic.get_topic_class(actuator[1][0]) + pub = rospy.Publisher(topicStr, topicType, queue_size=10) + + # Publish to the topic for the specified timeout + with Progress() as progress: + t_start = time.time() + t_end = t_start + tests.actuator_timeout + t_prev = time.time() + task = progress.add_task("Running", total=(t_end - t_start)) + while time.time() <= t_end: + pub.publish(actuator[1][1]) + progress.update(task, advance=(time.time() - t_prev)) + t_prev = time.time() + progress.update(task, advance=t_end) + + # Ask if the actuator worked + Console().print(menus.actuator_check) + results.append((actuator[0], next(iter(prompt(menus.yes_no).values())))) + except Exception: + Console().print(menus.actuator_failed) + results.append((actuator[0], False)) + + if __name__ == "__main__": - main() + asyncio.run(main()) diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py b/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py index 111a987b9..fe58fd040 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py @@ -51,6 +51,14 @@ "confirm": False, }, ] +press_anykey_menu_return = [ + { + "type": "confirm", + "name": "continue", + "message": "Press any key to return to the menu.", + "confirm": False, + }, +] incomplete_continue = [ { @@ -76,16 +84,37 @@ Welcome to the Topic Monitoring screen. This screen allows you to monitor the topics in the ROS system. In a ROS (Robot Operating System) environment, topics serve as channels through which nodes communicate by publishing and subscribing to messages. Monitoring topics enables you to verify that sensors are actively publishing their data. """ -# ----- Hardware Screen -----# -hardware_desc = """ -Welcome to the [bold]Hardware Inspection Checklist[/] page of our preflight app! This checklist is designed to ensure that all critical hardware components of your robot are thoroughly inspected before each operation. By completing this checklist, you contribute to the safety and reliability of the robot during its mission. Please carefully examine each item listed below to verify its condition and functionality. +nodeChecklist = [ + { + "type": "checkbox", + "message": "Node Checklist:", + "name": "NodeChecklist: \nPlease check that all of the following are in working order.", + "choices": [{"name": item} for item in tests.nodes], + }, +] + +topicChecklist = [ + { + "type": "checkbox", + "message": "Topic Checklist:", + "name": "TopicChecklist: \nPlease check that all of the following are in working order.", + "choices": [{"name": item} for item in tests.topics], + }, +] + +# ----- Setup Screen -----# +setup_desc = """ +Welcome to the [bold]Setup Checklist[/] page of our preflight app! This checklist is designed to ensure that all critical hardware components of your robot are thoroughly inspected before each operation. By completing this checklist, you contribute to the safety and reliability of the robot during its mission. Please carefully examine each item listed below to verify its condition and functionality. + +Go through each item and check it off. Use the arrow keys to select and item and press space to check it off. Once all items have been checked press enter to continue. You can always review what items you checked off later in the report section of the main menu. + """ -hardwareChecklist = [ +setupChecklist = [ { "type": "checkbox", - "message": "Hardware Checklist:", + "message": "Setup Checklist:", "name": "HardwareTests: \nPlease check that all of the following are in working order.", - "choices": [{"name": item} for item in tests.hardware], + "choices": [{"name": item} for item in tests.setup], }, ] @@ -101,3 +130,23 @@ actuator_check = """ Did the actuator work? """ + +actuator_failed = """ +Actuator failed! +""" + +actuatorChecklist = [ + { + "type": "checkbox", + "message": "Actuator Checklist:", + "name": "ActuatorTests: \nPlease check that all of the following are in working order.", + "choices": [{"name": item[0]} for item in tests.actuatorsList], + }, +] + +# ----- Specific Test Screen -----# +specific_desc = """ +Welcome to the [bold]Specific Test[/] page of our preflight app! Here you can specify which tests you want to run. This can be useful for debugging parts of the robot. +You can use the arrow keys to select which tests you want to run (use the spacebar to select). Once you are ready you can press enter to run those tests! + +""" diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py b/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py index 6edff2d11..f1f961e68 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py @@ -5,6 +5,7 @@ # add tests you would add them here. ################################################################################ + # ----- Actuator Tests ----- # # Add tests here for actuators. These will be turned on and the user # will confirm their operation. Also include any custom message @@ -13,24 +14,49 @@ # Thruster Messages from subjugator_msgs.msg import ThrusterCmd +# ----- Timeouts ----- # +node_timeout = 5 # seconds +topic_timeout = 5 # seconds +actuator_timeout = 1.5 # seconds + actuatorsList = [ ( - "/thrusters/thrust", - [ - ThrusterCmd(name="FLH", thrust=10.0), - ], + "FLH Thruster Test", + ("/thrusters/thrust", [ThrusterCmd(name="FLH", thrust=10.0)]), + ), + ( + "FRH Thruster Test", + ("/thrusters/thrust", [ThrusterCmd(name="FRH", thrust=10.0)]), + ), + ( + "BLH Thruster Test", + ("/thrusters/thrust", [ThrusterCmd(name="BLH", thrust=10.0)]), + ), + ( + "BRH Thruster Test", + ("/thrusters/thrust", [ThrusterCmd(name="BRH", thrust=10.0)]), + ), + ( + "FLV Thruster Test", + ("/thrusters/thrust", [ThrusterCmd(name="FLV", thrust=10.0)]), + ), + ( + "FRV Thruster Test", + ("/thrusters/thrust", [ThrusterCmd(name="FRV", thrust=10.0)]), + ), + ( + "BLV Thruster Test", + ("/thrusters/thrust", [ThrusterCmd(name="BLV", thrust=10.0)]), + ), + ( + "BRV Thruster Test", + ("/thrusters/thrust", [ThrusterCmd(name="BRV", thrust=10.0)]), ), ] -# ----- Hardware Tests ----- # -# Add tests here for things that need to be physically inspected -hardware = [ - "Setup and connect to Network Box.", - "Roll Tether and Connect it to network box. (DO NOT USE POE, Power-Over-Ethernet).", - "Connect Sub to the tether. (NOT POE).", - "Connect battery alarm. Power on Sub.", - "SSH into Sub.", - "Start tmux.", +# ----- Setup Tests ----- # +# Add tests here for things that need to be physically inspected or check before the sub is running +setup = [ "Grease O-rings with Molykote 55 every time a pressure vessel is closed.", "Deploy sub. (Check for bubbles coming out of every pressure vessel, make sure buoyancy is correct)", ] @@ -41,7 +67,13 @@ # need to be verified. # ----- Nodes -----# -nodes = ["/odom_estimator"] +nodes = [ + "/odom_estimator", + "/odom_estimator", + "/odom_estimator", + "/odom_estimator", + "/odom_estimator", +] # ----- Topics -----# topics = [ From 3ef5592a041675beb68f91aba3fb22941af21d8d Mon Sep 17 00:00:00 2001 From: keithmk Date: Sun, 17 Mar 2024 21:21:18 -0400 Subject: [PATCH 23/26] Finished implementing axros --- .../mil_tools/scripts/mil-preflight/main.py | 81 ++++++++++++------- .../mil_tools/scripts/mil-preflight/tests.py | 2 +- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py index 7f5526c86..1df2bf7f8 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py @@ -10,6 +10,7 @@ import asyncio import subprocess import time +from contextlib import suppress from pathlib import Path import menus @@ -18,7 +19,7 @@ import rospy import rostopic import tests -from axros import NodeHandle, Subscriber +from axros import NodeHandle from PyInquirer import prompt from rich.console import Console from rich.markdown import Markdown @@ -30,7 +31,6 @@ report = [] -nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) # ----- Main Routine ----- # @@ -111,7 +111,8 @@ async def fullTest(): return # Initialize the ROS node - rospy.init_node("preflight") + with suppress(Exception): + rospy.init_node("preflight") # Print Node Screen description Console().print(menus.node_desc) @@ -119,9 +120,10 @@ async def fullTest(): # Check Nodes # Setup AXROS + nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) async with nh: answers = [] - tasks = [check_node(node, answers) for node in tests.nodes] + tasks = [check_node(node, answers, nh) for node in tests.nodes] for task in track( asyncio.as_completed(tasks), description="Checking Nodes...", @@ -130,7 +132,7 @@ async def fullTest(): await task # Clear the screen, print and save the response to the report - # print_results(answers, "Node Liveliness") + print_results(answers, "Node Liveliness") # Prompt the user to continue to next test menu_ans = prompt(menus.continue_question) @@ -143,10 +145,18 @@ async def fullTest(): Console().print(menus.topic_desc) # Check Topics - answers = [] - for topic in track(tests.topics, description="Checking Topics..."): - # Check for messages on the topics - await check_topic(topic, answers) + + # Setup AXROS + nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) + async with nh: + answers = [] + tasks = [check_topic(node, answers, nh) for node in tests.topics] + for task in track( + asyncio.as_completed(tasks), + description="Checking Topics...", + total=len(tasks), + ): + await task # Clear the screen, print and save the response to the report print_results(answers, "Topic Liveliness") @@ -188,7 +198,8 @@ async def specificTest(): return # Initialize the ROS node - rospy.init_node("preflight") + with suppress(Exception): + rospy.init_node("preflight") # Clear the screen and display the node checklist clear_screen() @@ -205,10 +216,16 @@ async def specificTest(): Console().print(menus.node_desc) # Check Nodes - answers = [] - for node in track(nodes, description="Checking Nodes..."): - # Try and ping the nodes - await check_node(node, answers) + nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) + async with nh: + answers = [] + tasks = [check_node(node, answers, nh) for node in nodes] + for task in track( + asyncio.as_completed(tasks), + description="Checking Nodes...", + total=len(tasks), + ): + await task # Clear the screen, print and save the response to the report print_results(answers, "Node Liveliness") @@ -235,10 +252,16 @@ async def specificTest(): Console().print(menus.topic_desc) # Check Topics - answers = [] - for topic in track(topics, description="Checking Topics..."): - # Check for messages on the topics - await check_topic(topic, answers) + nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) + async with nh: + answers = [] + tasks = [check_topic(node, answers, nh) for node in topics] + for task in track( + asyncio.as_completed(tasks), + description="Checking Topics...", + total=len(tasks), + ): + await task # Clear the screen, print and save the response to the report print_results(answers, "Topic Liveliness") @@ -337,25 +360,23 @@ def clear_screen(): Console().print(menus.title) -async def check_node(node, results): +async def check_node(node, results, nh): try: - print(node) - print(nh.lookup_node(node)) - results.append((node, bool(nh.lookup_node(node)))) + results.append((node, bool(await nh.lookup_node(node)))) except Exception: results.append((node, False)) -async def check_topic(topic, results): - try: - topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class - sub = Subscriber(nh, topicStr, topicType) +async def check_topic(topic, results, nh): + topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class + sub = nh.subscribe(topicStr, topicType) - async with sub: + async with sub: + try: await asyncio.wait_for(sub.get_next_message(), tests.topic_timeout) - results.append((topic, True)) - except Exception: - results.append((topic, False)) + results.append((topic, True)) + except Exception: + results.append((topic, False)) def check_actuator(actuator, results): diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py b/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py index f1f961e68..91fa73b1a 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py @@ -72,7 +72,7 @@ "/odom_estimator", "/odom_estimator", "/odom_estimator", - "/odom_estimator", + "/doest_exist", ] # ----- Topics -----# From bb1dccf502884393285438e20993e5040ba076ac Mon Sep 17 00:00:00 2001 From: keithmk Date: Thu, 28 Mar 2024 00:30:24 -0400 Subject: [PATCH 24/26] Code Refactoring. Added Docs to website --- docs/reference/index.rst | 1 + docs/reference/preflight.md | 2 + .../mil_tools/scripts/mil-preflight/helper.py | 222 +++++++++++++ .../mil_tools/scripts/mil-preflight/main.py | 299 ++++-------------- .../mil_tools/scripts/mil-preflight/menus.py | 5 - .../mil-preflight/{README.md => preflight.md} | 7 +- .../mil_tools/scripts/mil-preflight/tests.py | 17 +- services.txt | 165 ---------- topics.txt | 254 --------------- 9 files changed, 301 insertions(+), 671 deletions(-) create mode 100644 docs/reference/preflight.md create mode 100644 mil_common/utils/mil_tools/scripts/mil-preflight/helper.py rename mil_common/utils/mil_tools/scripts/mil-preflight/{README.md => preflight.md} (86%) delete mode 100644 services.txt delete mode 100644 topics.txt diff --git a/docs/reference/index.rst b/docs/reference/index.rst index c63581a0c..6634f15bb 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -32,3 +32,4 @@ by MIL. These subsystems relate to a variety of processes. pneumatic sabertooth bagging + preflight diff --git a/docs/reference/preflight.md b/docs/reference/preflight.md new file mode 100644 index 000000000..a2a088fb3 --- /dev/null +++ b/docs/reference/preflight.md @@ -0,0 +1,2 @@ +```{include} ../../mil_common/utils/mil_tools/scripts/mil-preflight/preflight.md +``` diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/helper.py b/mil_common/utils/mil_tools/scripts/mil-preflight/helper.py new file mode 100644 index 000000000..bb5cf6ce9 --- /dev/null +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/helper.py @@ -0,0 +1,222 @@ +################################################################################ +# File name: helper.py +# Author: Keith Khadar +# Description: This is used to store the helper functions for preflight +################################################################################ +# ----- Imports ----- # +# ----- Console -----# +# ----- Async -----# +import asyncio +import subprocess +import time + +# ----- Misc -----# +from contextlib import suppress + +# ----- Preflight -----# +import menus + +# ----- ROS -----# +import rospy +import rostopic +import tests +from axros import NodeHandle +from PyInquirer import prompt +from rich.console import Console +from rich.progress import Progress, track +from rich.table import Table + +# ----- Variables ----- # +report = [] + + +# ----- Functions ----- # +def clear_screen(): + # Clears the screen and prints the preflight header + subprocess.run("clear", shell=True) + Console().print(menus.title) + + +def init_report(): + # Function to initialize the report + report.clear() + + +def init_ros(): + # Checks if ROS is running and initializes it. + # Returns False if ROS is not running and TRUE if the ROS node was properly setup. + + # Check that ROS is running! + try: + rostopic._check_master() + except Exception: + Console().print("[bold] ROS not running! Please try again later[/]") + prompt(menus.press_anykey) + return False + + # Initialize the ROS node + with suppress(Exception): + rospy.init_node("preflight") + return True + + +async def axros_check_nodes(nodes): + # Asynchronously check all the nodes and then print/save the results + + # Setup AXROS + nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) + + # Using async.io check all the nodes + answers = [] + async with nh: + # Create all the function calls to check_node + tasks = [check_node(node, answers, nh) for node in nodes] + + # Go through all the function calls and await them. + # Using track to display a loading bar. + for task in track( + asyncio.as_completed(tasks), + description="Checking Nodes...", + total=len(tasks), + ): + await task + + # Clear the screen, print and save the response to the report + print_results(answers, "Node Liveliness") + + +async def check_node(node, results, nh): + # Using AXROS lookup a node and save the result in the results list + + try: + results.append((node, bool(await nh.lookup_node(node)))) + except Exception: + results.append((node, False)) + + +async def axros_check_topics(topics): + # Asynchronously check all the topics and then print/save the results + + # Setup AXROS + nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) + + # Using async.io check all the topics + answers = [] + async with nh: + # Create all the function calls to check topic + tasks = [check_topic(topic, answers, nh) for topic in topics] + + # Go through all the function calls and await them. + # Using track to display a loading bar. + for task in track( + asyncio.as_completed(tasks), + description="Checking Topics...", + total=len(tasks), + ): + await task + + # Clear the screen, print and save the response to the report + print_results(answers, "Topic Liveliness") + + +async def check_topic(topic, results, nh): + # Using AXROS subscribe to a topic and wait for a message + + # Get the topic class + topicType, topicStr, _ = rostopic.get_topic_class(topic) + + # Create an AXROS subscriber + sub = nh.subscribe(topicStr, topicType) + + async with sub: + try: + await asyncio.wait_for(sub.get_next_message(), tests.topic_timeout) + results.append((topic, True)) + except Exception: + results.append((topic, False)) + + +def check_actuators(actuators): + # Check all the actuators using check_actuator + + answers = [] + for actuator in actuators: + check_actuator(actuator, answers) + + # Clear the screen, print and save the response to the report + print_results(answers, "Actuator Tests") + + +def check_actuator(actuator, results): + # Checks the actuator by publishing to a topic for a specified time + + try: + # Confirm that it is safe to run this actuator + Console().print(menus.safety_check, actuator[0]) + menu_ans = prompt(menus.continue_question) + if next(iter(menu_ans.values())) is False: + # Go back to main menu + return + + # Create a publisher + topicType, topicStr, _ = rostopic.get_topic_class(actuator[1][0]) + pub = rospy.Publisher(topicStr, topicType, queue_size=10) + + # Publish to the topic for the specified timeout + with Progress() as progress: + t_start = time.time() + t_end = t_start + tests.actuator_timeout + t_prev = time.time() + task = progress.add_task("Running", total=(t_end - t_start)) + while time.time() <= t_end: + pub.publish(actuator[1][1]) + progress.update(task, advance=(time.time() - t_prev)) + t_prev = time.time() + progress.update(task, advance=t_end) + + # Ask if the actuator worked + Console().print(menus.actuator_check) + results.append((actuator[0], next(iter(prompt(menus.yes_no).values())))) + except Exception: + Console().print(menus.actuator_failed) + results.append((actuator[0], False)) + + +def generate_report(): + # Attempts to create and display the report + + # Check that there is a report + if len(report) == 0: + Console().print( + "[bold]No report![/].\nPlease generate a report by running a full test.", + ) + prompt(menus.press_anykey) + return + # Generate the report + for result in report: + Console().print(result) + prompt(menus.press_anykey_menu_return) + + +def print_results(systems, name): + # This saves the result to the specified system and prints it + clear_screen() + result = create_result(systems, name) + Console().print(result) + + +def create_result(systems, name): + # This save the result into a RICH table + + # Generates a table to hold information about each system + result = Table(title=f"[bold]{name}[/]") + result.add_column("System Name", justify="center", style="cyan", no_wrap=True) + result.add_column("Status", justify="center", style="magenta", no_wrap=True) + + # Populates the table + for system, status in systems: + status_text = "[green]✔ Working[/]" if status else "[red]❌ Not Working[/]" + result.add_row(system, status_text) + report.append(result) + + return result diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py index 1df2bf7f8..b856c5028 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/main.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/main.py @@ -1,43 +1,32 @@ ################################################################################ # File name: main.py # Author: Keith Khadar -# Description: This file is the entry point to preflight. Version 1.0 +# Description: This file is the entry point to preflight. ################################################################################ # ----- Imports ----- # -# ----- Preflight -----# # ----- Console -----# # ----- Async -----# import asyncio import subprocess -import time -from contextlib import suppress + +# ----- Misc -----# from pathlib import Path -import menus +import helper -# ----- ROS -----# -import rospy -import rostopic +# ----- Preflight -----# +import menus import tests -from axros import NodeHandle from PyInquirer import prompt from rich.console import Console from rich.markdown import Markdown -from rich.progress import Progress, track -from rich.table import Table - -# ----- Variables ----- # -# ----- Reports -----# - - -report = [] # ----- Main Routine ----- # async def main(): # Clear Screen and Display Start menu - clear_screen() + helper.clear_screen() # Print Info about Preflight Console().print(menus.info_page) @@ -58,7 +47,9 @@ async def main(): if mode == "Exit": subprocess.run("clear", shell=True) return - + except StopIteration: + # Return if the user presses Ctrl-c + return except Exception: pass @@ -68,17 +59,16 @@ async def main(): # ----- Subroutines ----- # -# ----- Modes -----# - +# ----- Modes -----# async def fullTest(): - # Clear the report - report.clear() + + helper.init_report() ### Complete the setup tests ### # Clear the screen and display the setup checklist - clear_screen() + helper.clear_screen() Console().print(menus.setup_desc) respond = prompt(menus.setupChecklist) @@ -89,7 +79,7 @@ async def fullTest(): answers.append((tests.setup[i], True)) else: answers.append((tests.setup[i], False)) - createResult(answers, "Setup Checklist") + helper.create_result(answers, "Setup Checklist") # Check if the list is incomplete. If so prompt user for confirmation to continue if len(next(iter(respond.values()))) != len(tests.setup): @@ -98,41 +88,17 @@ async def fullTest(): return ### Complete Software Tests ### - - # Clear the screen - clear_screen() - - # Check that ROS is running! - try: - rostopic._check_master() - except Exception: - Console().print("[bold] ROS not running! Please try again later[/]") - menu_ans = prompt(menus.press_anykey) + if not helper.init_ros(): return - # Initialize the ROS node - with suppress(Exception): - rospy.init_node("preflight") + # Clear the screen + helper.clear_screen() # Print Node Screen description Console().print(menus.node_desc) # Check Nodes - - # Setup AXROS - nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) - async with nh: - answers = [] - tasks = [check_node(node, answers, nh) for node in tests.nodes] - for task in track( - asyncio.as_completed(tasks), - description="Checking Nodes...", - total=len(tasks), - ): - await task - - # Clear the screen, print and save the response to the report - print_results(answers, "Node Liveliness") + await helper.axros_check_nodes(tests.nodes) # Prompt the user to continue to next test menu_ans = prompt(menus.continue_question) @@ -141,25 +107,12 @@ async def fullTest(): return # Print Topic screen description - clear_screen() + helper.clear_screen() Console().print(menus.topic_desc) # Check Topics - # Setup AXROS - nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) - async with nh: - answers = [] - tasks = [check_topic(node, answers, nh) for node in tests.topics] - for task in track( - asyncio.as_completed(tasks), - description="Checking Topics...", - total=len(tasks), - ): - await task - - # Clear the screen, print and save the response to the report - print_results(answers, "Topic Liveliness") + await helper.axros_check_topics(tests.topics) # Prompt the user to continue to next test menu_ans = prompt(menus.continue_question) @@ -169,40 +122,51 @@ async def fullTest(): ### Actuators Test ### # Print Actuators Screen description - subprocess.run("clear", shell=True) + helper.clear_screen() Console().print(menus.node_desc) - answers = [] - for actuator in tests.actuatorsList: - check_actuator(actuator, answers) + helper.check_actuators(tests.actuatorsList) + + prompt(menus.press_anykey_menu_return) + return + + +def viewReport(): + # Clear the screen + helper.clear_screen() + + # Generate the report + helper.generate_report() + return + + +def viewDocumentation(): + # Clear the screen + helper.clear_screen() + + # Find path to README from current directory + mod_path = Path(__file__).parent + rel_path = "preflight.md" + src_path = (mod_path / rel_path).resolve() + # Print the documentation + with open(src_path, "r+") as help_file: + Console().print(Markdown(help_file.read())) - # Clear the screen, print and save the response to the report - print_results(answers, "Actuator Tests") prompt(menus.press_anykey_menu_return) return async def specificTest(): - # Clear the report - report.clear() + # Init the report + helper.init_report() # Clear the screen and display the node checklist - clear_screen() - - # Check that ROS is running! - try: - rostopic._check_master() - except Exception: - Console().print("[bold] ROS not running! Please try again later[/]") - menu_ans = prompt(menus.press_anykey) - return + helper.clear_screen() - # Initialize the ROS node - with suppress(Exception): - rospy.init_node("preflight") + helper.init_ros() # Clear the screen and display the node checklist - clear_screen() + helper.clear_screen() Console().print(menus.specific_desc) respond = prompt(menus.nodeChecklist) @@ -216,19 +180,7 @@ async def specificTest(): Console().print(menus.node_desc) # Check Nodes - nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) - async with nh: - answers = [] - tasks = [check_node(node, answers, nh) for node in nodes] - for task in track( - asyncio.as_completed(tasks), - description="Checking Nodes...", - total=len(tasks), - ): - await task - - # Clear the screen, print and save the response to the report - print_results(answers, "Node Liveliness") + await helper.axros_check_nodes(nodes=nodes) # Prompt the user to continue to next test menu_ans = prompt(menus.continue_question) @@ -237,7 +189,7 @@ async def specificTest(): return # Clear the screen and display the topic checklist - clear_screen() + helper.clear_screen() Console().print(menus.specific_desc) respond = prompt(menus.topicChecklist) @@ -248,23 +200,11 @@ async def specificTest(): topics.append(tests.topics[i]) # Print Topic screen description - clear_screen() + helper.clear_screen() Console().print(menus.topic_desc) # Check Topics - nh = NodeHandle.from_argv("Preflight_nh", "", anonymous=True) - async with nh: - answers = [] - tasks = [check_topic(node, answers, nh) for node in topics] - for task in track( - asyncio.as_completed(tasks), - description="Checking Topics...", - total=len(tasks), - ): - await task - - # Clear the screen, print and save the response to the report - print_results(answers, "Topic Liveliness") + await helper.axros_check_topics(topics=topics) # Prompt the user to continue to next test menu_ans = prompt(menus.continue_question) @@ -273,7 +213,7 @@ async def specificTest(): return # Clear the screen and display the actuator checklist - clear_screen() + helper.clear_screen() Console().print(menus.specific_desc) respond = prompt(menus.actuatorChecklist) @@ -284,133 +224,14 @@ async def specificTest(): actuators.append(tests.actuatorsList[i]) # Print Actuators Screen description - subprocess.run("clear", shell=True) + helper.clear_screen() Console().print(menus.node_desc) - answers = [] - for actuator in actuators: - check_actuator(actuator, answers) - - # Clear the screen, print and save the response to the report - print_results(answers, "Actuator Tests") - prompt(menus.press_anykey_menu_return) - return - - -def viewReport(): - # Clear the screen - clear_screen() - - # Check that there is a report - if len(report) == 0: - Console().print( - "[bold]No report![/].\nPlease generate a report by running a full test.", - ) - prompt(menus.press_anykey) - return - # Generate the report - for result in report: - Console().print(result) - prompt(menus.press_anykey_menu_return) - return - - -def viewDocumentation(): - # Clear the screen - clear_screen() - - # Find path to README from current directory - mod_path = Path(__file__).parent - rel_path = "README.md" - src_path = (mod_path / rel_path).resolve() - # Print the documentation - with open(src_path, "r+") as help_file: - Console().print(Markdown(help_file.read())) + helper.check_actuators(actuators=actuators) prompt(menus.press_anykey_menu_return) return -# ----- Helper -----# - - -def createResult(systems, name): - # Generates a table to hold information about each system - result = Table(title=f"[bold]{name}[/]") - result.add_column("System Name", justify="center", style="cyan", no_wrap=True) - result.add_column("Status", justify="center", style="magenta", no_wrap=True) - - # Populates the table - for system, status in systems: - status_text = "[green]✔ Working[/]" if status else "[red]❌ Not Working[/]" - result.add_row(system, status_text) - report.append(result) - - return result - - -def print_results(systems, name): - clear_screen() - result = createResult(systems, name) - Console().print(result) - - -def clear_screen(): - subprocess.run("clear", shell=True) - Console().print(menus.title) - - -async def check_node(node, results, nh): - try: - results.append((node, bool(await nh.lookup_node(node)))) - except Exception: - results.append((node, False)) - - -async def check_topic(topic, results, nh): - topicType, topicStr, _ = rostopic.get_topic_class(topic) # get topic class - sub = nh.subscribe(topicStr, topicType) - - async with sub: - try: - await asyncio.wait_for(sub.get_next_message(), tests.topic_timeout) - results.append((topic, True)) - except Exception: - results.append((topic, False)) - - -def check_actuator(actuator, results): - try: - # Confirm that it is safe to run this actuator - Console().print(menus.safety_check, actuator[0]) - menu_ans = prompt(menus.continue_question) - if next(iter(menu_ans.values())) is False: - # Go back to main menu - return - - # Create a publisher - topicType, topicStr, _ = rostopic.get_topic_class(actuator[1][0]) - pub = rospy.Publisher(topicStr, topicType, queue_size=10) - - # Publish to the topic for the specified timeout - with Progress() as progress: - t_start = time.time() - t_end = t_start + tests.actuator_timeout - t_prev = time.time() - task = progress.add_task("Running", total=(t_end - t_start)) - while time.time() <= t_end: - pub.publish(actuator[1][1]) - progress.update(task, advance=(time.time() - t_prev)) - t_prev = time.time() - progress.update(task, advance=t_end) - - # Ask if the actuator worked - Console().print(menus.actuator_check) - results.append((actuator[0], next(iter(prompt(menus.yes_no).values())))) - except Exception: - Console().print(menus.actuator_failed) - results.append((actuator[0], False)) - - if __name__ == "__main__": asyncio.run(main()) diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py b/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py index fe58fd040..53a3cd738 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/menus.py @@ -12,11 +12,6 @@ """ info_page = """ Welcome to the Preflight Program, a tool inspired by the preflight checklists used by pilots before flying a plane. This program is designed to verify the functionality of all software and hardware systems on your autonomous robot. It ensures that everything is in working order, allowing you to safely deploy your robot with confidence.\n -[italic]Authors:[/italic] -Keith Khadar -Anthony Liao -Joshua Thomas -Maanas Kotha\n """ diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/README.md b/mil_common/utils/mil_tools/scripts/mil-preflight/preflight.md similarity index 86% rename from mil_common/utils/mil_tools/scripts/mil-preflight/README.md rename to mil_common/utils/mil_tools/scripts/mil-preflight/preflight.md index 830fc5f9b..942d85cb4 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/README.md +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/preflight.md @@ -4,7 +4,6 @@ Simply type "preflight" anywhere in the MIL directory. Make sure that a robot is ## Description Preflight is an automated testing tool that should be run after turning on and connecting to the robot to run a prelaunch hardware checklist and automated software checklist. -In the current version 1.0, Run Specific Test is not yet implemented. ### There are three types of automated software tests #### Actuators This test will prompt the user to enable physical moving actuators on the robot. Make sure that the area is cleared and the robot won't damage itself or others nearby. The user will have to watch and validate that they move as expected personally. @@ -19,5 +18,7 @@ ROS Topics act as a channel for ROS Nodes to communicate by publishing and subsc To add a Topic test, add a topic to the list in tests.py -### Dependencies -ROS, Rich, PyInquirer +### Setup Tests +There are also setup tests. These are used to verify certain features on the robot that cannot be automated. For example ensuring that the O-rings are greased. + +To add a Setup test, add a what need to be tested to the list in tests.py diff --git a/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py b/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py index 91fa73b1a..9503cf5cd 100644 --- a/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py +++ b/mil_common/utils/mil_tools/scripts/mil-preflight/tests.py @@ -5,10 +5,10 @@ # add tests you would add them here. ################################################################################ - # ----- Actuator Tests ----- # # Add tests here for actuators. These will be turned on and the user # will confirm their operation. Also include any custom message + # imports here. # Thruster Messages @@ -20,6 +20,10 @@ actuator_timeout = 1.5 # seconds actuatorsList = [ + ### ( + ### "Name of Test", + ### ("/topic", message), + ### ) ( "FLH Thruster Test", ("/thrusters/thrust", [ThrusterCmd(name="FLH", thrust=10.0)]), @@ -54,6 +58,7 @@ ), ] + # ----- Setup Tests ----- # # Add tests here for things that need to be physically inspected or check before the sub is running setup = [ @@ -68,11 +73,13 @@ # ----- Nodes -----# nodes = [ + # Navbox processing "/odom_estimator", - "/odom_estimator", - "/odom_estimator", - "/odom_estimator", - "/doest_exist", + "/transform_odometry", + "/c3_trajectory_generator", + "/adaptive_controller", + "/thruster_mapper", + "/mission_runner", ] # ----- Topics -----# diff --git a/services.txt b/services.txt deleted file mode 100644 index ff8f96b88..000000000 --- a/services.txt +++ /dev/null @@ -1,165 +0,0 @@ -/adaptive_controller/get_loggers -/adaptive_controller/set_logger_level -/adaptive_controller/set_parameters -/alarm/get -/alarm/set -/alarm_sever/get_loggers -/alarm_sever/set_logger_level -/b_matrix -/c3_trajectory_generator/get_loggers -/c3_trajectory_generator/set_logger_level -/camera/down/down_image_proc/get_loggers -/camera/down/down_image_proc/set_logger_level -/camera/down/down_image_proc_debayer/set_parameters -/camera/down/down_image_proc_rectify_color/set_parameters -/camera/down/down_image_proc_rectify_mono/set_parameters -/camera/down/image_color/compressed/set_parameters -/camera/down/image_color/compressedDepth/set_parameters -/camera/down/image_color/theora/set_parameters -/camera/down/image_mono/compressed/set_parameters -/camera/down/image_mono/compressedDepth/set_parameters -/camera/down/image_mono/theora/set_parameters -/camera/down/image_raw/compressed/set_parameters -/camera/down/image_raw/compressedDepth/set_parameters -/camera/down/image_raw/theora/set_parameters -/camera/down/image_rect/compressed/set_parameters -/camera/down/image_rect/compressedDepth/set_parameters -/camera/down/image_rect/theora/set_parameters -/camera/down/image_rect_color/compressed/set_parameters -/camera/down/image_rect_color/compressedDepth/set_parameters -/camera/down/image_rect_color/theora/set_parameters -/camera/down/set_camera_info -/camera/down/set_parameters -/camera/front/camera_nodelet_manager/get_loggers -/camera/front/camera_nodelet_manager/list -/camera/front/camera_nodelet_manager/load_nodelet -/camera/front/camera_nodelet_manager/set_logger_level -/camera/front/camera_nodelet_manager/unload_nodelet -/camera/front/left/image_color/compressed/set_parameters -/camera/front/left/image_color/compressedDepth/set_parameters -/camera/front/left/image_color/theora/set_parameters -/camera/front/left/image_mono/compressed/set_parameters -/camera/front/left/image_mono/compressedDepth/set_parameters -/camera/front/left/image_mono/theora/set_parameters -/camera/front/left/image_raw/compressed/set_parameters -/camera/front/left/image_raw/compressedDepth/set_parameters -/camera/front/left/image_raw/theora/set_parameters -/camera/front/left/image_rect/compressed/set_parameters -/camera/front/left/image_rect/compressedDepth/set_parameters -/camera/front/left/image_rect/theora/set_parameters -/camera/front/left/image_rect_color/compressed/set_parameters -/camera/front/left/image_rect_color/compressedDepth/set_parameters -/camera/front/left/image_rect_color/theora/set_parameters -/camera/front/left/seecam_image_proc/get_loggers -/camera/front/left/seecam_image_proc/set_logger_level -/camera/front/left/seecam_image_proc_debayer/set_parameters -/camera/front/left/seecam_image_proc_rectify_color/set_parameters -/camera/front/left/seecam_image_proc_rectify_mono/set_parameters -/camera/front/left/set_camera_info -/camera/front/left/set_parameters -/camera/front/right/image_color/compressed/set_parameters -/camera/front/right/image_color/compressedDepth/set_parameters -/camera/front/right/image_color/theora/set_parameters -/camera/front/right/image_mono/compressed/set_parameters -/camera/front/right/image_mono/compressedDepth/set_parameters -/camera/front/right/image_mono/theora/set_parameters -/camera/front/right/image_raw/compressed/set_parameters -/camera/front/right/image_raw/compressedDepth/set_parameters -/camera/front/right/image_raw/theora/set_parameters -/camera/front/right/image_rect/compressed/set_parameters -/camera/front/right/image_rect/compressedDepth/set_parameters -/camera/front/right/image_rect/theora/set_parameters -/camera/front/right/image_rect_color/compressed/set_parameters -/camera/front/right/image_rect_color/compressedDepth/set_parameters -/camera/front/right/image_rect_color/theora/set_parameters -/camera/front/right/set_camera_info -/camera/front/right/set_parameters -/camera/front/right_image_proc_debayer/get_loggers -/camera/front/right_image_proc_debayer/set_logger_level -/camera/front/right_image_proc_debayer/set_parameters -/camera/front/right_image_proc_rect/get_loggers -/camera/front/right_image_proc_rect/set_logger_level -/camera/front/right_image_proc_rect/set_parameters -/camera/front/right_image_proc_rect_color/get_loggers -/camera/front/right_image_proc_rect_color/set_logger_level -/camera/front/right_image_proc_rect_color/set_parameters -/gazebo/apply_body_wrench -/gazebo/apply_joint_effort -/gazebo/clear_body_wrenches -/gazebo/clear_joint_forces -/gazebo/delete_light -/gazebo/delete_model -/gazebo/get_joint_properties -/gazebo/get_light_properties -/gazebo/get_link_properties -/gazebo/get_link_state -/gazebo/get_loggers -/gazebo/get_model_properties -/gazebo/get_model_state -/gazebo/get_physics_properties -/gazebo/get_world_properties -/gazebo/pause_physics -/gazebo/reset_simulation -/gazebo/reset_world -/gazebo/set_joint_properties -/gazebo/set_light_properties -/gazebo/set_link_properties -/gazebo/set_link_state -/gazebo/set_logger_level -/gazebo/set_model_configuration -/gazebo/set_model_state -/gazebo/set_parameters -/gazebo/set_physics_properties -/gazebo/spawn_sdf_model -/gazebo/spawn_urdf_model -/gazebo/unpause_physics -/hydrophones/hydrophones_visualization/get_loggers -/hydrophones/hydrophones_visualization/set_logger_level -/hydrophones/ping_locator/cross_correlation_debug_enable -/hydrophones/ping_locator/enable -/hydrophones/ping_locator/get_loggers -/hydrophones/ping_locator/samples_debug_enable -/hydrophones/ping_locator/set_logger_level -/hydrophones/triggering/enable -/hydrophones/triggering/filter_debug_enable -/hydrophones/triggering/filter_debug_trigger -/hydrophones/triggering/get_loggers -/hydrophones/triggering/reset -/hydrophones/triggering/sample_at_trigger_debug_enable -/hydrophones/triggering/set_logger_level -/hydrophones/triggering/trigger_debug_enable -/magnetometer_vis/get_loggers -/magnetometer_vis/set_logger_level -/mission_runner/get_loggers -/mission_runner/refresh_missions -/mission_runner/set_logger_level -/odom_estimator/get_loggers -/odom_estimator/set_ignore_magnetometer -/odom_estimator/set_logger_level -/odometry_to_tf/get_loggers -/odometry_to_tf/set_logger_level -/poi_server/add -/poi_server/delete -/poi_server/get_loggers -/poi_server/move -/poi_server/save_to_param -/poi_server/set_logger_level -/poi_server/tf2_frames -/robot_state_publisher/get_loggers -/robot_state_publisher/set_logger_level -/rosout/get_loggers -/rosout/set_logger_level -/set_mobo_kill -/set_valve -/simulate_go -/simulate_hard_kill -/simulate_soft_kill -/tf_republisher/get_loggers -/tf_republisher/set_logger_level -/thruster_mapper/get_loggers -/thruster_mapper/set_logger_level -/transform_odometry/get_loggers -/transform_odometry/set_logger_level -/update_thruster_layout -/usb_to_can_driver/get_loggers -/usb_to_can_driver/set_logger_level diff --git a/topics.txt b/topics.txt deleted file mode 100644 index d85bb2a17..000000000 --- a/topics.txt +++ /dev/null @@ -1,254 +0,0 @@ -/absodom -/adaptive_controller/adaptation -/adaptive_controller/dist -/adaptive_controller/drag -/adaptive_controller/parameter_descriptions -/adaptive_controller/parameter_updates -/adaptive_controller/pose_error -/adaptive_controller/twist_error -/alarm/updates -/c3_trajectory_generator/sub_ogrid -/c3_trajectory_generator/trajectory_v -/c3_trajectory_generator/waypoint -/c3_trajectory_generator/waypoint_ogrid -/camera/down/camera_info -/camera/down/down_image_proc_debayer/parameter_descriptions -/camera/down/down_image_proc_debayer/parameter_updates -/camera/down/down_image_proc_rectify_color/parameter_descriptions -/camera/down/down_image_proc_rectify_color/parameter_updates -/camera/down/down_image_proc_rectify_mono/parameter_descriptions -/camera/down/down_image_proc_rectify_mono/parameter_updates -/camera/down/image_color -/camera/down/image_color/compressed -/camera/down/image_color/compressed/parameter_descriptions -/camera/down/image_color/compressed/parameter_updates -/camera/down/image_color/compressedDepth -/camera/down/image_color/compressedDepth/parameter_descriptions -/camera/down/image_color/compressedDepth/parameter_updates -/camera/down/image_color/theora -/camera/down/image_color/theora/parameter_descriptions -/camera/down/image_color/theora/parameter_updates -/camera/down/image_mono -/camera/down/image_mono/compressed -/camera/down/image_mono/compressed/parameter_descriptions -/camera/down/image_mono/compressed/parameter_updates -/camera/down/image_mono/compressedDepth -/camera/down/image_mono/compressedDepth/parameter_descriptions -/camera/down/image_mono/compressedDepth/parameter_updates -/camera/down/image_mono/theora -/camera/down/image_mono/theora/parameter_descriptions -/camera/down/image_mono/theora/parameter_updates -/camera/down/image_raw -/camera/down/image_raw/compressed -/camera/down/image_raw/compressed/parameter_descriptions -/camera/down/image_raw/compressed/parameter_updates -/camera/down/image_raw/compressedDepth -/camera/down/image_raw/compressedDepth/parameter_descriptions -/camera/down/image_raw/compressedDepth/parameter_updates -/camera/down/image_raw/theora -/camera/down/image_raw/theora/parameter_descriptions -/camera/down/image_raw/theora/parameter_updates -/camera/down/image_rect -/camera/down/image_rect/compressed -/camera/down/image_rect/compressed/parameter_descriptions -/camera/down/image_rect/compressed/parameter_updates -/camera/down/image_rect/compressedDepth -/camera/down/image_rect/compressedDepth/parameter_descriptions -/camera/down/image_rect/compressedDepth/parameter_updates -/camera/down/image_rect/theora -/camera/down/image_rect/theora/parameter_descriptions -/camera/down/image_rect/theora/parameter_updates -/camera/down/image_rect_color -/camera/down/image_rect_color/compressed -/camera/down/image_rect_color/compressed/parameter_descriptions -/camera/down/image_rect_color/compressed/parameter_updates -/camera/down/image_rect_color/compressedDepth -/camera/down/image_rect_color/compressedDepth/parameter_descriptions -/camera/down/image_rect_color/compressedDepth/parameter_updates -/camera/down/image_rect_color/theora -/camera/down/image_rect_color/theora/parameter_descriptions -/camera/down/image_rect_color/theora/parameter_updates -/camera/down/parameter_descriptions -/camera/down/parameter_updates -/camera/front/camera_nodelet_manager/bond -/camera/front/left/camera_info -/camera/front/left/image_color -/camera/front/left/image_color/compressed -/camera/front/left/image_color/compressed/parameter_descriptions -/camera/front/left/image_color/compressed/parameter_updates -/camera/front/left/image_color/compressedDepth -/camera/front/left/image_color/compressedDepth/parameter_descriptions -/camera/front/left/image_color/compressedDepth/parameter_updates -/camera/front/left/image_color/theora -/camera/front/left/image_color/theora/parameter_descriptions -/camera/front/left/image_color/theora/parameter_updates -/camera/front/left/image_mono -/camera/front/left/image_mono/compressed -/camera/front/left/image_mono/compressed/parameter_descriptions -/camera/front/left/image_mono/compressed/parameter_updates -/camera/front/left/image_mono/compressedDepth -/camera/front/left/image_mono/compressedDepth/parameter_descriptions -/camera/front/left/image_mono/compressedDepth/parameter_updates -/camera/front/left/image_mono/theora -/camera/front/left/image_mono/theora/parameter_descriptions -/camera/front/left/image_mono/theora/parameter_updates -/camera/front/left/image_raw -/camera/front/left/image_raw/compressed -/camera/front/left/image_raw/compressed/parameter_descriptions -/camera/front/left/image_raw/compressed/parameter_updates -/camera/front/left/image_raw/compressedDepth -/camera/front/left/image_raw/compressedDepth/parameter_descriptions -/camera/front/left/image_raw/compressedDepth/parameter_updates -/camera/front/left/image_raw/theora -/camera/front/left/image_raw/theora/parameter_descriptions -/camera/front/left/image_raw/theora/parameter_updates -/camera/front/left/image_rect -/camera/front/left/image_rect/compressed -/camera/front/left/image_rect/compressed/parameter_descriptions -/camera/front/left/image_rect/compressed/parameter_updates -/camera/front/left/image_rect/compressedDepth -/camera/front/left/image_rect/compressedDepth/parameter_descriptions -/camera/front/left/image_rect/compressedDepth/parameter_updates -/camera/front/left/image_rect/theora -/camera/front/left/image_rect/theora/parameter_descriptions -/camera/front/left/image_rect/theora/parameter_updates -/camera/front/left/image_rect_color -/camera/front/left/image_rect_color/compressed -/camera/front/left/image_rect_color/compressed/parameter_descriptions -/camera/front/left/image_rect_color/compressed/parameter_updates -/camera/front/left/image_rect_color/compressedDepth -/camera/front/left/image_rect_color/compressedDepth/parameter_descriptions -/camera/front/left/image_rect_color/compressedDepth/parameter_updates -/camera/front/left/image_rect_color/theora -/camera/front/left/image_rect_color/theora/parameter_descriptions -/camera/front/left/image_rect_color/theora/parameter_updates -/camera/front/left/parameter_descriptions -/camera/front/left/parameter_updates -/camera/front/left/seecam_image_proc_debayer/parameter_descriptions -/camera/front/left/seecam_image_proc_debayer/parameter_updates -/camera/front/left/seecam_image_proc_rectify_color/parameter_descriptions -/camera/front/left/seecam_image_proc_rectify_color/parameter_updates -/camera/front/left/seecam_image_proc_rectify_mono/parameter_descriptions -/camera/front/left/seecam_image_proc_rectify_mono/parameter_updates -/camera/front/right/camera_info -/camera/front/right/image_color -/camera/front/right/image_color/compressed -/camera/front/right/image_color/compressed/parameter_descriptions -/camera/front/right/image_color/compressed/parameter_updates -/camera/front/right/image_color/compressedDepth -/camera/front/right/image_color/compressedDepth/parameter_descriptions -/camera/front/right/image_color/compressedDepth/parameter_updates -/camera/front/right/image_color/theora -/camera/front/right/image_color/theora/parameter_descriptions -/camera/front/right/image_color/theora/parameter_updates -/camera/front/right/image_mono -/camera/front/right/image_mono/compressed -/camera/front/right/image_mono/compressed/parameter_descriptions -/camera/front/right/image_mono/compressed/parameter_updates -/camera/front/right/image_mono/compressedDepth -/camera/front/right/image_mono/compressedDepth/parameter_descriptions -/camera/front/right/image_mono/compressedDepth/parameter_updates -/camera/front/right/image_mono/theora -/camera/front/right/image_mono/theora/parameter_descriptions -/camera/front/right/image_mono/theora/parameter_updates -/camera/front/right/image_raw -/camera/front/right/image_raw/compressed -/camera/front/right/image_raw/compressed/parameter_descriptions -/camera/front/right/image_raw/compressed/parameter_updates -/camera/front/right/image_raw/compressedDepth -/camera/front/right/image_raw/compressedDepth/parameter_descriptions -/camera/front/right/image_raw/compressedDepth/parameter_updates -/camera/front/right/image_raw/theora -/camera/front/right/image_raw/theora/parameter_descriptions -/camera/front/right/image_raw/theora/parameter_updates -/camera/front/right/image_rect -/camera/front/right/image_rect/compressed -/camera/front/right/image_rect/compressed/parameter_descriptions -/camera/front/right/image_rect/compressed/parameter_updates -/camera/front/right/image_rect/compressedDepth -/camera/front/right/image_rect/compressedDepth/parameter_descriptions -/camera/front/right/image_rect/compressedDepth/parameter_updates -/camera/front/right/image_rect/theora -/camera/front/right/image_rect/theora/parameter_descriptions -/camera/front/right/image_rect/theora/parameter_updates -/camera/front/right/image_rect_color -/camera/front/right/image_rect_color/compressed -/camera/front/right/image_rect_color/compressed/parameter_descriptions -/camera/front/right/image_rect_color/compressed/parameter_updates -/camera/front/right/image_rect_color/compressedDepth -/camera/front/right/image_rect_color/compressedDepth/parameter_descriptions -/camera/front/right/image_rect_color/compressedDepth/parameter_updates -/camera/front/right/image_rect_color/theora -/camera/front/right/image_rect_color/theora/parameter_descriptions -/camera/front/right/image_rect_color/theora/parameter_updates -/camera/front/right/parameter_descriptions -/camera/front/right/parameter_updates -/camera/front/right_image_proc_debayer/parameter_descriptions -/camera/front/right_image_proc_debayer/parameter_updates -/camera/front/right_image_proc_rect/parameter_descriptions -/camera/front/right_image_proc_rect/parameter_updates -/camera/front/right_image_proc_rect_color/parameter_descriptions -/camera/front/right_image_proc_rect_color/parameter_updates -/clock -/contact_bumper -/depth -/dvl -/dvl/range -/gazebo/link_states -/gazebo/model_states -/gazebo/parameter_descriptions -/gazebo/parameter_updates -/gazebo/performance_metrics -/gazebo/set_link_state -/gazebo/set_model_state -/hydrophones/direction -/hydrophones/direction_marker -/hydrophones/ping_locator/cross_correlation_debug -/hydrophones/ping_locator/samples_debug -/hydrophones/pings -/hydrophones/processed -/hydrophones/samples -/hydrophones/triggering/filter_debug -/hydrophones/triggering/sample_at_trigger_debug -/hydrophones/triggering/trigger_debug -/hydrophones/visualization -/imu/data_raw -/imu/inclinometer -/imu/mag -/imu/marker -/imu_odom -/joint_states -/mission/cancel -/mission/feedback -/mission/goal -/mission/result -/mission/status -/moveto/cancel -/moveto/feedback -/moveto/goal -/moveto/result -/moveto/status -/network -/odom -/odom_estimator/info -/ogrid_pointcloud/ogrid -/online_bagger/bag/cancel -/online_bagger/bag/feedback -/online_bagger/bag/goal -/online_bagger/bag/result -/online_bagger/bag/status -/points_of_interest -/points_of_interest/feedback -/points_of_interest/update -/points_of_interest/update_full -/rosout -/rosout_agg -/tf -/tf_static -/thrusters/thrust -/trajectory -/visualization -/wrench -/wrench_actual -/wrench_error -/yolov7/detections From 988ef997dc80f35be799edd96cf9f1e649675a44 Mon Sep 17 00:00:00 2001 From: Keith Khadar Date: Fri, 29 Mar 2024 13:11:59 -0400 Subject: [PATCH 25/26] Added Rich to requirements.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index ad0ec1fa1..8e95d9d9b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,6 +33,8 @@ sphinx-copybutton==0.5.0 # Terminal PyInquirer==1.0.3 +rich==13.7.1 +pygments==2.17.2 # External Devices pyserial==3.5 From f2e46cf1888c534cade624693afdbe671d0374d7 Mon Sep 17 00:00:00 2001 From: Cameron Brown Date: Fri, 29 Mar 2024 21:31:09 -0400 Subject: [PATCH 26/26] Move Preflight docs to software docs instead of reference docs --- docs/reference/index.rst | 1 - docs/software/index.rst | 1 + docs/{reference => software}/preflight.md | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename docs/{reference => software}/preflight.md (100%) diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 6634f15bb..c63581a0c 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -32,4 +32,3 @@ by MIL. These subsystems relate to a variety of processes. pneumatic sabertooth bagging - preflight diff --git a/docs/software/index.rst b/docs/software/index.rst index 5b06f569e..299168e7c 100644 --- a/docs/software/index.rst +++ b/docs/software/index.rst @@ -16,6 +16,7 @@ Various documentation related to practices followed by the MIL Software team. rqt rostest alarms + preflight Bash Style Guide C++ Style Guide Python Style Guide diff --git a/docs/reference/preflight.md b/docs/software/preflight.md similarity index 100% rename from docs/reference/preflight.md rename to docs/software/preflight.md