diff --git a/.github/ISSUE_TEMPLATE/navigator.yaml b/.github/ISSUE_TEMPLATE/navigator.yaml
index 8e528b706..a3617fae6 100644
--- a/.github/ISSUE_TEMPLATE/navigator.yaml
+++ b/.github/ISSUE_TEMPLATE/navigator.yaml
@@ -7,26 +7,6 @@ body:
attributes:
value: |
Hey, thanks for taking the time to add this software issue!
- - type: input
- id: assignee
- attributes:
- label: Assignee
- description: >
- Does this issue need to be completed by a specific person on the team?
- If so, mention them below.
- placeholder: ex. @torvalds is already working on this task!
- validations:
- required: false
- - type: input
- id: deadline
- attributes:
- label: Deadline
- description: >
- Does this task need a deadline? _If this task is related to a competition,
- it should have a deadline._
- placeholder: ex. 2023-12-25
- validations:
- required: false
- type: textarea
id: description
attributes:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index c69ca062a..de7c09a7a 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -31,19 +31,20 @@ jobs:
- name: Configure catkin workspace folder structure
run: |
mkdir -p $GITHUB_WORKSPACE/catkin_ws/src
+ sudo apt reinstall python3-pip
- name: Check out code from GitHub
uses: actions/checkout@v3.0.2
with:
submodules: recursive
path: catkin_ws/src/mil
- name: Setup ROS Noetic
- uses: ros-tooling/setup-ros@v0.3
+ uses: ros-tooling/setup-ros@v0.7
with:
required-ros-distributions: noetic
- name: Install pip dependencies
run: |
cd $GITHUB_WORKSPACE/catkin_ws/src/mil
- pip install -r requirements.txt
+ pip3 install -r requirements.txt
# We want to run a full test suite in CI - this includes the BlueView
# tests!
- name: Install BlueView Sonar SDK
@@ -120,7 +121,7 @@ jobs:
# We need to install rsync for GitHub Pages deploy action
- name: Install rsync
run: |
- sudo apt-get upgrade && sudo apt-get update && sudo apt-get install -y rsync
+ sudo apt-get update && sudo apt-get upgrade && sudo apt-get install -y rsync
# Publish the artifact to the GitHub Pages branch
- name: Push docs to GitHub Pages
diff --git a/.github/workflows/gh_pages.yaml b/.github/workflows/gh_pages.yaml
index b54342c28..39b70c62a 100644
--- a/.github/workflows/gh_pages.yaml
+++ b/.github/workflows/gh_pages.yaml
@@ -20,7 +20,7 @@ jobs:
# Wait for the CI to finish so we can download the docs artifact
- name: Wait for CI
- uses: lewagon/wait-on-check-action@v1.0.0
+ uses: lewagon/wait-on-check-action@v1.3.3
if: github.event.action != 'closed'
with:
ref: ${{ github.event.pull_request.head.ref }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 93b2c6fc4..79a11871a 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -11,41 +11,41 @@ ci:
repos:
- repo: https://github.com/adrienverge/yamllint.git
- rev: v1.30.0
+ rev: v1.33.0
hooks:
- id: yamllint
- repo: https://github.com/psf/black
- rev: 23.3.0
+ rev: 24.1.1
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-clang-format
- rev: v16.0.0
+ rev: v17.0.6
hooks:
- id: clang-format
- repo: https://github.com/PyCQA/autoflake
- rev: v2.0.2
+ rev: v2.2.1
hooks:
- id: autoflake
args: [--remove-all-unused-imports, --ignore-init-module-imports]
- repo: https://github.com/shellcheck-py/shellcheck-py
- rev: v0.9.0.2
+ rev: v0.9.0.6
hooks:
- id: shellcheck
exclude: ^docker|deprecated|NaviGator/simulation/VRX
args: [--severity=warning, --exclude=SC1090]
- repo: https://github.com/scop/pre-commit-shfmt
- rev: v3.6.0-2
+ rev: v3.7.0-4
hooks:
- id: shfmt
exclude: ^docker|deprecated|NaviGator/simulation/VRX
- - repo: https://github.com/charliermarsh/ruff-pre-commit
+ - repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
- rev: 'v0.0.260'
+ rev: 'v0.2.0'
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/codespell-project/codespell
- rev: v2.2.4
+ rev: v2.2.6
hooks:
- id: codespell
args:
@@ -73,11 +73,12 @@ repos:
- id: prettier-package-xml
- id: sort-package-xml
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.4.0
+ rev: v4.5.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-merge-conflict
+ exclude_types: [markdown, rst]
- id: check-executables-have-shebangs
- id: check-symlinks
- id: check-json
diff --git a/NaviGator/gnc/navigator_msg_multiplexer/nodes/ogrid_arbiter.py b/NaviGator/gnc/navigator_msg_multiplexer/nodes/ogrid_arbiter.py
index ac8fffd4f..eb425ec7a 100755
--- a/NaviGator/gnc/navigator_msg_multiplexer/nodes/ogrid_arbiter.py
+++ b/NaviGator/gnc/navigator_msg_multiplexer/nodes/ogrid_arbiter.py
@@ -493,10 +493,7 @@ def publish(self, timer_event):
)
print(e)
fprint(
- "w: {}, h: {}".format(
- global_ogrid.info.width,
- global_ogrid.info.height,
- ),
+ f"w: {global_ogrid.info.width}, h: {global_ogrid.info.height}",
msg_color="red",
)
diff --git a/NaviGator/gnc/navigator_path_planner/nodes/path_planner.py b/NaviGator/gnc/navigator_path_planner/nodes/path_planner.py
index ba33ca850..1f6ff6793 100755
--- a/NaviGator/gnc/navigator_path_planner/nodes/path_planner.py
+++ b/NaviGator/gnc/navigator_path_planner/nodes/path_planner.py
@@ -1070,7 +1070,7 @@ def reevaluate_plan(self) -> None:
def action_check(self, _: rospy.timer.TimerEvent) -> None:
"""
Manages action preempting. Serves as the callback to a Timer operating
- opereating every self.revisit_period seconds.
+ operating every self.revisit_period seconds.
"""
if self.preempted or not self.move_server.is_active():
return
diff --git a/NaviGator/gnc/navigator_thrust_mapper/navigator_thrust_mapper/thruster_map.py b/NaviGator/gnc/navigator_thrust_mapper/navigator_thrust_mapper/thruster_map.py
index 588679455..2fc19700a 100644
--- a/NaviGator/gnc/navigator_thrust_mapper/navigator_thrust_mapper/thruster_map.py
+++ b/NaviGator/gnc/navigator_thrust_mapper/navigator_thrust_mapper/thruster_map.py
@@ -166,15 +166,11 @@ def from_urdf(
if find != -1 and find + len(transmission_suffix) == len(transmission.name):
if len(transmission.joints) != 1:
raise Exception(
- "Transmission {} does not have 1 joint".format(
- transmission.name,
- ),
+ f"Transmission {transmission.name} does not have 1 joint",
)
if len(transmission.actuators) != 1:
raise Exception(
- "Transmission {} does not have 1 actuator".format(
- transmission.name,
- ),
+ f"Transmission {transmission.name} does not have 1 actuator",
)
t_ratio = transmission.actuators[0].mechanicalReduction
@@ -195,9 +191,7 @@ def from_urdf(
joint = t_joint
if joint is None:
rospy.logerr(
- "Transmission joint {} not found".format(
- transmission.joints[0].name,
- ),
+ f"Transmission joint {transmission.joints[0].name} not found",
)
try:
trans = buff.lookup_transform(
@@ -217,9 +211,7 @@ def from_urdf(
joints.append(joint.name)
if limit != -1 and joint.limit.effort != limit:
raise Exception(
- "Thruster {} had a different limit, cannot proceed".format(
- joint.name,
- ),
+ f"Thruster {joint.name} had a different limit, cannot proceed",
)
limit = joint.limit.effort
limit_tuple = (limit, -limit)
diff --git a/NaviGator/hardware_drivers/navigator_kill_board/navigator_kill_board/constants.py b/NaviGator/hardware_drivers/navigator_kill_board/navigator_kill_board/constants.py
index 83663e034..d5eaef7e4 100644
--- a/NaviGator/hardware_drivers/navigator_kill_board/navigator_kill_board/constants.py
+++ b/NaviGator/hardware_drivers/navigator_kill_board/navigator_kill_board/constants.py
@@ -17,6 +17,7 @@
The computer can also command a kill (for example, if ROS notices a criticaly low battery)
by sending the COMPUTER.KILL.REQUEST and undone with COMPUTER.CLEAR.REQUEST
"""
+
constants = {
"TIMEOUT_SECONDS": 8.0, # How often board must be pinged to not set HEARTBERAT_REMOTE True
# Note: not official documented, this is just a guess
diff --git a/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/battery_voltage.py b/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/battery_voltage.py
index 6c25b9169..c10b13c91 100644
--- a/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/battery_voltage.py
+++ b/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/battery_voltage.py
@@ -27,9 +27,9 @@ def _check_voltage(self, msg):
if not self._raised or self._severity != severity:
self.broadcaster.raise_alarm(
severity=severity,
- problem_description="battery critcaly low"
- if severity == 2
- else "battery low",
+ problem_description=(
+ "battery critcaly low" if severity == 2 else "battery low"
+ ),
parameters={"voltage": voltage},
)
diff --git a/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/kill.py b/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/kill.py
index de42244da..547c56fa8 100644
--- a/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/kill.py
+++ b/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/kill.py
@@ -28,10 +28,7 @@ def _online_bagger_cb(self, status, result):
rospy.loginfo(f"KILL BAG WRITTEN TO {result.filename}")
else:
rospy.logwarn(
- "KILL BAG {}, status: {}".format(
- TerminalState.to_string(status),
- result.status,
- ),
+ f"KILL BAG {TerminalState.to_string(status)}, status: {result.status}",
)
def _kill_task_cb(self, status, result):
@@ -39,10 +36,7 @@ def _kill_task_cb(self, status, result):
rospy.loginfo("Killed task success!")
return
rospy.logwarn(
- "Killed task failed ({}): {}".format(
- TerminalState.to_string(status),
- result.result,
- ),
+ f"Killed task failed ({TerminalState.to_string(status)}): {result.result}",
)
def raised(self, alarm):
@@ -54,7 +48,7 @@ def raised(self, alarm):
rospy.logwarn("BAG_ALWAYS or BAG_KILL not set. Not making kill bag.")
else:
goal = BagOnlineGoal(bag_name="kill.bag")
- goal.topics = os.environ["BAG_ALWAYS"] + " " + os.environ["bag_kill"]
+ goal.topics = os.environ["BAG_ALWAYS"] + " " + os.environ["BAG_KILL"]
self.bag_client.send_goal(goal, done_cb=self._online_bagger_cb)
self.task_client.run_mission("Killed", done_cb=self._kill_task_cb)
diff --git a/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/odom_kill.py b/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/odom_kill.py
index 2bc5e6c43..d0fa63afd 100755
--- a/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/odom_kill.py
+++ b/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/odom_kill.py
@@ -51,9 +51,7 @@ def check_continuity(self, odom):
self._raised = True # Avoid raising multiple times
rospy.logwarn("ODOM DISCONTINUITY DETECTED")
self.ab.raise_alarm(
- problem_description="ODOM DISCONTINUITY DETECTED. JUMPED {} METERS".format(
- jump,
- ),
+ problem_description=f"ODOM DISCONTINUITY DETECTED. JUMPED {jump} METERS",
severity=5,
)
self.last_position = position
diff --git a/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/thruster_fault.py b/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/thruster_fault.py
index a89612632..ce89ac3a0 100644
--- a/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/thruster_fault.py
+++ b/NaviGator/mission_control/navigator_alarm/navigator_alarm_handlers/thruster_fault.py
@@ -65,9 +65,7 @@ def _check_faults(self, msg, topic):
return
self.broadcaster.raise_alarm(
severity=5,
- problem_description="{} thrusters have faults".format(
- len(self._raised_alarms),
- ),
+ problem_description=f"{len(self._raised_alarms)} thrusters have faults",
parameters={
t: self._get_fault_codes(k) for t, k in self._raised_alarms.items()
},
diff --git a/NaviGator/mission_control/navigator_launch/launch/vrx/vrx_master.launch b/NaviGator/mission_control/navigator_launch/launch/vrx/vrx_master.launch
index 944df5bfa..377f824de 100644
--- a/NaviGator/mission_control/navigator_launch/launch/vrx/vrx_master.launch
+++ b/NaviGator/mission_control/navigator_launch/launch/vrx/vrx_master.launch
@@ -7,6 +7,7 @@
+
@@ -30,5 +31,4 @@
-
diff --git a/NaviGator/mission_control/navigator_launch/launch/vrx/vrx_tf.launch b/NaviGator/mission_control/navigator_launch/launch/vrx/vrx_tf.launch
index f46bcca90..a9bdd66e8 100644
--- a/NaviGator/mission_control/navigator_launch/launch/vrx/vrx_tf.launch
+++ b/NaviGator/mission_control/navigator_launch/launch/vrx/vrx_tf.launch
@@ -1,5 +1,8 @@
+
+ true
+
@@ -11,9 +14,10 @@
-
-
-
-
+
+
+
+
+
diff --git a/NaviGator/mission_control/navigator_missions/launch/mission_params.yaml b/NaviGator/mission_control/navigator_missions/launch/mission_params.yaml
index 7b44edc7e..c4ee5940c 100644
--- a/NaviGator/mission_control/navigator_missions/launch/mission_params.yaml
+++ b/NaviGator/mission_control/navigator_missions/launch/mission_params.yaml
@@ -157,14 +157,14 @@ dock_shape_1:
param: /mission/identify_dock/shape_1
options: [CIRCLE, TRIANGLE, CROSS, ANY]
description: >
- The shape of the first bay to dock in during the dentify
+ The shape of the first bay to dock in during the identify
Symbols and Dock mission. If set to ANY, mission should dock based on the
color parameter and set this parameter during the mission
dock_color_1:
param: /mission/identify_dock/color_1
options: [RED, GREEN, BLUE, ANY]
description: >
- The color of the first bay to dock in during the dentify Symbols and Dock
+ The color of the first bay to dock in during the identify Symbols and Dock
mission. If set to ANY, mission should dock based on the shape parameter
and set this parameter during the mission
@@ -174,7 +174,7 @@ dock_shape_2:
description: >
# yamllint disable-line rule:line-length
The shape of the second bay to dock in during the
- dentify Symbols and Dock mission. If set to ANY,
+ identify Symbols and Dock mission. If set to ANY,
mission should dock based on the color parameter and set this
parameter during the mission
dock_color_2:
@@ -183,6 +183,6 @@ dock_color_2:
description: >
# yamllint disable-line rule:line-length
The color of the second bay to dock in during the
- dentify Symbols and Dock mission.
+ identify Symbols and Dock mission.
If set to ANY, mission should dock based on the shape
parameter and set this parameter during the mission
diff --git a/NaviGator/mission_control/navigator_missions/navigator_missions/constant_velocity.py b/NaviGator/mission_control/navigator_missions/navigator_missions/constant_velocity.py
index c9a5a503b..a0ce42a26 100644
--- a/NaviGator/mission_control/navigator_missions/navigator_missions/constant_velocity.py
+++ b/NaviGator/mission_control/navigator_missions/navigator_missions/constant_velocity.py
@@ -61,12 +61,12 @@ def decode_parameters(cls, parameters):
if not isinstance(parsed, list) or len(parsed) != 3:
raise err
for i in range(3):
- if not (isinstance(parsed[i], int) or isinstance(parsed[i], float)):
+ if not (isinstance(parsed[i], (int, float))):
raise err
return parsed
async def run(self, args):
- # Publish a velocity of zero for a while to stabalize navigator
+ # Publish a velocity of zero for a while to stabilize navigator
self.send_feedback("Switching trajectory to constant")
await self.change_trajectory("constant")
await self.nh.sleep(0.1)
diff --git a/NaviGator/mission_control/navigator_missions/navigator_missions/demonstrate_navigation.py b/NaviGator/mission_control/navigator_missions/navigator_missions/demonstrate_navigation.py
index 6c53d35a4..599a388cc 100644
--- a/NaviGator/mission_control/navigator_missions/navigator_missions/demonstrate_navigation.py
+++ b/NaviGator/mission_control/navigator_missions/navigator_missions/demonstrate_navigation.py
@@ -68,7 +68,7 @@ async def run(self, parameters):
_, closest_reds = await self.get_sorted_objects("red_cylinder", 1)
_, closest_greens = await self.get_sorted_objects("green_cylinder", 1)
- # Rename the totems for their symantic name
+ # Rename the totems for their semantic name
green_close = closest_greens[0]
red_close = closest_reds[0]
@@ -83,7 +83,7 @@ async def run(self, parameters):
_, closest_reds = await self.get_sorted_objects("red_cylinder", 2)
_, closest_greens = await self.get_sorted_objects("green_cylinder", 2)
- # Rename the totems for their symantic name
+ # Rename the totems for their semantic name
green_far = closest_greens[1]
red_far = closest_reds[1]
diff --git a/NaviGator/mission_control/navigator_missions/navigator_missions/detect_deliver_2016.py b/NaviGator/mission_control/navigator_missions/navigator_missions/detect_deliver_2016.py
index bc95612b0..dee540de0 100644
--- a/NaviGator/mission_control/navigator_missions/navigator_missions/detect_deliver_2016.py
+++ b/NaviGator/mission_control/navigator_missions/navigator_missions/detect_deliver_2016.py
@@ -153,9 +153,7 @@ async def do_circle():
await self.nh.sleep(0.25)
continue
fprint(
- "Shape ({}found, using normal to look at other 3 shapes if needed".format(
- res[0],
- ),
+ f"Shape ({res[0]}found, using normal to look at other 3 shapes if needed",
title="DETECT DELIVER",
msg_color="green",
)
@@ -240,10 +238,7 @@ async def search_sides(self, moves):
self.shape_pose = found_pose
return
fprint(
- "Saw (Shape={}, Color={}) on this side".format(
- shape_color[0],
- shape_color[1],
- ),
+ f"Saw (Shape={shape_color[0]}, Color={shape_color[1]}) on this side",
title="DETECT DELIVER",
msg_color="green",
)
@@ -287,10 +282,7 @@ def select_backup_shape(self):
self.shape_pose = point_normal
if self.Shape == shape or self.Color == color:
fprint(
- "Correct shape not found, resorting to shape={} color={}".format(
- shape,
- color,
- ),
+ f"Correct shape not found, resorting to shape={shape} color={color}",
title="DETECT DELIVER",
msg_color="yellow",
)
@@ -430,9 +422,7 @@ async def shoot_and_align_forest(self):
move = await self.align_to_target()
if move.failure_reason != "":
fprint(
- "Error Aligning with target = {}. Ending mission :(".format(
- move.failure_reason,
- ),
+ f"Error Aligning with target = {move.failure_reason}. Ending mission :(",
title="DETECT DELIVER",
msg_color="red",
)
@@ -479,9 +469,7 @@ async def shoot_and_align(self):
move = await self.align_to_target()
if move.failure_reason != "":
fprint(
- "Error Aligning with target = {}. Ending mission :(".format(
- move.failure_reason,
- ),
+ f"Error Aligning with target = {move.failure_reason}. Ending mission :(",
title="DETECT DELIVER",
msg_color="red",
)
diff --git a/NaviGator/mission_control/navigator_missions/navigator_missions/identify_dock.py b/NaviGator/mission_control/navigator_missions/navigator_missions/identify_dock.py
index 28419f6b6..6d2203826 100644
--- a/NaviGator/mission_control/navigator_missions/navigator_missions/identify_dock.py
+++ b/NaviGator/mission_control/navigator_missions/navigator_missions/identify_dock.py
@@ -150,10 +150,7 @@ async def check_bays(self):
def update_shape(self, shape_res, normal_res, tf):
print_good(
- "Found (Shape={}, Color={} in a bay".format(
- shape_res.Shape,
- shape_res.Color,
- ),
+ f"Found (Shape={shape_res.Shape}, Color={shape_res.Color} in a bay",
)
self.identified_shapes[(shape_res.Shape, shape_res.Color)] = self.get_shape_pos(
normal_res,
diff --git a/NaviGator/mission_control/navigator_missions/navigator_missions/move.py b/NaviGator/mission_control/navigator_missions/navigator_missions/move.py
index 03017c09b..a9debd213 100755
--- a/NaviGator/mission_control/navigator_missions/navigator_missions/move.py
+++ b/NaviGator/mission_control/navigator_missions/navigator_missions/move.py
@@ -149,9 +149,7 @@ async def run(self, args):
"yl": "yaw_left",
"yr": "yaw_right",
}
- command = (
- command if command not in shorthand.keys() else shorthand[command]
- )
+ command = shorthand.get(command, command)
movement = getattr(self.move, command)
trans_move = command[:3] != "yaw"
diff --git a/NaviGator/mission_control/navigator_missions/navigator_missions/navigation.py b/NaviGator/mission_control/navigator_missions/navigator_missions/navigation.py
index 9b977b0bf..7812e5108 100644
--- a/NaviGator/mission_control/navigator_missions/navigator_missions/navigation.py
+++ b/NaviGator/mission_control/navigator_missions/navigator_missions/navigation.py
@@ -187,9 +187,7 @@ async def explore_closest_until(self, is_done, filter_and_sort):
)
if classification_index != -1:
self.send_feedback(
- "{} identified. Canceling investigation".format(
- move_id_tuple[1],
- ),
+ f"{move_id_tuple[1]} identified. Canceling investigation",
)
move_task.cancel()
diff --git a/NaviGator/mission_control/navigator_missions/navigator_missions/pose_editor.py b/NaviGator/mission_control/navigator_missions/navigator_missions/pose_editor.py
index 5f25f36ab..d2b1855cd 100644
--- a/NaviGator/mission_control/navigator_missions/navigator_missions/pose_editor.py
+++ b/NaviGator/mission_control/navigator_missions/navigator_missions/pose_editor.py
@@ -341,9 +341,7 @@ def as_MoveGoal(self, move_type=MoveGoal.DRIVE, **kwargs):
for key in kwargs:
if not hasattr(MoveGoal, key):
fprint(
- "MoveGoal msg doesn't have a field called '{}' you tried to set via kwargs.".format(
- key,
- ),
+ f"MoveGoal msg doesn't have a field called '{key}' you tried to set via kwargs.",
title="POSE_EDITOR",
msg_color="red",
)
diff --git a/NaviGator/mission_control/navigator_missions/vrx_missions/dock.py b/NaviGator/mission_control/navigator_missions/vrx_missions/dock.py
index 23d7cdfb3..44a3cacae 100644
--- a/NaviGator/mission_control/navigator_missions/vrx_missions/dock.py
+++ b/NaviGator/mission_control/navigator_missions/vrx_missions/dock.py
@@ -607,7 +607,7 @@ async def prepare_for_docking(self):
# This function looks at the two squares in front of the boat
# and it gets the middle pixel between the two squares.
# If the middle pixel is for some reason not in the middle of our camera...
- # adjust the boat postiion before docking
+ # adjust the boat position before docking
print("prepare for landing!")
img = await self.front_left_camera_sub.get_next_message()
diff --git a/NaviGator/mission_control/navigator_missions/vrx_missions/vrx.py b/NaviGator/mission_control/navigator_missions/vrx_missions/vrx.py
index d629df644..91514c01d 100644
--- a/NaviGator/mission_control/navigator_missions/vrx_missions/vrx.py
+++ b/NaviGator/mission_control/navigator_missions/vrx_missions/vrx.py
@@ -29,145 +29,143 @@
class Vrx(NaviGatorMission):
nh: NodeHandle
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- @staticmethod
- async def init():
- if hasattr(Vrx, "_vrx_init"):
+ @classmethod
+ async def setup(cls):
+ if hasattr(cls, "_cls_init"):
return
- Vrx.from_lla = Vrx.nh.get_service_client("/fromLL", FromLL)
- Vrx.to_lla = Vrx.nh.get_service_client("/toLL", ToLL)
- Vrx.task_info_sub = Vrx.nh.subscribe("/vrx/task/info", Task)
- await Vrx.task_info_sub.setup()
- Vrx.scan_dock_color_sequence = Vrx.nh.get_service_client(
+ cls.from_lla = cls.nh.get_service_client("/fromLL", FromLL)
+ cls.to_lla = cls.nh.get_service_client("/toLL", ToLL)
+ cls.task_info_sub = cls.nh.subscribe("/vrx/task/info", Task)
+ cls.scan_dock_color_sequence = cls.nh.get_service_client(
"/vrx/scan_dock_deliver/color_sequence",
ColorSequence,
)
- Vrx.fire_ball = Vrx.nh.advertise("/wamv/shooters/ball_shooter/fire", Empty)
- Vrx.station_keep_goal = Vrx.nh.subscribe(
+ cls.fire_ball = cls.nh.advertise("/wamv/shooters/ball_shooter/fire", Empty)
+ cls.station_keep_goal = cls.nh.subscribe(
"/vrx/station_keeping/goal",
GeoPoseStamped,
)
- Vrx.wayfinding_path_sub = Vrx.nh.subscribe("/vrx/wayfinding/waypoints", GeoPath)
- Vrx.station_keeping_pose_error = Vrx.nh.subscribe(
+ cls.wayfinding_path_sub = cls.nh.subscribe("/vrx/wayfinding/waypoints", GeoPath)
+ cls.station_keeping_pose_error = cls.nh.subscribe(
"/vrx/station_keeping/pose_error",
Float64,
)
- Vrx.station_keeping_rms_error = Vrx.nh.subscribe(
+ cls.station_keeping_rms_error = cls.nh.subscribe(
"/vrx/station_keeping/rms_error",
Float64,
)
- Vrx.wayfinding_min_errors = Vrx.nh.subscribe(
+ cls.wayfinding_min_errors = cls.nh.subscribe(
"/vrx/wayfinding/min_errors",
Float64MultiArray,
)
- Vrx.wayfinding_mean_error = Vrx.nh.subscribe(
+ cls.wayfinding_mean_error = cls.nh.subscribe(
"/vrx/wayfinding/mean_error",
Float64,
)
- Vrx.perception_landmark = Vrx.nh.advertise(
+ cls.perception_landmark = cls.nh.advertise(
"/vrx/perception/landmark",
GeoPoseStamped,
)
await asyncio.gather(
- Vrx.fire_ball.setup(),
- Vrx.station_keep_goal.setup(),
- Vrx.wayfinding_path_sub.setup(),
- Vrx.station_keeping_pose_error.setup(),
- Vrx.station_keeping_rms_error.setup(),
- Vrx.wayfinding_min_errors.setup(),
- Vrx.wayfinding_mean_error.setup(),
- Vrx.perception_landmark.setup(),
+ cls.task_info_sub.setup(),
+ cls.fire_ball.setup(),
+ cls.station_keep_goal.setup(),
+ cls.wayfinding_path_sub.setup(),
+ cls.station_keeping_pose_error.setup(),
+ cls.station_keeping_rms_error.setup(),
+ cls.wayfinding_min_errors.setup(),
+ cls.wayfinding_mean_error.setup(),
+ cls.perception_landmark.setup(),
)
- Vrx.animal_landmarks = Vrx.nh.subscribe("/vrx/wildlife/animals/poses", GeoPath)
- Vrx.beacon_landmark = Vrx.nh.get_service_client("beaconLocator", AcousticBeacon)
- Vrx.circle_animal = Vrx.nh.get_service_client("/choose_animal", ChooseAnimal)
- Vrx.set_long_waypoint = Vrx.nh.get_service_client(
+ cls.animal_landmarks = cls.nh.subscribe("/vrx/wildlife/animals/poses", GeoPath)
+ cls.beacon_landmark = cls.nh.get_service_client("beaconLocator", AcousticBeacon)
+ cls.circle_animal = cls.nh.get_service_client("/choose_animal", ChooseAnimal)
+ cls.set_long_waypoint = cls.nh.get_service_client(
"/set_long_waypoint",
MoveToWaypoint,
)
- Vrx.yolo_objects = Vrx.nh.subscribe("/yolov7/detections", Detection2DArray)
- Vrx.tf_listener = axros_tf.TransformListener(Vrx.nh)
- await Vrx.tf_listener.setup()
- Vrx.database_response = Vrx.nh.get_service_client(
+ cls.yolo_objects = cls.nh.subscribe("/yolov7/detections", Detection2DArray)
+ cls.tf_listener = axros_tf.TransformListener(cls.nh)
+ await cls.tf_listener.setup()
+ cls.database_response = cls.nh.get_service_client(
"/database/requests",
ObjectDBQuery,
)
- Vrx.get_two_closest_cones = Vrx.nh.get_service_client(
+ cls.get_two_closest_cones = cls.nh.get_service_client(
"/get_two_closest_cones",
TwoClosestCones,
)
await asyncio.gather(
- Vrx.animal_landmarks.setup(),
- Vrx.yolo_objects.setup(),
+ cls.animal_landmarks.setup(),
+ cls.yolo_objects.setup(),
)
- Vrx.pcodar_reset = Vrx.nh.get_service_client("/pcodar/reset", Trigger)
+ cls.pcodar_reset = cls.nh.get_service_client("/pcodar/reset", Trigger)
- Vrx.front_left_camera_info_sub = None
- Vrx.front_left_camera_sub = None
- Vrx.front_right_camera_info_sub = None
- Vrx.front_right_camera_sub = None
+ cls.front_left_camera_info_sub = None
+ cls.front_left_camera_sub = None
+ cls.front_right_camera_info_sub = None
+ cls.front_right_camera_sub = None
- Vrx._vrx_init = True
+ cls._cls_init = True
- @staticmethod
- async def shutdown():
+ @classmethod
+ async def shutdown(cls):
+ return
await asyncio.gather(
- Vrx.task_info_sub.shutdown(),
- Vrx.animal_landmarks.shutdown(),
- Vrx.yolo_objects.shutdown(),
- Vrx.fire_ball.shutdown(),
- Vrx.station_keep_goal.shutdown(),
- Vrx.wayfinding_path_sub.shutdown(),
- Vrx.station_keeping_pose_error.shutdown(),
- Vrx.station_keeping_rms_error.shutdown(),
- Vrx.wayfinding_min_errors.shutdown(),
- Vrx.wayfinding_mean_error.shutdown(),
- Vrx.perception_landmark.shutdown(),
+ cls.task_info_sub.shutdown(),
+ cls.animal_landmarks.shutdown(),
+ cls.yolo_objects.shutdown(),
+ cls.fire_ball.shutdown(),
+ cls.station_keep_goal.shutdown(),
+ cls.wayfinding_path_sub.shutdown(),
+ cls.station_keeping_pose_error.shutdown(),
+ cls.station_keeping_rms_error.shutdown(),
+ cls.wayfinding_min_errors.shutdown(),
+ cls.wayfinding_mean_error.shutdown(),
+ cls.perception_landmark.shutdown(),
)
def cleanup(self):
pass
- @staticmethod
- async def init_front_left_camera():
- if Vrx.front_left_camera_sub is None:
- Vrx.front_left_camera_sub = Vrx.nh.subscribe(
+ @classmethod
+ async def init_front_left_camera(cls):
+ if cls.front_left_camera_sub is None:
+ cls.front_left_camera_sub = cls.nh.subscribe(
"/wamv/sensors/cameras/front_left_camera/image_raw",
Image,
)
- if Vrx.front_left_camera_info_sub is None:
- Vrx.front_left_camera_info_sub = Vrx.nh.subscribe(
+ if cls.front_left_camera_info_sub is None:
+ cls.front_left_camera_info_sub = cls.nh.subscribe(
"/wamv/sensors/cameras/front_left_camera/camera_info",
CameraInfo,
)
await asyncio.gather(
- Vrx.front_left_camera_sub.setup(),
- Vrx.front_left_camera_info_sub.setup(),
+ cls.front_left_camera_sub.setup(),
+ cls.front_left_camera_info_sub.setup(),
)
- @staticmethod
- async def init_front_right_camera():
- if Vrx.front_right_camera_sub is None:
- Vrx.front_right_camera_sub = Vrx.nh.subscribe(
+ @classmethod
+ async def init_front_right_camera(cls):
+ if cls.front_right_camera_sub is None:
+ cls.front_right_camera_sub = cls.nh.subscribe(
"/wamv/sensors/cameras/front_right_camera/image_raw",
Image,
)
- if Vrx.front_right_camera_info_sub is None:
- Vrx.front_right_camera_info_sub = Vrx.nh.subscribe(
+ if cls.front_right_camera_info_sub is None:
+ cls.front_right_camera_info_sub = cls.nh.subscribe(
"/wamv/sensors/cameras/front_right_camera/camera_info",
CameraInfo,
)
await asyncio.gather(
- Vrx.front_right_camera_sub.setup(),
- Vrx.front_right_camera_info_sub.setup(),
+ cls.front_right_camera_sub.setup(),
+ cls.front_right_camera_info_sub.setup(),
)
async def geo_pose_to_enu_pose(self, geo):
diff --git a/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_navigation.py b/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_navigation.py
index 3086e39b5..7ef98c064 100644
--- a/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_navigation.py
+++ b/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_navigation.py
@@ -151,9 +151,7 @@ async def explore_closest_until(self, is_done, filter_and_sort):
)
if classification_index != -1:
self.send_feedback(
- "{} identified. Canceling investigation".format(
- move_id_tuple[1],
- ),
+ f"{move_id_tuple[1]} identified. Canceling investigation",
)
move_id_tuple[0].cancel()
await self.nh.sleep(1.0)
diff --git a/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_perception.py b/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_perception.py
index f1483416f..2b1ef6d50 100644
--- a/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_perception.py
+++ b/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_perception.py
@@ -79,11 +79,7 @@ async def run(self, parameters):
)
elif objects[key] != new_objects[key]:
self.send_feedback(
- "{} changed from {} to {}".format(
- key,
- objects[key],
- new_objects[key],
- ),
+ f"{key} changed from {objects[key]} to {new_objects[key]}",
)
await self.announce_object(
key,
diff --git a/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_wayfinding_2.py b/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_wayfinding_2.py
index 60496d0b8..966f38be0 100644
--- a/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_wayfinding_2.py
+++ b/NaviGator/mission_control/navigator_missions/vrx_missions/vrx_wayfinding_2.py
@@ -5,6 +5,7 @@
from .vrx import Vrx
___author___ = "Alex Perez"
+# Optimized by Daniel Parra
class VrxWayfinding2(Vrx):
@@ -42,12 +43,18 @@ async def run(self, parameters):
poses = poses[:start_pose_index]
path = path[1:]
- # self.send_feedback('Sorted poses' + str(poses))
await self.wait_for_task_such_that(lambda task: task.state in ["running"])
# do movements
for index in path:
self.send_feedback(f"Going to {poses[index]}")
-
# Go to goal
+ P = 0.85
+ part_way_point = [x * P for x in poses[index][0][:-1]]
+ part_way_point.append(poses[index][0][-1])
+ self.send_feedback(
+ f"\nPartway:\n{part_way_point}\nEndPoint:\n{poses[index][0]}",
+ )
+
+ await self.send_trajectory_without_path([part_way_point, poses[index][1]])
await self.send_trajectory_without_path(poses[index])
diff --git a/NaviGator/satellite/rviz_satellite/src/aerialmap_display.cpp b/NaviGator/satellite/rviz_satellite/src/aerialmap_display.cpp
index 22a307f76..bf5ec8b20 100644
--- a/NaviGator/satellite/rviz_satellite/src/aerialmap_display.cpp
+++ b/NaviGator/satellite/rviz_satellite/src/aerialmap_display.cpp
@@ -416,7 +416,7 @@ void AerialMapDisplay::assembleScene()
// determine location of this tile, flipping y in the process
const double x = (tile.x() - loader_->centerTileX()) * tile_w + origin_x;
const double y = -(tile.y() - loader_->centerTileY()) * tile_h + origin_y;
- // don't re-use any ids
+ // don't reuse any ids
const std::string name_suffix = std::to_string(tile.x()) + "_" + std::to_string(tile.y()) + "_" +
std::to_string(map_id_) + "_" + std::to_string(scene_id_);
diff --git a/NaviGator/scripts/bash_aliases.sh b/NaviGator/scripts/bash_aliases.sh
index 216b1ff80..de6da5f4b 100755
--- a/NaviGator/scripts/bash_aliases.sh
+++ b/NaviGator/scripts/bash_aliases.sh
@@ -18,7 +18,7 @@ nthrust() {
topic="/$1_motor/cmd"
publishers=$(rostopic info "$topic" | grep Publishers)
if [ "$publishers" != "Publishers: None" ]; then
- echo "Somone is already publishing to $topic. Perhaps you need to kill thrust mapper?"
+ echo "Someone is already publishing to $topic. Perhaps you need to kill thrust mapper?"
return 1
fi
rostopic pub "$topic" "roboteq_msgs/Command" "setpoint: $2" -r100
diff --git a/NaviGator/simulation/navigator_gazebo/test/test_sim_integration.py b/NaviGator/simulation/navigator_gazebo/test/test_sim_integration.py
index 3cb7ab8a7..46e20b856 100755
--- a/NaviGator/simulation/navigator_gazebo/test/test_sim_integration.py
+++ b/NaviGator/simulation/navigator_gazebo/test/test_sim_integration.py
@@ -71,10 +71,7 @@ def test_odom(self):
rospy.sleep(0.1)
self.assertTrue(
len(self.odom_pos_msg) == 3 and len(self.odom_ori_msg) == 4,
- msg="POS, ORI: {}, {}".format(
- len(self.odom_pos_msg),
- len(self.odom_ori_msg),
- ),
+ msg=f"POS, ORI: {len(self.odom_pos_msg)}, {len(self.odom_ori_msg)}",
)
initial_pos = [-1.2319, 0.0, 0.0]
initial_ori = [0.0, 0.0, 0.0, 1.0]
@@ -100,10 +97,7 @@ def test_absodom(self):
rospy.sleep(0.1)
self.assertTrue(
len(self.absodom_pos_msg) == 3 and len(self.absodom_ori_msg) == 4,
- msg="POS, ORI: {}, {}".format(
- len(self.absodom_pos_msg),
- len(self.absodom_ori_msg),
- ),
+ msg=f"POS, ORI: {len(self.absodom_pos_msg)}, {len(self.absodom_ori_msg)}",
)
initial_pos = [743789.637462, -5503821.36715, 3125622.10477]
initial_ori = [0.0, 0.0, 0.0, 1.0]
@@ -122,25 +116,13 @@ def verify_pos_ori(self, pos, initial_pos, ori, initial_ori, topic):
actual,
initial,
places=0,
- msg=(
- "Error: {} position is: {} should be {}".format(
- topic,
- actual,
- initial,
- )
- ),
+ msg=(f"Error: {topic} position is: {actual} should be {initial}"),
)
for actual, initial in zip(ori, initial_ori):
self.assertEqual(
actual,
initial,
- msg=(
- "Error: {} orientation is: {} should be {}".format(
- topic,
- actual,
- initial,
- )
- ),
+ msg=(f"Error: {topic} orientation is: {actual} should be {initial}"),
)
def cam_info_right_cb(self, msg):
@@ -229,10 +211,7 @@ def verify_not_empty(self, data_lists, num_topics):
self.assertEqual(
len(data_lists),
num_topics,
- msg="Number of topics is {}, should be {}".format(
- len(data_lists),
- num_topics,
- ),
+ msg=f"Number of topics is {len(data_lists)}, should be {num_topics}",
)
for data_list in data_lists:
self.assertNotEqual(len(data_list), 0, msg="data is empty")
@@ -243,13 +222,7 @@ def verify_info(self, res_info, initial_info, topic):
self.assertNotEqual(
actual_dim,
initial_dim,
- msg=(
- "Error: {} is: {} shouldn't be {}".format(
- topic,
- actual_dim,
- initial_dim,
- )
- ),
+ msg=(f"Error: {topic} is: {actual_dim} shouldn't be {initial_dim}"),
)
diff --git a/NaviGator/utils/navigator_msgs/srv/GetDockBays.srv b/NaviGator/utils/navigator_msgs/srv/GetDockBays.srv
index 9a39764bd..7081b1b07 100644
--- a/NaviGator/utils/navigator_msgs/srv/GetDockBays.srv
+++ b/NaviGator/utils/navigator_msgs/srv/GetDockBays.srv
@@ -2,4 +2,4 @@
geometry_msgs/Point[3] bays #The positions in ENU frame of the center of the three bays 0=left, 1=center, 2=right
geometry_msgs/Vector3 normal #Vector or normal pointing away from plane of dock back
bool success #False if an error occurred getting dock bays
-string error #Descripion of error if success=false
+string error #Description of error if success=false
diff --git a/NaviGator/utils/navigator_robotx_comms/nodes/robotx_comms_client.py b/NaviGator/utils/navigator_robotx_comms/nodes/robotx_comms_client.py
index d8583f010..59e6139e3 100755
--- a/NaviGator/utils/navigator_robotx_comms/nodes/robotx_comms_client.py
+++ b/NaviGator/utils/navigator_robotx_comms/nodes/robotx_comms_client.py
@@ -559,10 +559,7 @@ def connect(self) -> None:
"""
if not self.connected:
rospy.loginfo(
- "Attempting Connection to TD Server at {}:{}".format(
- self.tcp_ip,
- self.tcp_port,
- ),
+ f"Attempting Connection to TD Server at {self.tcp_ip}:{self.tcp_port}",
)
while not self.connected and not rospy.is_shutdown():
# recreate socket
diff --git a/NaviGator/utils/navigator_tools/navigator_tools/object_database_helper.py b/NaviGator/utils/navigator_tools/navigator_tools/object_database_helper.py
index 0798c78e0..5cb8762cb 100644
--- a/NaviGator/utils/navigator_tools/navigator_tools/object_database_helper.py
+++ b/NaviGator/utils/navigator_tools/navigator_tools/object_database_helper.py
@@ -1,4 +1,3 @@
-"""Use the DBHelper class to interface with the Database without having to deal with ROS things."""
import asyncio
import sys
import time
@@ -14,10 +13,29 @@
class DBHelper:
- """DBHelper class."""
+ """
+ Use the DBHelper class to interface with the Database without having to deal with ROS things.
+
+ Attributes:
+ found (bool): checks whether the object is what the user has been looking for.
+ nh (axros.NodeHandle): processes database requests.
+ position (int): the current position of the object.
+ rot (): one of the dimensional values.
+ new_object_subscriber (): an object that is being called from the database.
+ ensuring_objects (bool): a variable state for the object.
+ ensuring_object_dep (): a list of objects being used for storage.
+ ensuring_object_cb (): this is considered when it is an "ensuring_objects".
+ looking_for (): a setter variable to which a name is being assigned.
+ is_found (bool): determines whether the object is found or not.
+ """
def __init__(self, nh):
- """Initialize the DB helper class."""
+ """
+ Initialize the DB helper class.
+
+ Args:
+ nh(NodeHandle): NodeHandle object
+ """
self.found = set()
self.nh = nh
self.position = None
@@ -30,7 +48,12 @@ def __init__(self, nh):
self.is_found = False
async def init_(self, navigator=None):
- """Initialize the axros parts of the DBHelper."""
+ """
+ Initialize the axros parts of the DBHelper.
+
+ Args:
+ navigator (NaviGator | None): Base NaviGator object
+ """
# self._sub_database = yield self.nh.subscribe('/database/objects', PerceptionObjectArray, self.object_cb)
self._database = self.nh.get_service_client("/database/requests", ObjectDBQuery)
self.navigator = navigator
@@ -43,21 +66,37 @@ async def init_(self, navigator=None):
return self
def _odom_cb(self, odom):
+ """
+ Sets the position and the rot values.
+
+ Args:
+ odom (object): Odom
+ """
self.position, self.rot = nt.odometry_to_numpy(odom)[0]
async def get_object_by_id(self, my_id):
+ """
+ Retrieves the object with the associated "my_id".
+
+ Args:
+ my_id (int): an "id" of the object is passed in.
+
+ Returns:
+ An individual object is being returned with a unique id.
+ """
print(my_id)
req = ObjectDBQueryRequest()
req.name = "all"
resp = await self._database(req)
- ans = [obj for obj in resp.objects if obj.id == my_id][0]
+ ans = next(obj for obj in resp.objects if obj.id == my_id)
return ans
async def begin_observing(self, cb):
"""
Get notified when a new object is added to the database.
- cb : The callback that is called when a new object is added to the database
+ Args:
+ cb : The callback that is called when a new object is added to the database.
"""
self.new_object_subscriber = cb
req = ObjectDBQueryRequest()
@@ -78,6 +117,12 @@ async def begin_observing(self, cb):
self.new_object_subscriber(o)
async def get_unknown_and_low_conf(self):
+ """
+ Gets unknown objects that are of low confidence.
+
+ Returns:
+ Objects that meet certain criteria.
+ """
req = ObjectDBQueryRequest()
req.name = "all"
resp = await self._database(req)
@@ -91,9 +136,21 @@ async def get_unknown_and_low_conf(self):
return m
def set_looking_for(self, name):
+ """
+ Setting to a name that is being looked for.
+
+ Args:
+ name (string): name of the object.
+ """
self.looking_for = name
- def is_found_func(self):
+ def is_found_func(self) -> bool:
+ """
+ Determines whether the object is being found or not.
+
+ Returns:
+ The existence of the object is returned.
+ """
if self.is_found:
self.looking_for = None
self.is_found = False
@@ -101,7 +158,12 @@ def is_found_func(self):
return False
def object_cb(self, perception_objects):
- """Callback for the object database."""
+ """
+ Callback for the object database.
+
+ Args:
+ perception_objects (object): a list of objects that are passed.
+ """
self.total_num = len(perception_objects.objects)
for o in perception_objects.objects:
if o.name == self.looking_for:
@@ -120,12 +182,23 @@ def object_cb(self, perception_objects):
self.ensuring_object_cb(missings_objs)
def remove_found(self, name):
- """Remove an object that has been listed as found."""
+ """
+ Remove an object that has been listed as found.
+
+ Args:
+ name (string): a name of the object is being passed in.
+ """
self.found.remove(name)
def ensure_object_permanence(self, object_dep, cb):
- """Ensure that all the objects in the object_dep list remain in the database.
- Call the callback if this isn't true."""
+ """
+ Ensure that all the objects in the object_dep list remain in the database.
+ Call the callback if this isn't true.
+
+ Args:
+ object_dep: a new object is passed in order to be set.
+ cb : The callback that is called when a new object is added to the database.
+ """
if object_dep is None or cb is None:
return
self.ensuring_objects = True
@@ -133,10 +206,21 @@ def ensure_object_permanence(self, object_dep, cb):
self.ensuring_object_dep = object_dep
def stop_ensuring_object_permanence(self):
- """Stop ensuring that objects remain in the database."""
+ """
+ Stop ensuring that objects remain in the database.
+ """
self.ensuring_objects = False
- def _wait_for_position(self, timeout=10):
+ def _wait_for_position(self, timeout=10) -> bool:
+ """
+ A possible position is being stored in a variable.
+
+ Args:
+ timeout (int): time limit to retrieve something.
+
+ Returns:
+ bool: Determines whether the position is found within the time limit.
+ """
count = 0
while self.position is None:
if self.navigator is not None:
@@ -148,7 +232,15 @@ def _wait_for_position(self, timeout=10):
return True
async def get_closest_object(self, objects):
- """Get the closest mission."""
+ """
+ Get the closest mission.
+
+ Args:
+ objects (object): a list of objects are being passed in.
+
+ Returns:
+ A object with the closest mission / distance is returned.
+ """
pobjs = []
for obj in objects:
req = ObjectDBQueryRequest()
@@ -171,6 +263,15 @@ async def get_closest_object(self, objects):
return min_obj
async def _dist(self, x):
+ """
+ Finds the distance of the object keeping into account its current position.
+
+ Args:
+ x (object): a specific object is being passed in order to retrieve its position.
+
+ Returns:
+ the distance between the two objects is being returned.
+ """
if self.position is None:
success = asyncio.create_task(self._wait_for_position)
if not success:
@@ -188,7 +289,18 @@ async def get_object(
thresh=50,
thresh_strict=50,
):
- """Get an object from the database."""
+ """
+ Get an object from the database.
+
+ Args:
+ object_name (string): the name of the object is passed in.
+ volume_only (bool): determines whether it is volume-based or not.
+ thresh (int): a maximum distance is passed in.
+ thresh_strict(int): a more strict maximum distance is passed in.
+
+ Returns:
+ closest_potential_object (object): returns the object that is within the closest range.
+ """
if volume_only:
req = ObjectDBQueryRequest()
req.name = object_name
@@ -233,6 +345,15 @@ async def get_object(
return closest_potential_object
def wait_for_additional_objects(self, timeout=60):
+ """
+ Returns true/false whether additional objects are being passed in.
+
+ Args:
+ timeout (int): maximum time limit of 60 seconds to run the program.
+
+ Returns:
+ (bool): determines whether additional objects are added.
+ """
num_items = self.num_items
start = time.time()
while timeout < time.time() - start:
@@ -241,14 +362,36 @@ def wait_for_additional_objects(self, timeout=60):
return False
def set_color(self, color, name):
- """Set the color of an object in the database."""
+ """
+ Sets the color of an object in the database.
+
+ Args:
+ color: the new color of the object is passed in.
+ name: the name of the object is passed in.
+ """
raise NotImplementedError
def set_fake_position(self, pos):
- """Set the position of a fake perception object."""
+ """
+ Sets the position of a fake perception object.
+
+ Args:
+ pos (int): the new position of the object is passed in.
+ """
raise NotImplementedError
async def get_objects_in_radius(self, pos, radius, objects="all"):
+ """
+ Retrieves the objects that are present within the radius.
+
+ Args:
+ pos (int): the position of the object is passed in.
+ radius (int): the radius of the object is passed in.
+ objects (object): this is a list of all the objects that needs to be compared.
+
+ Returns:
+ ans (object): returns the objects that are present within the radius.
+ """
req = ObjectDBQueryRequest()
req.name = "all"
resp = await self._database(req)
diff --git a/NaviGator/utils/navigator_tools/nodes/estimated_object_setter.py b/NaviGator/utils/navigator_tools/nodes/estimated_object_setter.py
index 99845b004..57d4b7c01 100755
--- a/NaviGator/utils/navigator_tools/nodes/estimated_object_setter.py
+++ b/NaviGator/utils/navigator_tools/nodes/estimated_object_setter.py
@@ -24,7 +24,7 @@ async def main(name, lla):
name = "_".join(txt.title() for txt in name.split("_"))
point = await convert.request(CoordinateConversionRequest(frame="lla", point=lla))
- await db(ObjectDBQueryRequest(cmd="{}={p[0]}, {p[1]}".format(name, p=point.enu)))
+ await db(ObjectDBQueryRequest(cmd=f"{name}={point.enu[0]}, {point.enu[1]}"))
if __name__ == "__main__":
diff --git a/NaviGator/utils/navigator_tools/nodes/navigator_status_tui b/NaviGator/utils/navigator_tools/nodes/navigator_status_tui
index 3efa0a5d1..0fc39eb3b 100755
--- a/NaviGator/utils/navigator_tools/nodes/navigator_status_tui
+++ b/NaviGator/utils/navigator_tools/nodes/navigator_status_tui
@@ -35,7 +35,7 @@ class nav_tui:
self.panel.hide()
panel.update_panels()
self.rate = rospy.Rate(2) # Fixed rate for while loop to update at: 2 hz
- # The following are default field initalizations for various values that that will be overwritten
+ # The following are default field initializations for various values that that will be overwritten
self.voltage = 0
self.wrench = None
self.LAT = None
@@ -214,15 +214,13 @@ class nav_tui:
if len(self.decode_fault_status(self.FL_fault)) == 0:
self.window.addstr(5, self.x / 2 - 7, "No faults", curses.color_pair(3))
else:
- n = 0
- for fault in self.decode_fault_status(self.FL_fault):
+ for n, fault in enumerate(self.decode_fault_status(self.FL_fault)):
self.window.addstr(
5 + n,
self.x / 2 - 7,
"%s" % fault,
curses.color_pair(1),
)
- n += 1
self.window.addstr(14, self.x / 2 - 7, "Back Left", color)
if len(self.decode_fault_status(self.BL_fault)) == 0:
diff --git a/NaviGator/utils/remote_control/navigator_emergency_control/nodes/navigator_emergency.py b/NaviGator/utils/remote_control/navigator_emergency_control/nodes/navigator_emergency.py
index 8077b4601..49b799fa4 100755
--- a/NaviGator/utils/remote_control/navigator_emergency_control/nodes/navigator_emergency.py
+++ b/NaviGator/utils/remote_control/navigator_emergency_control/nodes/navigator_emergency.py
@@ -67,8 +67,7 @@ def reset(self) -> None:
def check_for_timeout(self, joy: Joy):
"""
- Consists of several procedures that reference parameters that are retrieved from the "Joy" object in
- order to determine the state of the controller or whether it is a timeout phase.
+ This checks for a particular duration when the controller times out.
Args:
joy (Joy): The Joy message.
@@ -95,7 +94,7 @@ def check_for_timeout(self, joy: Joy):
def joy_recieved(self, joy: Joy) -> None:
"""
- Button elements are being assigned and simplied to readable names. The
+ Button elements are being assigned and simplified to readable names. The
number of deployments or retractions for thrusters are being updated based
on several conditions. Moreover, additional settings are changed based on the
state of the controller and the activation of potential alarms or switches.
diff --git a/NaviGator/utils/voltage_gui/src/voltage_gui.py b/NaviGator/utils/voltage_gui/src/voltage_gui.py
index 91e5396e6..79e6a0e85 100644
--- a/NaviGator/utils/voltage_gui/src/voltage_gui.py
+++ b/NaviGator/utils/voltage_gui/src/voltage_gui.py
@@ -11,15 +11,33 @@
from roboteq_msgs.msg import Feedback
from std_msgs.msg import Float32
-# Display voltage from battery_monitor and the four motors to a GUI
-
-
__author__ = "Joseph Brooks"
__email__ = "brooksturtle@ufl.edu"
__license__ = "MIT"
class voltageGUI(Plugin):
+ """
+ Display voltage from battery_monitor and the four motors to a GUI
+
+ Attributes:
+ height (int): defines the height of the screen
+ fontSize(int): sets the font size of the screen
+ warningCounter(int): prints the number of warning signs
+ paramCounter(int): the number of times "updateLabel" function is called
+ heightRatio(int): the ratio change in height that is caused by the resize
+ gotParams(bool): this checks to see whether the parameters are set
+ lowThreshold(int): colors values which include Good (Green), Warning (Yellow), and Critical (Red)
+ criticalThreshold(int): colors values which include Good (Green), Warning (Yellow), and Critical (Red)
+ paramCounter(int): number of parameters that are called by function
+
+ battery_voltage(int): the amount of voltage that is stored in the battery
+ voltageFL(int): the voltage that is being supplied from dataFL
+ voltageFR(int): the voltage that is being supplied from dataFR
+ voltageBL(int): the voltage that is being supplied from dataBL
+ voltageBR(int): the voltage that is being supplied from dataBR
+ """
+
def __init__(self, context):
super().__init__(context)
self.setObjectName("voltage_gui")
@@ -33,8 +51,10 @@ def __init__(self, context):
context.add_widget(self.myWidget)
self.runGUI()
- # Updates Values displayed in GUI every second
def runGUI(self) -> None:
+ """
+ Updates Values displayed in GUI every second
+ """
app = QApplication(sys.argv)
self.myWidget.show()
while 0 == 0:
@@ -57,12 +77,12 @@ def __init__(self):
# Whenever the screen is resized the resizeFont function is called
self.resized.connect(self.resizeFont)
- self.height = VoltageWidget.frameGeometry(self).height()
+ self.height = VoltageWidget.frameGeometry(self).height() # done
- self.fontSize = 40
+ self.fontSize = 40 # done
- self.warningCounter = 0
- self.paramCounter = 0
+ self.warningCounter = 0 # done
+ self.paramCounter = 0 # done
self.initThresh()
@@ -80,27 +100,67 @@ def __init__(self):
# The functions that the subscribers call in order to get new data
def updateMain(self, mainData: Float32) -> None:
+ """
+ It is one of the functions that the subscribers call in order to get new data.
+
+ Args:
+ mainData: it is a float value that is being passed in for a variable to be set to.
+ """
self.battery_voltage = mainData
def update_FL(self, dataFL: Feedback) -> None:
+ """
+ It is one of the functions that the subscribers call in order to get new data.
+
+ Args:
+ dataFL: it is a feedback value that is being passed in for a variable to be set to.
+ """
self.voltageFL = dataFL.supply_voltage
def update_FR(self, dataFR: Feedback) -> None:
+ """
+ It is one of the functions that the subscribers call in order to get new data.
+
+ Args:
+ dataFR: it is a feedback value that is being passed in for a variable to be set to.
+ """
self.voltageFR = dataFR.supply_voltage
def update_BL(self, dataBL: Feedback) -> None:
+ """
+ It is one of the functions that the subscribers call in order to get new data.
+
+ Args:
+ dataBL: it is a feedback value that is being passed in for a variable to be set to.
+ """
self.voltageBL = dataBL.supply_voltage
def update_BR(self, dataBR: Feedback) -> None:
+ """
+ It is one of the functions that the subscribers call in order to get new data.
+
+ Args:
+ dataBR: it is a feedback value that is being passed in for a variable to be set to.
+ """
self.voltageBR = dataBR.supply_voltage
- # Part of signal that notifies program whenever window is resized
- def resizeEvent(self, event):
+ def resizeEvent(self, event): # done
+ """
+ Part of signal that notifies program whenever window is resized
+
+ Args:
+ event: an event object is being passed in.
+
+ Returns:
+ An event was being returned with a different size.
+ """
self.resized.emit()
return super().resizeEvent(event)
- # Increase/decrease size of fonts based on window resize
- def resizeFont(self) -> None:
+ def resizeFont(self) -> None: # done
+ """
+ Increase/decrease size of fonts based on window resize
+ """
# gets new window dimensions, the self is needed because we are referencing
# our VoltageWidget class
height = VoltageWidget.frameGeometry(self).height()
@@ -124,8 +184,11 @@ def resizeFont(self) -> None:
threshFont = QtGui.QFont("Times", (self.fontSize) / 3, QtGui.QFont.Bold)
self.labelThresh.setFont(threshFont)
- # Sets the text of the thrshold info box
+ # Sets the text of the threshold info box
def initThresh(self) -> None:
+ """
+ Sets the text of the threshold info box
+ """
# Low and Critical decide what colors the boxes take for
# Good (Green), Warning (Yellow), and Critical (Red)
# If the parameter server has not set these values then we use the DEFAULT
@@ -159,8 +222,10 @@ def initThresh(self) -> None:
threshFont = QtGui.QFont("Times", (self.fontSize) / 3, QtGui.QFont.Bold)
self.labelThresh.setFont(threshFont)
- # If self.gotParams is False, the updateLabel function calls testParams every 5 seconds
- def testParams(self) -> None:
+ def testParams(self) -> None: # done
+ """
+ If self.gotParams is False, the updateLabel function calls testParams every 5 seconds
+ """
try:
self.lowThreshold = rospy.get_param("battery-voltage/low")
self.criticalThreshold = rospy.get_param("battery-voltage/critical")
@@ -180,8 +245,13 @@ def testParams(self) -> None:
)
self.labelThresh.setText(threshText)
- # sets colors of boxes based on current values of voltages for each box
- def setColors(self, numMain: float) -> None:
+ def setColors(self, numMain: float) -> None: # done
+ """
+ sets colors of boxes based on current values of voltages for each box
+
+ Args:
+ numMain(float): box object that stores current values
+ """
if numMain > self.lowThreshold:
self.labelMain.setStyleSheet(
"QLabel { background-color : green; color : white; }",
@@ -260,7 +330,9 @@ def setColors(self, numMain: float) -> None:
)
def updateLabel(self) -> None:
- # Tries self.gotParams every 3 function calls
+ """
+ Tries self.gotParams every 3 function calls
+ """
self.paramCounter = self.paramCounter + 1
if self.gotParams is False and self.paramCounter >= 3:
self.testParams()
diff --git a/SubjuGator/command/subjugator_alarm/alarm_handlers/kill.py b/SubjuGator/command/subjugator_alarm/alarm_handlers/kill.py
index d0d751f0a..4055694d8 100644
--- a/SubjuGator/command/subjugator_alarm/alarm_handlers/kill.py
+++ b/SubjuGator/command/subjugator_alarm/alarm_handlers/kill.py
@@ -101,10 +101,7 @@ def _bag_done_cb(self, status, result):
rospy.loginfo(f"KILL BAG WRITTEN TO {result.filename}")
else:
rospy.logwarn(
- "KILL BAG {}, status: {}".format(
- TerminalState.to_string(status),
- result.status,
- ),
+ f"KILL BAG {TerminalState.to_string(status)}, status: {result.status}",
)
def bagger_dump(self):
@@ -117,7 +114,7 @@ def bagger_dump(self):
rospy.logwarn("BAG_ALWAYS or BAG_KILL not set. Not making kill bag.")
return
goal = BagOnlineGoal(bag_name="kill.bag")
- goal.topics = os.environ["BAG_ALWAYS"] + " " + os.environ["bag_kill"]
+ goal.topics = os.environ["BAG_ALWAYS"] + " " + os.environ["BAG_KILL"]
self.bag_client.send_goal(goal, done_cb=self._bag_done_cb)
def meta_predicate(self, meta_alarm, sub_alarms):
@@ -170,5 +167,5 @@ def meta_predicate(self, meta_alarm, sub_alarms):
# Raised if any alarms besides the two above are raised
return any(
- [alarm.raised for name, alarm in sub_alarms.items() if name not in ignore],
+ alarm.raised for name, alarm in sub_alarms.items() if name not in ignore
)
diff --git a/SubjuGator/command/subjugator_alarm/alarm_handlers/odom_kill.py b/SubjuGator/command/subjugator_alarm/alarm_handlers/odom_kill.py
index 4a7638909..90a8e817b 100644
--- a/SubjuGator/command/subjugator_alarm/alarm_handlers/odom_kill.py
+++ b/SubjuGator/command/subjugator_alarm/alarm_handlers/odom_kill.py
@@ -101,9 +101,7 @@ def check_continuity(self, new_odom_msg: Odometry): # True if 'continuous'
if jump > self.MAX_JUMP:
rospy.logerr("ODOM DISCONTINUITY DETECTED")
self.ab.raise_alarm(
- problem_description="ODOM DISCONTINUITY DETECTED JUMPED {} METERS".format(
- jump,
- ),
+ problem_description=f"ODOM DISCONTINUITY DETECTED JUMPED {jump} METERS",
severity=5,
)
self.odom_discontinuity = True
@@ -120,9 +118,7 @@ def need_kill(self):
if odom_loss:
rospy.logerr_throttle(
1,
- "LOST ODOM FOR {} SECONDS".format(
- (rospy.Time.now() - self.last_time).to_sec(),
- ),
+ f"LOST ODOM FOR {(rospy.Time.now() - self.last_time).to_sec()} SECONDS",
)
self.ab.raise_alarm(
problem_description="LOST ODOM FOR {} SECONDS".format(
diff --git a/SubjuGator/command/subjugator_keyboard_control/teleop_twist_keyboard.py b/SubjuGator/command/subjugator_keyboard_control/teleop_twist_keyboard.py
index ea5c7bedb..870df6ac7 100755
--- a/SubjuGator/command/subjugator_keyboard_control/teleop_twist_keyboard.py
+++ b/SubjuGator/command/subjugator_keyboard_control/teleop_twist_keyboard.py
@@ -141,9 +141,7 @@ def wait_for_subscribers(self):
while not rospy.is_shutdown() and self.publisher.get_num_connections() == 0:
if i == 4:
print(
- "Waiting for subscriber to connect to {}".format(
- self.publisher.name,
- ),
+ f"Waiting for subscriber to connect to {self.publisher.name}",
)
rospy.sleep(0.5)
i += 1
diff --git a/SubjuGator/command/subjugator_launch/config/adaptive_controller.yaml b/SubjuGator/command/subjugator_launch/config/adaptive_controller.yaml
index c6406c44d..aefd3cb36 100644
--- a/SubjuGator/command/subjugator_launch/config/adaptive_controller.yaml
+++ b/SubjuGator/command/subjugator_launch/config/adaptive_controller.yaml
@@ -1,6 +1,6 @@
---
-kp: 1000, 1000, 1000, 5000, 5000, 5000
-kd: 150, 150, 150, 50, 100, 25
-kg: 5,5,5,5,5,5
-ki: 5,5,5,5,10,5
-use_learned: false
+kp: 120, 150, 200, 100, 50, 50
+kd: 25, 25, 25, 25, 25, 25
+kg: 2.5,2.5,2.5,2.5,2.5,2.5
+ki: 2.5,2.5,2.5,2.5,2.5,2.5
+use_learned: true
diff --git a/SubjuGator/command/subjugator_launch/config/adaptive_controller_gazebo.yaml b/SubjuGator/command/subjugator_launch/config/adaptive_controller_gazebo.yaml
new file mode 100644
index 000000000..c6406c44d
--- /dev/null
+++ b/SubjuGator/command/subjugator_launch/config/adaptive_controller_gazebo.yaml
@@ -0,0 +1,6 @@
+---
+kp: 1000, 1000, 1000, 5000, 5000, 5000
+kd: 150, 150, 150, 50, 100, 25
+kg: 5,5,5,5,5,5
+ki: 5,5,5,5,10,5
+use_learned: false
diff --git a/SubjuGator/command/subjugator_launch/config/passive_sonar.yaml b/SubjuGator/command/subjugator_launch/config/passive_sonar.yaml
index 9901f9703..e55aec3da 100644
--- a/SubjuGator/command/subjugator_launch/config/passive_sonar.yaml
+++ b/SubjuGator/command/subjugator_launch/config/passive_sonar.yaml
@@ -3,7 +3,7 @@
dist_h: 2.286e-02
# speed of sound in water
v_sound: 1482
-# target Frquency in Hz
+# target Frequency in Hz
triggering/target_frequency: 30000
# tolerance around target frequerncy in Hz
triggering/frequency_tolerance: 100
diff --git a/SubjuGator/command/subjugator_launch/launch/bag_debugging_controller.launch b/SubjuGator/command/subjugator_launch/launch/bag_debugging_controller.launch
new file mode 100644
index 000000000..4c6024669
--- /dev/null
+++ b/SubjuGator/command/subjugator_launch/launch/bag_debugging_controller.launch
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/SubjuGator/command/subjugator_launch/launch/can.launch b/SubjuGator/command/subjugator_launch/launch/can.launch
index 525671ace..b46fbd8ba 100644
--- a/SubjuGator/command/subjugator_launch/launch/can.launch
+++ b/SubjuGator/command/subjugator_launch/launch/can.launch
@@ -1,15 +1,13 @@
-
+
# Path of serial device
- port: /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A800GHCF-if00-port0
+ port: /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A50285BI-if00-port0
# Baudrate of device, should leave as is
baudrate: 115200
- # The CAN device id of the usb-can board
- can_id: 0
# List of python device handle classes
device_handles:
"18": sub8_thrust_and_kill_board.ThrusterAndKillBoard
diff --git a/SubjuGator/command/subjugator_launch/launch/sub8.launch b/SubjuGator/command/subjugator_launch/launch/sub8.launch
index 178efc6bb..247fe1e62 100644
--- a/SubjuGator/command/subjugator_launch/launch/sub8.launch
+++ b/SubjuGator/command/subjugator_launch/launch/sub8.launch
@@ -39,7 +39,9 @@
-
+
+
+
diff --git a/SubjuGator/command/subjugator_launch/launch/subsystems/adaptive_controller.launch b/SubjuGator/command/subjugator_launch/launch/subsystems/adaptive_controller.launch
index 17bd1d3ac..a758c4278 100644
--- a/SubjuGator/command/subjugator_launch/launch/subsystems/adaptive_controller.launch
+++ b/SubjuGator/command/subjugator_launch/launch/subsystems/adaptive_controller.launch
@@ -1,8 +1,10 @@
-
+
+
-
-
+
+
+
diff --git a/SubjuGator/command/subjugator_launch/launch/subsystems/nav_box.launch b/SubjuGator/command/subjugator_launch/launch/subsystems/nav_box.launch
index eb5e1bc31..fe18b292d 100644
--- a/SubjuGator/command/subjugator_launch/launch/subsystems/nav_box.launch
+++ b/SubjuGator/command/subjugator_launch/launch/subsystems/nav_box.launch
@@ -7,7 +7,7 @@
-
+
@@ -17,7 +17,7 @@
-
+
@@ -26,7 +26,7 @@
-
+
@@ -42,10 +42,10 @@
scale:
- - [0.993770963897068, 0.00105871125374563, 7.659410525291767e-05]
- - [0.00105871125374563, 0.9996814868251349, -0.0011040738267441828]
- - [7.659410525291767e-05, -0.001104073826744163, 1.0065910531028952]
- shift: [1.2551999807772446e-06, -1.1666595150804588e-06, 6.895773090438596e-08]
+ - [0.9991765357958566, 0.006242798579443988, -0.008472478269327878]
+ - [0.006242798579443957, 1.0016179705091928, 0.0059841151097914345]
+ - [-0.008472478269327836, 0.0059841151097913, 0.999354597532967]
+ shift: [7.889247409445414e-06, 4.879179471165382e-06, 7.46017199298374e-06]
diff --git a/SubjuGator/command/subjugator_launch/package.xml b/SubjuGator/command/subjugator_launch/package.xml
index 6a6beeeb6..e3f6ef4ba 100644
--- a/SubjuGator/command/subjugator_launch/package.xml
+++ b/SubjuGator/command/subjugator_launch/package.xml
@@ -5,8 +5,10 @@
The subjugator_launch package
Jacob Panikulam
MIT
+ rosbag
roslaunch
roslaunch
+ rosbag
robot_state_publisher
nodelet
c3_trajectory_generator
diff --git a/SubjuGator/command/subjugator_launch/scripts/depth_conn b/SubjuGator/command/subjugator_launch/scripts/depth_conn
index 13bf8a480..c63922eb9 100755
--- a/SubjuGator/command/subjugator_launch/scripts/depth_conn
+++ b/SubjuGator/command/subjugator_launch/scripts/depth_conn
@@ -1,2 +1,2 @@
#!/bin/sh
-exec socat -d -d pty,link=/tmp/depth,raw,echo=0 tcp:mil-sub-gumstix.ad.mil.ufl.edu:33056
+exec socat -d -d pty,link=/tmp/depth,raw,echo=0 tcp:192.168.37.61:33056
diff --git a/SubjuGator/command/subjugator_launch/scripts/dvl_conn b/SubjuGator/command/subjugator_launch/scripts/dvl_conn
index f0be15464..745a45097 100755
--- a/SubjuGator/command/subjugator_launch/scripts/dvl_conn
+++ b/SubjuGator/command/subjugator_launch/scripts/dvl_conn
@@ -1,2 +1,2 @@
#!/bin/sh
-exec socat -d -d pty,link=/tmp/dvl,raw,echo=0 tcp:mil-sub-gumstix.ad.mil.ufl.edu:349
+exec socat -d -d pty,link=/tmp/dvl,raw,echo=0 tcp:192.168.37.61:349
diff --git a/SubjuGator/command/subjugator_launch/scripts/imu_conn b/SubjuGator/command/subjugator_launch/scripts/imu_conn
index 59275c393..bc93e1eb1 100755
--- a/SubjuGator/command/subjugator_launch/scripts/imu_conn
+++ b/SubjuGator/command/subjugator_launch/scripts/imu_conn
@@ -1,2 +1,2 @@
#!/bin/sh
-exec socat -d -d pipe:/tmp/imu,wronly=1 tcp:mil-sub-gumstix.ad.mil.ufl.edu:1382
+exec socat -d -d pipe:/tmp/imu,wronly=1 tcp:192.168.37.61:1382
diff --git a/SubjuGator/command/subjugator_missions/subjugator_missions/arm_torpedos.py b/SubjuGator/command/subjugator_missions/subjugator_missions/arm_torpedos.py
index aad130049..7a88e8908 100644
--- a/SubjuGator/command/subjugator_missions/subjugator_missions/arm_torpedos.py
+++ b/SubjuGator/command/subjugator_missions/subjugator_missions/arm_torpedos.py
@@ -170,9 +170,7 @@ async def fire(self, target: str):
)
self.print_good(
- "{} locked. Firing torpedoes. Hit confirmed, good job Commander.".format(
- target,
- ),
+ f"{target} locked. Firing torpedoes. Hit confirmed, good job Commander.",
)
sub_pos = await self.tx_pose()
print("Current Sub Position: ", sub_pos)
diff --git a/SubjuGator/command/subjugator_missions/subjugator_missions/pose_editor.py b/SubjuGator/command/subjugator_missions/subjugator_missions/pose_editor.py
index 6eafca064..ee2562491 100644
--- a/SubjuGator/command/subjugator_missions/subjugator_missions/pose_editor.py
+++ b/SubjuGator/command/subjugator_missions/subjugator_missions/pose_editor.py
@@ -617,8 +617,8 @@ def as_PoseTwist(
def as_PoseTwistStamped(
self,
- linear: Sequence[int] = [0, 0, 0],
- angular: Sequence[int] = [0, 0, 0],
+ linear: Sequence[float] = [0, 0, 0],
+ angular: Sequence[float] = [0, 0, 0],
) -> PoseTwistStamped:
"""
Returns a :class:`~mil_msgs.msg.PoseTwist` message class with the pose
@@ -639,8 +639,8 @@ def as_PoseTwistStamped(
def as_MoveToGoal(
self,
- linear: Sequence[int] = [0, 0, 0],
- angular: Sequence[int] = [0, 0, 0],
+ linear: Sequence[float] = [0, 0, 0],
+ angular: Sequence[float] = [0, 0, 0],
**kwargs,
) -> MoveToGoal:
return MoveToGoal(
diff --git a/SubjuGator/command/subjugator_missions/subjugator_missions/start_gate.py b/SubjuGator/command/subjugator_missions/subjugator_missions/start_gate.py
index f395bd1e0..0886298e1 100644
--- a/SubjuGator/command/subjugator_missions/subjugator_missions/start_gate.py
+++ b/SubjuGator/command/subjugator_missions/subjugator_missions/start_gate.py
@@ -160,9 +160,7 @@ def find_gate(
p2 = rosmsg_to_numpy(o2.pose.position)
if distance.euclidean(p, p2) > max_distance_away:
fprint(
- "Poles too far away. Distance {}".format(
- distance.euclidean(p, p2),
- ),
+ f"Poles too far away. Distance {distance.euclidean(p, p2)}",
)
continue
if distance.euclidean(p, p2) < min_distance_away:
@@ -180,10 +178,7 @@ def find_gate(
continue
if abs(line[0]) < 1 and abs(line[1]) < 1:
fprint(
- "Objects on top of one another. x {}, y {}".format(
- line[0],
- line[1],
- ),
+ f"Objects on top of one another. x {line[0]}, y {line[1]}",
)
continue
return (p, p2)
diff --git a/SubjuGator/command/subjugator_missions/subjugator_missions/sub_singleton.py b/SubjuGator/command/subjugator_missions/subjugator_missions/sub_singleton.py
index 693fc3bd7..8e498fc4d 100644
--- a/SubjuGator/command/subjugator_missions/subjugator_missions/sub_singleton.py
+++ b/SubjuGator/command/subjugator_missions/subjugator_missions/sub_singleton.py
@@ -599,7 +599,7 @@ async def start_search_in_cone(
distance_tol: float = 10,
speed: float = 0.5,
clear: bool = False,
- c_func: Callable = None,
+ c_func: Callable | None = None,
):
if clear:
print("SONAR_OBJECTS: clearing pointcloud")
diff --git a/SubjuGator/drivers/magnetic_compensation/sub8_magnetic_hardsoft_compensation/scripts/generate_config b/SubjuGator/drivers/magnetic_compensation/sub8_magnetic_hardsoft_compensation/scripts/generate_config
index 5d12dad06..342292350 100755
--- a/SubjuGator/drivers/magnetic_compensation/sub8_magnetic_hardsoft_compensation/scripts/generate_config
+++ b/SubjuGator/drivers/magnetic_compensation/sub8_magnetic_hardsoft_compensation/scripts/generate_config
@@ -9,6 +9,7 @@ import rosbag
import roslib
import scipy.linalg
import yaml
+from mpl_toolkits.mplot3d import Axes3D
from tf import transformations
roslib.load_manifest("magnetic_hardsoft_compensation")
@@ -20,7 +21,7 @@ def normalized_matrix(m):
def calculate_error(points):
- radii = map(numpy.linalg.norm, points)
+ radii = list(map(numpy.linalg.norm, points))
error = numpy.std(radii) / numpy.mean(radii)
return error
@@ -47,7 +48,7 @@ def fit_ellipsoid(points):
B = numpy.ones((points.shape[0], 1))
- X = numpy.linalg.lstsq(A, B)[0].flatten()
+ X = numpy.linalg.lstsq(A, B, rcond=-1)[0].flatten()
if X[0] < 0:
X = -X # make sure ka turns out positive definite
@@ -110,9 +111,7 @@ def test():
assert numpy.allclose(
shift2,
shift,
- ), "Magnetic Hardsoft Compenstion self-test failed, shifts: {}".format(
- (shift2, shift),
- )
+ ), f"Magnetic Hardsoft Compenstion self-test failed, shifts: {(shift2, shift)}"
assert (
error < 1e-5
), f"Magnetic Hardsoft Compenstion self-test failed, error: {error}"
@@ -133,9 +132,11 @@ if __name__ == "__main__":
with rosbag.Bag(sys.argv[1]) as bag:
points = numpy.array(
[
- mil_ros_tools.rosmsg_to_numpy(msg.magnetic_field)
- if hasattr(msg, "magnetic_field")
- else mil_ros_tools.rosmsg_to_numpy(msg.vector)
+ (
+ mil_ros_tools.rosmsg_to_numpy(msg.magnetic_field)
+ if hasattr(msg, "magnetic_field")
+ else mil_ros_tools.rosmsg_to_numpy(msg.vector)
+ )
for topic, msg, t in bag.read_messages(topics=["/imu/mag_raw"])
],
)
@@ -152,7 +153,7 @@ if __name__ == "__main__":
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10, 10))
- ax = fig.add_subplot("111", projection="3d")
+ ax = Axes3D(fig)
ax.scatter([0], [0], [0], s=100, c="r")
ax.scatter(*zip(*points[::10, :]))
axisEqual3D(ax)
@@ -170,7 +171,7 @@ if __name__ == "__main__":
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10, 10))
- ax = fig.add_subplot("111", projection="3d")
+ ax = Axes3D(fig)
ax.scatter([0], [0], [0], s=100, c="r")
ax.scatter(*zip(*points[::10, :]))
ax.scatter(*zip(*compensated[::10, :]), c="g")
@@ -185,8 +186,8 @@ if __name__ == "__main__":
print(
yaml.dump(
{
- "scale": (map(float, x) for x in scale),
- "shift": map(float, shift),
+ "scale": scale.tolist(),
+ "shift": shift.tolist(),
},
),
)
diff --git a/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/handle.py b/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/handle.py
index 9db8c34be..cee7efb30 100644
--- a/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/handle.py
+++ b/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/handle.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
import rospy
-from mil_usb_to_can import CANDeviceHandle
+from mil_usb_to_can.sub8 import CANDeviceHandle
from sub8_actuator_board.srv import SetValve, SetValveRequest
diff --git a/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/packets.py b/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/packets.py
index 73536f7e5..f287e09fa 100644
--- a/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/packets.py
+++ b/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/packets.py
@@ -1,6 +1,6 @@
import struct
-from mil_usb_to_can import ApplicationPacket
+from mil_usb_to_can.sub8 import ApplicationPacket
# CAN ID for the channel from MOBO to actuator board
SEND_ID = 0x51
diff --git a/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/simulation.py b/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/simulation.py
index af0867fce..f776274d2 100644
--- a/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/simulation.py
+++ b/SubjuGator/drivers/sub8_actuator_board/sub8_actuator_board/simulation.py
@@ -1,5 +1,5 @@
#!/usr/bin/python3
-from mil_usb_to_can import SimulatedCANDevice
+from mil_usb_to_can.sub8 import SimulatedCANDevice
from .packets import SEND_ID, CommandMessage, FeedbackMessage
diff --git a/SubjuGator/drivers/sub8_adis16400_imu/include/adis16400_imu/driver.h b/SubjuGator/drivers/sub8_adis16400_imu/include/adis16400_imu/driver.h
index b62785f36..dc5146e7f 100644
--- a/SubjuGator/drivers/sub8_adis16400_imu/include/adis16400_imu/driver.h
+++ b/SubjuGator/drivers/sub8_adis16400_imu/include/adis16400_imu/driver.h
@@ -41,7 +41,7 @@ class Device
}
catch (const std::exception &exc)
{
- ROS_ERROR("error on open(%s): %s; reopening after delay", port.c_str(), exc.what());
+ ROS_ERROR_THROTTLE(5, "error on open(%s): %s; reopening after delay", port.c_str(), exc.what());
boost::this_thread::sleep(boost::posix_time::seconds(1));
return false;
}
@@ -62,7 +62,7 @@ class Device
}
catch (const std::exception &exc)
{
- ROS_ERROR("error on read: %s; reopening", exc.what());
+ ROS_ERROR_THROTTLE(5, "error on read: %s; reopening", exc.what());
open();
return false;
}
@@ -70,7 +70,7 @@ class Device
result.header.frame_id = frame_id;
result.header.stamp = ros::Time::now();
- result.orientation_covariance[0] = -1; // indicate no orientation data
+ result.orientation_covariance[0] = -1; // indicate no orientation data
static const double GYRO_CONVERSION = 0.05 * (2 * M_PI / 360); // convert to deg/s and then to rad/s
result.angular_velocity.x = get16(data + 4 + 2 * 0) * GYRO_CONVERSION;
@@ -78,7 +78,7 @@ class Device
result.angular_velocity.z = get16(data + 4 + 2 * 2) * GYRO_CONVERSION;
result.angular_velocity_covariance[0] = result.angular_velocity_covariance[4] =
result.angular_velocity_covariance[8] =
- pow(0.9 * (2 * M_PI / 360), 2); // 0.9 deg/sec rms converted to rad/sec and then squared
+ pow(0.9 * (2 * M_PI / 360), 2); // 0.9 deg/sec rms converted to rad/sec and then squared
static const double ACC_CONVERSION = 3.33e-3 * 9.80665; // convert to g's and then to m/s^2
result.linear_acceleration.x = -get16(data + 10 + 2 * 0) * ACC_CONVERSION;
@@ -99,9 +99,9 @@ class Device
mag_result.magnetic_field_covariance[8] =
pow(1.25e-3 * 0.0001, 2); // 1.25 mgauss converted to tesla and then squared
- getu16(data + 0); // flags unused
- getu16(data + 2) * 2.418e-3; // supply voltage unused
- get16(data + 22) * 0.14 + 25; // temperature unused
+ getu16(data + 0); // flags unused
+ getu16(data + 2) * 2.418e-3; // supply voltage unused
+ get16(data + 22) * 0.14 + 25; // temperature unused
return true;
}
diff --git a/SubjuGator/drivers/sub8_depth_driver/include/depth_driver/driver.h b/SubjuGator/drivers/sub8_depth_driver/include/depth_driver/driver.h
index e9c287107..2f4468091 100644
--- a/SubjuGator/drivers/sub8_depth_driver/include/depth_driver/driver.h
+++ b/SubjuGator/drivers/sub8_depth_driver/include/depth_driver/driver.h
@@ -69,7 +69,7 @@ class Device
}
catch (const std::exception &exc)
{
- ROS_ERROR("error on write: %s; dropping", exc.what());
+ ROS_ERROR_THROTTLE(5, "error on write: %s; dropping", exc.what());
}
}
@@ -82,7 +82,7 @@ class Device
}
catch (const std::exception &exc)
{
- ROS_ERROR("error on read: %s; reopening", exc.what());
+ ROS_ERROR_THROTTLE(5, "error on read: %s; reopening", exc.what());
open();
return false;
}
@@ -98,7 +98,7 @@ class Device
}
catch (const std::exception &exc)
{
- ROS_ERROR("error on open(%s): %s; reopening after delay", port.c_str(), exc.what());
+ ROS_ERROR_THROTTLE(5, "error on open(%s): %s; reopening after delay", port.c_str(), exc.what());
boost::this_thread::sleep(boost::posix_time::seconds(1));
}
}
@@ -166,7 +166,7 @@ class Device
void send_heartbeat()
{
- send_packet(ByteVec()); // heartbeat
+ send_packet(ByteVec()); // heartbeat
uint8_t msg[] = { 4, 1, 20 };
send_packet(ByteVec(msg, msg + sizeof(msg) / sizeof(msg[0]))); // StartPublishing 20hz
}
diff --git a/SubjuGator/drivers/sub8_rdi_dvl/include/rdi_explorer_dvl/driver.hpp b/SubjuGator/drivers/sub8_rdi_dvl/include/rdi_explorer_dvl/driver.hpp
index 914706c44..80e9cf973 100644
--- a/SubjuGator/drivers/sub8_rdi_dvl/include/rdi_explorer_dvl/driver.hpp
+++ b/SubjuGator/drivers/sub8_rdi_dvl/include/rdi_explorer_dvl/driver.hpp
@@ -48,7 +48,7 @@ class Device
}
catch (const std::exception &exc)
{
- ROS_ERROR_THROTTLE(0.5, "DVL: error on read: %s; reopening serial port", exc.what());
+ ROS_ERROR_THROTTLE(5, "DVL: error on read: %s; reopening serial port", exc.what());
open();
return false;
}
@@ -86,7 +86,7 @@ class Device
}
catch (const std::exception &exc)
{
- ROS_ERROR("DVL: error on open(port=%s): %s; reopening after delay", port.c_str(), exc.what());
+ ROS_ERROR_THROTTLE(5, "DVL: error on open(port=%s): %s; reopening after delay", port.c_str(), exc.what());
boost::this_thread::sleep(boost::posix_time::seconds(1));
}
}
@@ -268,7 +268,7 @@ class Device
}
catch (const std::exception &exc)
{
- ROS_ERROR_THROTTLE(0.5, "DVL: error on write: %s; dropping heartbeat", exc.what());
+ ROS_ERROR_THROTTLE(5, "DVL: error on write: %s; dropping heartbeat", exc.what());
}
}
diff --git a/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/handle.py b/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/handle.py
index 336e0336d..19df02c33 100644
--- a/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/handle.py
+++ b/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/handle.py
@@ -1,6 +1,6 @@
#!/usr/bin/python3
import rospy
-from mil_usb_to_can import CANDeviceHandle
+from mil_usb_to_can.sub8 import CANDeviceHandle
from ros_alarms import AlarmBroadcaster, AlarmListener
from ros_alarms_msgs.msg import Alarm
from rospy.timer import TimerEvent
@@ -26,7 +26,7 @@ class ThrusterAndKillBoard(CANDeviceHandle):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Initialize thruster mapping from params
- self.thrusters = make_thruster_dictionary(
+ self.thrusters, self.name_to_id = make_thruster_dictionary(
rospy.get_param("/thruster_layout/thrusters"),
)
# Tracks last hw-kill alarm update
@@ -93,7 +93,7 @@ def on_hw_kill(self, alarm: Alarm) -> None:
Update the classes' hw-kill alarm to the latest update.
Args:
- alarm (:class:`~ros_alarms.msg._Alarm.Alarm`): The alarm message to update with.
+ alarm (:class:`~ros_alarms_msgs.msg._Alarm.Alarm`): The alarm message to update with.
"""
self._last_hw_kill = alarm
@@ -109,16 +109,14 @@ def on_command(self, msg: Thrust) -> None:
# If we don't have a mapping for this thruster, ignore it
if cmd.name not in self.thrusters:
rospy.logwarn(
- "Command received for {}, but this is not a thruster.".format(
- cmd.name,
- ),
+ f"Command received for {cmd.name}, but this is not a thruster.",
)
continue
# Map commanded thrust (in newetons) to effort value (-1 to 1)
effort = self.thrusters[cmd.name].effort_from_thrust(cmd.thrust)
# Send packet to command specified thruster the specified force
packet = ThrustPacket.create_thrust_packet(
- ThrustPacket.ID_MAPPING[cmd.name],
+ self.name_to_id[cmd.name],
effort,
)
self.send_data(bytes(packet), can_id=THRUST_SEND_ID)
diff --git a/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/packets.py b/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/packets.py
index 519d4e829..dcd1aaa0b 100644
--- a/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/packets.py
+++ b/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/packets.py
@@ -1,7 +1,7 @@
import struct
from collections import namedtuple
-from mil_usb_to_can import ApplicationPacket
+from mil_usb_to_can.sub8 import ApplicationPacket
# CAN channel to send thrust messages to
THRUST_SEND_ID = 0x21
@@ -250,41 +250,9 @@ class ThrustPacket(ApplicationPacket):
Attributes:
IDENTIFIER (int): The packet identifier, equal to the ordinal value of "T,"
or 84.
- ID_MAPPING (Dict[str, int]): A dictionary mapping 3-letter thruster codes
- to their respective IDs:
-
- +--------+------+
- | Name | ID |
- +========+======+
- | FLH | 0 |
- +--------+------+
- | FRH | 1 |
- +--------+------+
- | FLV | 2 |
- +--------+------+
- | FRV | 3 |
- +--------+------+
- | BLH | 4 |
- +--------+------+
- | BRH | 5 |
- +--------+------+
- | BLV | 6 |
- +--------+------+
- | BRV | 7 |
- +--------+------+
"""
IDENTIFIER = ord("T")
- ID_MAPPING = {
- "FLH": 0,
- "FRH": 1,
- "FLV": 2,
- "FRV": 3,
- "BLH": 4,
- "BRH": 5,
- "BLV": 6,
- "BRV": 7,
- }
@classmethod
def create_thrust_packet(cls, thruster_id: int, command: float):
@@ -319,7 +287,4 @@ def command(self) -> float:
return struct.unpack("f", self.payload[1:])[0]
def __str__(self):
- return "ThrustPacket(thruster_id={}, command={})".format(
- self.thruster_id,
- self.command,
- )
+ return f"ThrustPacket(thruster_id={self.thruster_id}, command={self.command})"
diff --git a/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/simulation.py b/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/simulation.py
index a24a4ab95..83c595815 100644
--- a/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/simulation.py
+++ b/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/simulation.py
@@ -1,6 +1,6 @@
#!/usr/bin/python3
import rospy
-from mil_usb_to_can import SimulatedCANDevice
+from mil_usb_to_can.sub8 import SimulatedCANDevice
from std_srvs.srv import SetBool, SetBoolRequest, SetBoolResponse
from .packets import (
@@ -156,4 +156,4 @@ def on_data(self, data: bytes, can_id: int) -> None:
packet = HeartbeatMessage.from_bytes(data)
self._last_heartbeat = rospy.Time.now()
else:
- assert False, "No recognized identifier"
+ raise Exception("No recognized identifier")
diff --git a/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/thruster.py b/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/thruster.py
index 5a90baac0..7fe9aef12 100644
--- a/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/thruster.py
+++ b/SubjuGator/drivers/sub8_thrust_and_kill_board/sub8_thrust_and_kill_board/thruster.py
@@ -1,16 +1,21 @@
-from typing import Any, Dict
+from __future__ import annotations
+
+from typing import Any
from numpy import clip, polyval
-def make_thruster_dictionary(dictionary):
+def make_thruster_dictionary(dictionary) -> tuple[dict[str, Thruster], dict[str, int]]:
"""
- Make a dictionary mapping thruster names to :class:`Thruster` objects.
+ Make a dictionary mapping thruster names to :class:`Thruster` objects
+ and a dictionary mapping thruster names to node IDs.
"""
ret = {}
+ name_id_map = {}
for thruster, content in dictionary.items():
ret[thruster] = Thruster.from_dict(content)
- return ret
+ name_id_map[thruster] = content["node_id"]
+ return ret, name_id_map
class Thruster:
@@ -27,7 +32,7 @@ def __init__(self, forward_calibration, backward_calibration):
self.backward_calibration = backward_calibration
@classmethod
- def from_dict(cls, data: Dict[str, Dict[str, Any]]):
+ def from_dict(cls, data: dict[str, dict[str, Any]]):
"""
Constructs the class from a dictionary. The dictionary should be formatted
as so:
diff --git a/SubjuGator/drivers/sub9_thrust_and_kill_board/CMakeLists.txt b/SubjuGator/drivers/sub9_thrust_and_kill_board/CMakeLists.txt
new file mode 100644
index 000000000..19b63afff
--- /dev/null
+++ b/SubjuGator/drivers/sub9_thrust_and_kill_board/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.3)
+project(sub9_thrust_and_kill_board)
+find_package(catkin REQUIRED COMPONENTS
+ mil_usb_to_can
+)
+add_rostest(test/simulated_board.test)
+catkin_python_setup()
+catkin_package()
diff --git a/SubjuGator/drivers/sub9_thrust_and_kill_board/package.xml b/SubjuGator/drivers/sub9_thrust_and_kill_board/package.xml
new file mode 100644
index 000000000..530dcfdf9
--- /dev/null
+++ b/SubjuGator/drivers/sub9_thrust_and_kill_board/package.xml
@@ -0,0 +1,13 @@
+
+
+ sub9_thrust_and_kill_board
+ 0.0.0
+ The sub9_thrust_and_kill_board package
+ Cameron Brown
+ MIT
+ Cameron Brown
+ catkin
+ mil_usb_to_can
+ mil_usb_to_can
+ mil_usb_to_can
+
diff --git a/SubjuGator/drivers/sub9_thrust_and_kill_board/setup.py b/SubjuGator/drivers/sub9_thrust_and_kill_board/setup.py
new file mode 100644
index 000000000..32234daad
--- /dev/null
+++ b/SubjuGator/drivers/sub9_thrust_and_kill_board/setup.py
@@ -0,0 +1,11 @@
+# ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD
+
+from catkin_pkg.python_setup import generate_distutils_setup
+from setuptools import setup
+
+# Fetch values from package.xml
+setup_args = generate_distutils_setup(
+ packages=["sub9_thrust_and_kill_board"],
+)
+
+setup(**setup_args)
diff --git a/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/__init__.py b/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/__init__.py
new file mode 100644
index 000000000..7a9f7f666
--- /dev/null
+++ b/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/__init__.py
@@ -0,0 +1,11 @@
+from .handle import ThrusterAndKillBoard
+from .packets import (
+ HeartbeatReceivePacket,
+ HeartbeatSetPacket,
+ KillReceivePacket,
+ KillSetPacket,
+ KillStatus,
+ ThrustSetPacket,
+)
+from .simulation import ThrusterAndKillBoardSimulation
+from .thruster import Thruster
diff --git a/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/handle.py b/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/handle.py
new file mode 100644
index 000000000..8d103cc78
--- /dev/null
+++ b/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/handle.py
@@ -0,0 +1,196 @@
+#!/usr/bin/python3
+from __future__ import annotations
+
+import rospy
+from mil_misc_tools import rospy_to_datetime
+from mil_usb_to_can.sub9 import AckPacket, CANDeviceHandle, NackPacket
+from ros_alarms import AlarmBroadcaster, AlarmListener
+from ros_alarms_msgs.msg import Alarm
+from rospy.timer import TimerEvent
+from std_srvs.srv import SetBool, SetBoolRequest, SetBoolResponse
+from subjugator_msgs.msg import Thrust
+
+from .packets import (
+ HeartbeatReceivePacket,
+ HeartbeatSetPacket,
+ KillReceivePacket,
+ KillSetPacket,
+ KillStatus,
+ ThrustSetPacket,
+)
+from .thruster import make_thruster_dictionary
+
+
+class ThrusterAndKillBoard(CANDeviceHandle):
+ """
+ Device handle for the thrust and kill board.
+ """
+
+ ID_MAPPING = {
+ "FLH": 0,
+ "FRH": 1,
+ "FLV": 2,
+ "FRV": 3,
+ "BLH": 4,
+ "BRH": 5,
+ "BLV": 6,
+ "BRV": 7,
+ }
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ # Initialize thruster mapping from params
+ self.thrusters = make_thruster_dictionary(
+ rospy.get_param("/thruster_layout/thrusters"),
+ )
+ # Tracks last hw-kill alarm update
+ self._last_hw_kill = None
+ # Used to raise/clear hw-kill when board updates
+ self._kill_broadcaster = AlarmBroadcaster("hw-kill")
+ # Listens to hw-kill updates to ensure another nodes doesn't manipulate it
+ self._hw_kill_listener = AlarmListener(
+ "hw-kill",
+ callback_funct=self.on_hw_kill,
+ )
+ # Provide service for alarm handler to set/clear the motherboard kill
+ self._unkill_service = rospy.Service("/set_mobo_kill", SetBool, self.set_kill)
+ # Sends heartbeat to board
+ self._heartbeat_timer = rospy.Timer(rospy.Duration(0.4), self.send_heartbeat)
+ # Create a subscribe for thruster commands
+ self._sub = rospy.Subscriber(
+ "/thrusters/thrust",
+ Thrust,
+ self.on_command,
+ queue_size=10,
+ )
+ self._last_heartbeat = rospy.Time.now()
+ self._last_packet = None
+ self._updated_kill = False
+
+ def set_kill(self, req: SetBoolRequest) -> SetBoolResponse:
+ """
+ Called on service calls to ``/set_mobo_kill``, sending the appropriate
+ packet to the board to unassert or assert to motherboard-origin kill.
+
+ Args:
+ req (SetBoolRequest): The service request.
+
+ Returns:
+ SetBoolResponse: The service response.
+ """
+ self.send_data(KillSetPacket(req.data, KillStatus.SOFTWARE_REQUESTED))
+ start = rospy.Time.now()
+ while rospy.Time.now() - start < rospy.Duration(1):
+ if self._last_packet is not None:
+ break
+
+ if isinstance(self._last_packet, NackPacket):
+ raise RuntimeError("Request not acknowledged.")
+
+ start = rospy.Time.now()
+ while rospy.Time.now() - start < rospy.Duration(1):
+ if self._updated_kill:
+ break
+
+ if self._updated_kill:
+ self._updated_kill = False
+ return SetBoolResponse(success=True)
+ else:
+ return SetBoolResponse(
+ success=False,
+ message="No response from board after 1 second.",
+ )
+
+ def send_heartbeat(self, _: TimerEvent) -> None:
+ """
+ Send a special heartbeat packet. Called by a recurring timer set upon
+ initialization.
+ """
+ self.send_data(HeartbeatSetPacket())
+
+ def on_hw_kill(self, alarm: Alarm) -> None:
+ """
+ Update the classes' hw-kill alarm to the latest update.
+
+ Args:
+ alarm (:class:`~ros_alarms_msgs.msg._Alarm.Alarm`): The alarm message to update with.
+ """
+ self._last_hw_kill = alarm
+
+ def on_command(self, msg: Thrust) -> None:
+ """
+ When a thrust command message is received from the Subscriber, send the appropriate packet
+ to the board.
+
+ Args:
+ msg (Thrust): The thrust message.
+ """
+ for cmd in msg.thruster_commands:
+ # If we don't have a mapping for this thruster, ignore it
+ if cmd.name not in self.thrusters:
+ rospy.logwarn(
+ f"Command received for {cmd.name}, but this is not a thruster.",
+ )
+ continue
+ # Map commanded thrust (in newetons) to effort value (-1 to 1)
+ effort = self.thrusters[cmd.name].effort_from_thrust(cmd.thrust)
+ # Send packet to command specified thruster the specified force
+ packet = ThrustSetPacket(self.ID_MAPPING[cmd.name], effort)
+ self.send_data(packet)
+
+ def update_software_kill(self, raised: bool, message: str):
+ # If the current status differs from the alarm, update the alarm
+ severity = 2 if raised else 0
+ self._updated_kill = True
+ self._hw_kill_listener.wait_for_server()
+ if (
+ self._last_hw_kill is None
+ or self._last_hw_kill.raised != raised
+ or self._last_hw_kill.problem_description != message
+ or self._last_hw_kill.severity != severity
+ ):
+ if raised:
+ self._kill_broadcaster.raise_alarm(
+ severity=severity,
+ problem_description=message,
+ )
+ else:
+ self._kill_broadcaster.clear_alarm(severity=severity)
+
+ def on_data(
+ self,
+ data: AckPacket | NackPacket | HeartbeatReceivePacket | KillReceivePacket,
+ ) -> None:
+ """
+ Parse the two bytes and raise kills according to a set of specifications
+ listed below.
+ """
+ if isinstance(data, (AckPacket, NackPacket)):
+ self._last_packet = data
+ elif isinstance(data, HeartbeatReceivePacket):
+ self._last_heartbeat = rospy.Time.now()
+ elif isinstance(data, KillReceivePacket):
+ if data.set is False:
+ self.update_software_kill(False, "")
+ elif data.status is KillStatus.MOBO_HEARTBEAT_LOST:
+ self.update_software_kill(
+ True,
+ "Thrust/kill board lost heartbeat from motherboard.",
+ )
+ elif data.status is KillStatus.BATTERY_LOW:
+ self.update_software_kill(True, "Battery too low.")
+ elif data.status is KillStatus.KILL_SWITCH:
+ self.update_software_kill(True, "Kill switch was pulled!")
+ elif data.status is KillStatus.BOARD_HEARTBEAT_LOST:
+ dt = rospy_to_datetime(self._last_heartbeat)
+ self.update_software_kill(
+ True,
+ f"Motherboard is no longer hearing heartbeat from thrust/kill board. Last heard from board at {dt}.",
+ )
+ elif data.status is KillStatus.SOFTWARE_REQUESTED:
+ self.update_software_kill(
+ True,
+ "Software requested kill.",
+ )
+ else:
+ raise ValueError(f"Not expecting packet of type {data.__class__.__name__}!")
diff --git a/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/packets.py b/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/packets.py
new file mode 100644
index 000000000..93d892fd3
--- /dev/null
+++ b/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/packets.py
@@ -0,0 +1,98 @@
+from dataclasses import dataclass
+from enum import IntEnum
+
+from mil_usb_to_can.sub9 import Packet
+
+
+@dataclass
+class HeartbeatSetPacket(Packet, msg_id=0x02, subclass_id=0x00, payload_format=""):
+ """
+ Heartbeat packet sent by the motherboard to the thrust/kill board.
+ """
+
+
+@dataclass
+class HeartbeatReceivePacket(Packet, msg_id=0x02, subclass_id=0x01, payload_format=""):
+ """
+ Heartbeat packet sent by the thrust/kill board to the motherboard.
+ """
+
+
+@dataclass
+class ThrustSetPacket(Packet, msg_id=0x02, subclass_id=0x02, payload_format="=Bf"):
+ """
+ Packet to set the speed of a specific thruster.
+
+ Attributes:
+ thruster_id (int): The ID of the thruster to set the speed of. The ID of
+ the thruster corresponds to a specific thruster:
+
+ +--------+------+
+ | name | id |
+ +========+======+
+ | FLH | 0 |
+ +--------+------+
+ | FRH | 1 |
+ +--------+------+
+ | FLV | 2 |
+ +--------+------+
+ | FRV | 3 |
+ +--------+------+
+ | BLH | 4 |
+ +--------+------+
+ | BRH | 5 |
+ +--------+------+
+ | BLV | 6 |
+ +--------+------+
+ | BRV | 7 |
+ +--------+------+
+ speed (float): The speed to set the thruster to.
+ """
+
+ thruster_id: int
+ speed: float
+
+
+class KillStatus(IntEnum):
+ """
+ Enum to represent the purpose behind a kill.
+ """
+
+ #: A software user manually requested a kill on the sub.
+ SOFTWARE_REQUESTED = 0
+ #: The board reported that it stopped hearing the heartbeat from the motherboard.
+ MOBO_HEARTBEAT_LOST = 1
+ #: The motherboard reported that it stopped hearing the heartbeat from the board.
+ BOARD_HEARTBEAT_LOST = 2
+ #: The physical kill switch was pulled, requesting an immediate kill.
+ KILL_SWITCH = 3
+ #: The battery is too low to continue operation.
+ BATTERY_LOW = 4
+
+
+@dataclass
+class KillSetPacket(Packet, msg_id=0x02, subclass_id=0x03, payload_format="=BB"):
+ """
+ Packet sent by the motherboard to set/unset the kill.
+
+ Attributes:
+ set (bool): Whether the kill is set or unset.
+ status (KillStatus): The reason for the kill.
+ """
+
+ set: bool
+ status: KillStatus
+
+
+@dataclass
+class KillReceivePacket(Packet, msg_id=0x02, subclass_id=0x04, payload_format="=BB"):
+ """
+ Packet sent by the motherboard to set/unset the kill.
+
+ Attributes:
+ set (bool): Whether the kill is set or unset.
+ status (KillStatus): The reason for the kill.
+ """
+
+ set: bool
+ status: KillStatus
diff --git a/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/simulation.py b/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/simulation.py
new file mode 100644
index 000000000..52deb3181
--- /dev/null
+++ b/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/simulation.py
@@ -0,0 +1,92 @@
+#!/usr/bin/python3
+from __future__ import annotations
+
+import rospy
+from mil_usb_to_can.sub9 import AckPacket, NackPacket, SimulatedCANDeviceHandle
+from std_srvs.srv import SetBool, SetBoolRequest, SetBoolResponse
+
+from .packets import (
+ HeartbeatReceivePacket,
+ HeartbeatSetPacket,
+ KillReceivePacket,
+ KillSetPacket,
+ KillStatus,
+ ThrustSetPacket,
+)
+
+
+class ThrusterAndKillBoardSimulation(SimulatedCANDeviceHandle):
+ """
+ Serial simulator for the thruster and kill board,
+ providing services to simulate physical plug connections/disconnections.
+
+ Inherits from :class:`~mil_usb_to_can.SimulatedCANDevice`.
+
+ Attributes:
+ kill (bool): Whether the hard kill was set.
+ """
+
+ HEARTBEAT_TIMEOUT_SECONDS = rospy.Duration(1.0)
+
+ def __init__(self, *args, **kwargs):
+ self.kill = False
+ self._last_heartbeat = None
+ super().__init__(*args, **kwargs)
+ self._update_timer = rospy.Timer(rospy.Duration(1), self._check_for_timeout)
+ self._kill_srv = rospy.Service("/simulate_kill", SetBool, self.set_kill)
+
+ def _check_for_timeout(self, _: rospy.timer.TimerEvent):
+ if self.heartbeat_timedout and not self.kill:
+ self.send_data(bytes(KillSetPacket(True, KillStatus.BOARD_HEARTBEAT_LOST)))
+ self.kill = True
+
+ def set_kill(self, req: SetBoolRequest) -> SetBoolResponse:
+ """
+ Called by the `/simulate_kill` service to set the kill state of the
+ simluated device.
+
+ Args:
+ req (SetBoolRequest): The request to set the service with.
+
+ Returns:
+ SetBoolResponse: The response to the service that the operation was successful.
+ """
+ self.kill = req.data
+ return SetBoolResponse(success=True)
+
+ @property
+ def heartbeat_timedout(self) -> bool:
+ """
+ Whether the heartbeat timed out.
+
+ Returns:
+ bool: The status of the heartbeat timing out.
+ """
+ return (
+ self._last_heartbeat is None
+ or (rospy.Time.now() - self._last_heartbeat)
+ > self.HEARTBEAT_TIMEOUT_SECONDS
+ )
+
+ def on_data(
+ self,
+ packet: HeartbeatSetPacket | ThrustSetPacket | KillSetPacket,
+ ) -> None:
+ """
+ Serves as the data handler for the device. Handles :class:`KillMessage`,
+ :class:`ThrustPacket`, and :class:`HeartbeatMessage` types.
+ """
+ if isinstance(packet, HeartbeatSetPacket):
+ self._last_heartbeat = rospy.Time.now()
+ self.send_data(bytes(HeartbeatReceivePacket()))
+
+ elif isinstance(packet, ThrustSetPacket):
+ self.send_data(bytes(AckPacket()))
+
+ elif isinstance(packet, KillSetPacket):
+ self.kill = packet.set
+ self.send_data(bytes(AckPacket()))
+ self.send_data(bytes(KillReceivePacket(packet.set, packet.status)))
+
+ else:
+ self.send_data(bytes(NackPacket()))
diff --git a/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/thruster.py b/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/thruster.py
new file mode 100644
index 000000000..5a90baac0
--- /dev/null
+++ b/SubjuGator/drivers/sub9_thrust_and_kill_board/sub9_thrust_and_kill_board/thruster.py
@@ -0,0 +1,66 @@
+from typing import Any, Dict
+
+from numpy import clip, polyval
+
+
+def make_thruster_dictionary(dictionary):
+ """
+ Make a dictionary mapping thruster names to :class:`Thruster` objects.
+ """
+ ret = {}
+ for thruster, content in dictionary.items():
+ ret[thruster] = Thruster.from_dict(content)
+ return ret
+
+
+class Thruster:
+ """
+ Models the force (thrust) to PWM (effort) of a thruster.
+
+ Attributes:
+ forward_calibration (???): ???
+ backward_calibration (???): ???
+ """
+
+ def __init__(self, forward_calibration, backward_calibration):
+ self.forward_calibration = forward_calibration
+ self.backward_calibration = backward_calibration
+
+ @classmethod
+ def from_dict(cls, data: Dict[str, Dict[str, Any]]):
+ """
+ Constructs the class from a dictionary. The dictionary should be formatted
+ as so:
+
+ .. code-block:: python3
+
+ {
+ "calib": {
+ "forward": ...,
+ "backward": ...,
+ }
+ }
+
+ Args:
+ data (Dict[str, Dict[str, Any]]): The dictionary containing the initialization info.
+ """
+ forward_calibration = data["calib"]["forward"]
+ backward_calibration = data["calib"]["backward"]
+ return cls(forward_calibration, backward_calibration)
+
+ def effort_from_thrust_unclipped(self, thrust: Any):
+ if thrust < 0:
+ return polyval(self.backward_calibration, thrust)
+ else:
+ return polyval(self.forward_calibration, thrust)
+
+ def effort_from_thrust(self, thrust: Any):
+ """
+ Attempts to find the effort from a particular value of thrust.
+
+ Args:
+ thrust (???): The amount of thrust.
+ """
+ unclipped = self.effort_from_thrust_unclipped(thrust)
+ # Theoretically can limit to .66 under 16V assumptions or .5 under 12V assumptions... So do both (.5 + 66)/2
+ return clip(unclipped, -0.58, 0.58)
diff --git a/SubjuGator/drivers/sub9_thrust_and_kill_board/test/simulated_board.test b/SubjuGator/drivers/sub9_thrust_and_kill_board/test/simulated_board.test
new file mode 100644
index 000000000..44904f746
--- /dev/null
+++ b/SubjuGator/drivers/sub9_thrust_and_kill_board/test/simulated_board.test
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+ device_handles:
+ sub9_thrust_and_kill_board.ThrusterAndKillBoard: [sub9_thrust_and_kill_board.KillReceivePacket]
+ simulated_devices:
+ sub9_thrust_and_kill_board.ThrusterAndKillBoardSimulation: [sub9_thrust_and_kill_board.HeartbeatSetPacket, sub9_thrust_and_kill_board.ThrustSetPacket, sub9_thrust_and_kill_board.KillSetPacket]
+
+
+
+
+
+
+
+
diff --git a/SubjuGator/drivers/sub9_thrust_and_kill_board/test/simulated_board_test.py b/SubjuGator/drivers/sub9_thrust_and_kill_board/test/simulated_board_test.py
new file mode 100755
index 000000000..4af9813d7
--- /dev/null
+++ b/SubjuGator/drivers/sub9_thrust_and_kill_board/test/simulated_board_test.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+import unittest
+
+import rospy
+from ros_alarms import AlarmListener
+from std_srvs.srv import SetBool, SetBoolRequest
+
+
+class SimulatedBoardTest(unittest.TestCase):
+ """
+ Integration test for CAN2USB board driver. Talks
+ to a simulated CAN device which should add two integers
+ """
+
+ def __init__(self, *args):
+ self.kill_srv = rospy.ServiceProxy("/set_mobo_kill", SetBool)
+ self.hw_alarm_listener = AlarmListener("hw-kill")
+ super().__init__(*args)
+
+ def test_correct_response(self):
+ """
+ Test we can get correct data through CAN bus at least ten times.
+ """
+ self.kill_srv.wait_for_service(5)
+ self.hw_alarm_listener.wait_for_server()
+ self.assertTrue(self.kill_srv(SetBoolRequest(True)).success)
+ self.assertTrue(self.hw_alarm_listener.is_raised(True))
+ self.assertTrue(self.kill_srv(SetBoolRequest(False)).success)
+ self.assertTrue(self.hw_alarm_listener.is_raised(False))
+
+
+if __name__ == "__main__":
+ rospy.init_node("simulated_board_test", anonymous=True)
+ import rostest
+
+ rostest.rosrun(
+ "sub9_thrust_and_kill_board",
+ "simulated_board_test",
+ SimulatedBoardTest,
+ )
+ unittest.main()
diff --git a/SubjuGator/drivers/sub_actuator_board/CMakeLists.txt b/SubjuGator/drivers/sub_actuator_board/CMakeLists.txt
new file mode 100644
index 000000000..9309bb083
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.0.2)
+project(sub_actuator_board)
+find_package(catkin REQUIRED COMPONENTS
+ message_generation
+ mil_usb_to_can
+)
+catkin_python_setup()
+add_service_files(
+ FILES
+ SetValve.srv
+ GetValve.srv
+)
+add_rostest(test/simulated_board.test)
+generate_messages()
+catkin_package(CATKIN_DEPENDS message_runtime)
diff --git a/SubjuGator/drivers/sub_actuator_board/package.xml b/SubjuGator/drivers/sub_actuator_board/package.xml
new file mode 100644
index 000000000..0ab794680
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/package.xml
@@ -0,0 +1,15 @@
+
+
+ sub_actuator_board
+ 0.0.0
+ The sub_actuator_board package
+ Kevin Allen
+ MIT
+ Kevin Allen
+ catkin
+ message_generation
+ mil_usb_to_can
+ mil_usb_to_can
+ message_runtime
+ mil_usb_to_can
+
diff --git a/SubjuGator/drivers/sub_actuator_board/setup.py b/SubjuGator/drivers/sub_actuator_board/setup.py
new file mode 100644
index 000000000..42e9f57e8
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/setup.py
@@ -0,0 +1,9 @@
+# ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD
+
+from catkin_pkg.python_setup import generate_distutils_setup
+from setuptools import setup
+
+# Fetch values from package.xml
+setup_args = generate_distutils_setup(packages=["sub_actuator_board"])
+
+setup(**setup_args)
diff --git a/SubjuGator/drivers/sub_actuator_board/srv/GetValve.srv b/SubjuGator/drivers/sub_actuator_board/srv/GetValve.srv
new file mode 100644
index 000000000..dff0ce39b
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/srv/GetValve.srv
@@ -0,0 +1,4 @@
+# Service call to get the status of a pneumatic valve
+uint8 actuator # ID of valve
+---
+bool opened # Whether the valve has been opened
diff --git a/SubjuGator/drivers/sub_actuator_board/srv/SetValve.srv b/SubjuGator/drivers/sub_actuator_board/srv/SetValve.srv
new file mode 100644
index 000000000..837be5cd7
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/srv/SetValve.srv
@@ -0,0 +1,6 @@
+# Service call to open or close a pneumatic valve
+uint8 actuator # ID of valve
+bool opened # If True, valve will open; if False, valve will close
+---
+bool success # False if there were any problems with the request.
+string message # Description of error if success is false
diff --git a/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/__init__.py b/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/__init__.py
new file mode 100644
index 000000000..8d260d68e
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/__init__.py
@@ -0,0 +1,7 @@
+from .handle import ActuatorBoard
+from .packets import (
+ ActuatorPollRequestPacket,
+ ActuatorPollResponsePacket,
+ ActuatorSetPacket,
+)
+from .simulation import ActuatorBoardSimulation
diff --git a/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/handle.py b/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/handle.py
new file mode 100644
index 000000000..0da860670
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/handle.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python3
+from __future__ import annotations
+
+import rospy
+from mil_usb_to_can.sub9 import AckPacket, CANDeviceHandle
+
+from sub_actuator_board.srv import (
+ GetValve,
+ GetValveRequest,
+ GetValveResponse,
+ SetValve,
+ SetValveRequest,
+)
+
+from .packets import (
+ ActuatorPollRequestPacket,
+ ActuatorPollResponsePacket,
+ ActuatorSetPacket,
+)
+
+
+class ActuatorBoard(CANDeviceHandle):
+ """
+ Device handle for the actuator board. Because this class implements a CAN device,
+ it inherits from the :class:`CANDeviceHandle` class.
+ """
+
+ _recent_response: ActuatorPollResponsePacket | None
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self._set_service = rospy.Service("/set_valve", SetValve, self.set_valve)
+ self._get_service = rospy.Service("/get_valve", GetValve, self.get_valve)
+ self._recent_response = None
+
+ def set_valve(self, req: SetValveRequest) -> dict:
+ """
+ Called when the ``/set_valve`` service is requested. Creates a message to
+ control the valve and sends it through the inherited device handle.
+
+ Args:
+ req (SetValveRequest): Request to set the valve.
+
+ Returns:
+ dict: List of information which is casted into a SetValveResponse.
+ """
+ # Send board command to open or close specified valve
+ message = ActuatorSetPacket(address=req.actuator, open=req.opened)
+ self.send_data(message)
+ rospy.loginfo(
+ "Set valve {} {}".format(
+ req.actuator,
+ "opened" if req.opened else "closed",
+ ),
+ )
+ # Wait some time for board to process command
+ rospy.sleep(0.01)
+ # Request the status of the valve just commanded to ensure it worked
+ self.send_data(ActuatorPollRequestPacket())
+ start = rospy.Time.now()
+ while rospy.Time.now() - start < rospy.Duration(2):
+ if self._recent_response is not None:
+ break
+
+ success = False
+ if self._recent_response is not None:
+ if not req.opened:
+ success = not (self._recent_response.values & (1 << req.actuator))
+ else:
+ success = self._recent_response.values & (1 << req.actuator)
+ response = {"success": success}
+ self._recent_response = None
+ return response
+
+ def get_valve(self, req: GetValveRequest) -> GetValveResponse:
+ message = ActuatorPollRequestPacket()
+ self.send_data(message)
+ start = rospy.Time.now()
+ while rospy.Time.now() - start < rospy.Duration(10):
+ if self._recent_response is not None:
+ break
+
+ if not self._recent_response:
+ raise RuntimeError("No response from the board within 10 seconds.")
+
+ response = GetValveResponse(
+ opened=self._recent_response.values & (1 << req.actuator),
+ )
+ self._recent_response = None
+ return response
+
+ def on_data(self, packet: ActuatorPollResponsePacket | AckPacket) -> None:
+ """
+ Process data received from board.
+ """
+ if isinstance(packet, ActuatorPollResponsePacket):
+ self._recent_response = packet
diff --git a/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/packets.py b/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/packets.py
new file mode 100644
index 000000000..9a146f363
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/packets.py
@@ -0,0 +1,50 @@
+from dataclasses import dataclass
+
+from mil_usb_to_can.sub9 import Packet
+
+
+@dataclass
+class ActuatorSetPacket(Packet, msg_id=0x03, subclass_id=0x00, payload_format="BB"):
+ """
+ Packet used by the actuator board to set a specific valve.
+
+ Attributes:
+ address (int): The actuator ID to set.
+ open (bool): Whether to open the specified actuator. ``True`` requests opening,
+ ``False`` requests closing.
+ """
+
+ address: int
+ open: bool
+
+
+@dataclass
+class ActuatorPollRequestPacket(
+ Packet,
+ msg_id=0x03,
+ subclass_id=0x01,
+ payload_format="",
+):
+ """
+ Packet used by the actuator board to request the status of all valves.
+ """
+
+ pass
+
+
+@dataclass
+class ActuatorPollResponsePacket(
+ Packet,
+ msg_id=0x03,
+ subclass_id=0x02,
+ payload_format="B",
+):
+ """
+ Packet used by the actuator board to return the status of all valves.
+
+ Attributes:
+ values (int): The statues of all actuators. Bits 0-3 represent the opened
+ status of actuators 0-3.
+ """
+
+ values: int
diff --git a/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/simulation.py b/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/simulation.py
new file mode 100644
index 000000000..dd77921e1
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/sub_actuator_board/simulation.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python3
+from __future__ import annotations
+
+import random
+
+import rospy
+from mil_usb_to_can.sub9 import AckPacket, SimulatedCANDeviceHandle
+
+from .packets import (
+ ActuatorPollRequestPacket,
+ ActuatorPollResponsePacket,
+ ActuatorSetPacket,
+)
+
+
+class ActuatorBoardSimulation(SimulatedCANDeviceHandle):
+ """
+ Simulator for the communication of the actuator board.
+
+ Attributes:
+ status (Dict[int, bool]): The status of the valves. The keys are each of the valve IDs,
+ and the values are the statues of whether the valves are open.
+ """
+
+ def __init__(self, *args, **kwargs):
+ # Tracks the status of the 12 valves
+ self.status = {i: False for i in range(4)}
+ super().__init__(*args, **kwargs)
+
+ def on_data(self, packet: ActuatorSetPacket | ActuatorPollRequestPacket) -> None:
+ """
+ Processes data received from motherboard / other devices. For each message received,
+ the class' status attribute is updated if the message is asking to write, otherwise
+ a feedback message is constructed and sent back.
+ """
+ # If message is writing a valve, store this change in the internal dictionary
+ if isinstance(packet, ActuatorSetPacket):
+ rospy.sleep(random.randrange(0, 1)) # Time to simluate opening of valves
+ self.status[packet.address] = packet.open
+ self.send_data(bytes(AckPacket()))
+
+ # If message is a status request, send motherboard the status of the requested valve
+ elif isinstance(packet, ActuatorPollRequestPacket):
+ self.send_data(
+ bytes(
+ ActuatorPollResponsePacket(
+ int(
+ "".join(
+ str(int(x)) for x in reversed(self.status.values())
+ ),
+ base=2,
+ ),
+ ),
+ ),
+ )
diff --git a/SubjuGator/drivers/sub_actuator_board/test/simulated_board.test b/SubjuGator/drivers/sub_actuator_board/test/simulated_board.test
new file mode 100644
index 000000000..7257f68ef
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/test/simulated_board.test
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ device_handles:
+ sub_actuator_board.ActuatorBoard: [sub_actuator_board.ActuatorPollResponsePacket]
+ simulated_devices:
+ sub_actuator_board.ActuatorBoardSimulation: [sub_actuator_board.ActuatorPollRequestPacket, sub_actuator_board.ActuatorSetPacket]
+
+
+
+
+
diff --git a/SubjuGator/drivers/sub_actuator_board/test/simulated_board_test.py b/SubjuGator/drivers/sub_actuator_board/test/simulated_board_test.py
new file mode 100755
index 000000000..8c4665f09
--- /dev/null
+++ b/SubjuGator/drivers/sub_actuator_board/test/simulated_board_test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+import unittest
+
+import rospy
+from sub_actuator_board.srv import GetValve, GetValveRequest, SetValve, SetValveRequest
+
+
+class SimulatedBoardTest(unittest.TestCase):
+ """
+ Integration test for CAN2USB board driver. Talks
+ to a simulated CAN device which should add two integers
+ """
+
+ def __init__(self, *args):
+ self.set_srv = rospy.ServiceProxy("/set_valve", SetValve)
+ self.get_srv = rospy.ServiceProxy("/get_valve", GetValve)
+ super().__init__(*args)
+
+ def test_correct_response(self):
+ """
+ Test we can get correct data through CAN bus at least ten times.
+ """
+ self.set_srv.wait_for_service(1)
+ self.get_srv.wait_for_service(1)
+ self.assertTrue(self.set_srv(SetValveRequest(0, True)).success)
+ self.assertTrue(self.get_srv(GetValveRequest(0)).opened)
+ self.assertTrue(self.set_srv(SetValveRequest(0, False)).success)
+ self.assertFalse(self.get_srv(GetValveRequest(0)).opened)
+ self.assertTrue(self.set_srv(SetValveRequest(0, False)).success)
+ self.assertFalse(self.get_srv(GetValveRequest(0)).opened)
+ self.assertTrue(self.set_srv(SetValveRequest(3, True)).success)
+ self.assertTrue(self.get_srv(GetValveRequest(3)).opened)
+ self.assertFalse(self.get_srv(GetValveRequest(0)).opened)
+ self.assertTrue(self.set_srv(SetValveRequest(4, False)).success)
+ self.assertFalse(self.get_srv(GetValveRequest(4)).opened)
+ self.assertFalse(self.get_srv(GetValveRequest(0)).opened)
+
+
+if __name__ == "__main__":
+ rospy.init_node("simulated_board_test", anonymous=True)
+ import rostest
+
+ rostest.rosrun("sub_actuator_board", "simulated_board_test", SimulatedBoardTest)
+ unittest.main()
diff --git a/SubjuGator/etc/motd b/SubjuGator/etc/motd
new file mode 100644
index 000000000..bf6bb0855
--- /dev/null
+++ b/SubjuGator/etc/motd
@@ -0,0 +1,9 @@
+#-------#-------#-------#-------#-------#-------#-------#-------#
+ You have connected to SubjuGator 8!
+#-------#-------#-------#-------#-------#-------#-------#-------#
+
+If you are testing the sub in the water (or are preparing to do so), please make sure to read the Subjugator Testing Procedures page on uf-mil.github.io for useful tips, advice, and checklists.
+
+We (the previous MIL members) will watch your testing session with great interest.
+
+Happy Testing!
diff --git a/SubjuGator/gnc/subjugator_thruster_mapper/config/thruster_layout.yaml b/SubjuGator/gnc/subjugator_thruster_mapper/config/thruster_layout.yaml
index 2d3de8ac9..48992559a 100644
--- a/SubjuGator/gnc/subjugator_thruster_mapper/config/thruster_layout.yaml
+++ b/SubjuGator/gnc/subjugator_thruster_mapper/config/thruster_layout.yaml
@@ -30,7 +30,7 @@ thruster_ports:
# mapping from thrust in Newtons to effort (e = t[0]x^4 + t[1]x^3 + t[2]x^2 + t[3]x)
thrusters:
FLH: {
- node_id: 3,
+ node_id: 4,
position: [0.2678, 0.2795, 0.0],
direction: [0.866, -0.5, 0.0],
thrust_bounds: [-81.85, 99.7],
@@ -42,7 +42,7 @@ thrusters:
}
}
FLV: {
- node_id: 1,
+ node_id: 5,
position: [0.1583, 0.169, 0.0142],
direction: [0.0, 0.0, 1.0],
thrust_bounds: [-81.85, 99.7],
@@ -54,7 +54,7 @@ thrusters:
}
}
FRH: {
- node_id: 2,
+ node_id: 0,
position: [0.2678, -0.2795, 0.0],
direction: [0.866, 0.5, 0.0],
thrust_bounds: [-81.85, 99.7],
@@ -66,9 +66,9 @@ thrusters:
}
}
FRV: {
- node_id: 0,
+ node_id: 1,
position: [0.1583, -0.169, 0.0142],
- direction: [0.0, 0.0, -1.0],
+ direction: [0.0, 0.0, 1.0],
thrust_bounds: [-81.85, 99.7],
calib: {
# yamllint disable-line rule:line-length
@@ -78,7 +78,7 @@ thrusters:
}
}
BLH: {
- node_id: 4,
+ node_id: 3,
position: [-0.2678, 0.2795, 0.0],
direction: [0.866, 0.5, 0.0],
thrust_bounds: [-81.85, 99.7],
@@ -90,7 +90,7 @@ thrusters:
}
}
BLV: {
- node_id: 5,
+ node_id: 6,
position: [-0.1583, 0.169, 0.0142],
direction: [0.0, 0.0, 1.0],
thrust_bounds: [-81.85, 99.7],
@@ -102,7 +102,7 @@ thrusters:
}
}
BRH: {
- node_id: 6,
+ node_id: 7,
position: [-0.2678, -0.2795, 0.0],
direction: [0.866, -0.5, 0.0],
thrust_bounds: [-81.85, 99.7],
@@ -114,7 +114,7 @@ thrusters:
}
}
BRV: {
- node_id: 7,
+ node_id: 2,
position: [-0.1583, -0.169, 0.0142],
direction: [0.0, 0.0, 1.0],
thrust_bounds: [-81.85, 99.7],
diff --git a/SubjuGator/perception/subjugator_perception/ml_classifiers/path_marker/path_localizer.py b/SubjuGator/perception/subjugator_perception/ml_classifiers/path_marker/path_localizer.py
index 29665f12a..c70e5e258 100755
--- a/SubjuGator/perception/subjugator_perception/ml_classifiers/path_marker/path_localizer.py
+++ b/SubjuGator/perception/subjugator_perception/ml_classifiers/path_marker/path_localizer.py
@@ -17,7 +17,7 @@
rospack.get_path("subjugator_perception") + "/ml_classifiers/path_marker/utils",
)
-from utils import detector_utils # noqa: manually appending sys.path
+from utils import detector_utils # noqa
class classifier:
diff --git a/SubjuGator/perception/subjugator_perception/nodes/dice_detect.py b/SubjuGator/perception/subjugator_perception/nodes/dice_detect.py
index 55d1dd5e2..312123597 100755
--- a/SubjuGator/perception/subjugator_perception/nodes/dice_detect.py
+++ b/SubjuGator/perception/subjugator_perception/nodes/dice_detect.py
@@ -93,7 +93,7 @@ def detect(self, dice_img):
params.minConvexity = 0.8 # 1 = perfect convex hull
# Filter by Inertia
params.filterByInertia = True
- params.minInertiaRatio = 0.4 # Defines the ellipsoid 1= detects only cirlces
+ params.minInertiaRatio = 0.4 # Defines the ellipsoid 1= detects only circles
# 0 = Detects even lines
# Create a detector with the parameters
diff --git a/SubjuGator/perception/subjugator_perception/nodes/hsv_calibration.py b/SubjuGator/perception/subjugator_perception/nodes/hsv_calibration.py
index 4a67f4bb7..433133431 100755
--- a/SubjuGator/perception/subjugator_perception/nodes/hsv_calibration.py
+++ b/SubjuGator/perception/subjugator_perception/nodes/hsv_calibration.py
@@ -36,13 +36,17 @@ def parse_string(threshes):
def reconfigure(self, config, level):
try:
self.lower = np.array(self.parse_string(config["dyn_lower"]))
- rospy.logwarn("HSV lower bound below minimum value") if (
- self.lower < 0
- ).any() else None
+ (
+ rospy.logwarn("HSV lower bound below minimum value")
+ if (self.lower < 0).any()
+ else None
+ )
self.upper = np.array(self.parse_string(config["dyn_upper"]))
- rospy.logwarn("HSV upper bound above maximum values") if (
- self.upper[0] > 179
- ).any() or (self.upper[1:] > 255).any() else None
+ (
+ rospy.logwarn("HSV upper bound above maximum values")
+ if (self.upper[0] > 179).any() or (self.upper[1:] > 255).any()
+ else None
+ )
except ValueError as e:
rospy.logwarn(f"Invalid dynamic reconfigure: {e}")
diff --git a/SubjuGator/perception/subjugator_perception/nodes/orange_rectangle_finder.py b/SubjuGator/perception/subjugator_perception/nodes/orange_rectangle_finder.py
index 0701c3b05..237fe94e3 100755
--- a/SubjuGator/perception/subjugator_perception/nodes/orange_rectangle_finder.py
+++ b/SubjuGator/perception/subjugator_perception/nodes/orange_rectangle_finder.py
@@ -52,7 +52,7 @@ class OrangeRectangleFinder:
* Transform this frames pose into /map frame
* Plug this frames pose in /map into a kalman filter to reduce noise
- TODO: Allow for two objects to be identifed at once, both filtered through its own KF
+ TODO: Allow for two objects to be identified at once, both filtered through its own KF
"""
# Coordinate axes for debugging image
diff --git a/SubjuGator/perception/subjugator_perception/nodes/torpedo_board.cpp b/SubjuGator/perception/subjugator_perception/nodes/torpedo_board.cpp
index a5f2aa352..51f57e387 100644
--- a/SubjuGator/perception/subjugator_perception/nodes/torpedo_board.cpp
+++ b/SubjuGator/perception/subjugator_perception/nodes/torpedo_board.cpp
@@ -1494,7 +1494,7 @@ void anisotropic_diffusion(const Mat &src, Mat &dest, int t_max)
if (i == 0 || i == x0.rows - 1 || j == 0 || j == x0.cols - 1) // conduction coefficient set to
d = 1; // 1 p633 after equation 13
else
- d = 1.0 / (1 + (gx * gx + 0 * gy * gy) * K2); // expression of g(gradient(I))
+ d = 1.0 / (1 + (gx * gx + 0 * gy * gy) * K2); // expression of g(gradient(I))
// d =-exp(-(gx*gx+gy*gy)*K2); // expression of g(gradient(I))
D.at(i, j) = d;
}
diff --git a/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/HOG/HOG_SVM_trainer.py b/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/HOG/HOG_SVM_trainer.py
index bbdb7aefb..01e85b3a2 100644
--- a/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/HOG/HOG_SVM_trainer.py
+++ b/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/HOG/HOG_SVM_trainer.py
@@ -16,8 +16,7 @@
class_list = np.array(0)
# loop through the training images
-count = 0
-for i in os.listdir(os.path.abspath(folder)):
+for count, i in enumerate(os.listdir(os.path.abspath(folder))):
# get the roi from the file
path = folder + "/" + i
roi_str = f.readline()
@@ -72,7 +71,6 @@
class_temp = np.empty(len_myinvhog / 9)
class_temp.fill(-1)
class_list = np.append(class_list, class_temp)
- count += 1
# hack
class_list = np.delete(class_list, [0])
diff --git a/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/machine_learning/boost_auto.py b/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/machine_learning/boost_auto.py
index c9027ff60..c1cf17e1a 100644
--- a/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/machine_learning/boost_auto.py
+++ b/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/machine_learning/boost_auto.py
@@ -100,10 +100,11 @@ def train_on_data(observation_list, label_list, split_factor=4):
s_time = time.time()
process_round = 0
# Split this into multiple passes in an attempt to free RAM (no idea if this works).
- for x, y in zip(all_observations_split, all_labels_split):
+ for process_round, (x, y) in enumerate(
+ zip(all_observations_split, all_labels_split),
+ ):
print(f"Training subset {process_round + 1}/{split_factor}.")
boost.train(x, cv2.CV_ROW_SAMPLE, y, params=parameters)
- process_round += 1
print(f"Time to complete: {time.time() - s_time}")
print("Done! Saving...")
diff --git a/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/marker_occ_grid.py b/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/marker_occ_grid.py
index 9261de0ac..c547f7847 100644
--- a/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/marker_occ_grid.py
+++ b/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/marker_occ_grid.py
@@ -174,7 +174,7 @@ def return_pose(self, srv):
self.poly_generator = self.polygon_generator()
return [0, False, srv.intial_position]
- # We search at 1.5 * r so that there is some overlay in the search feilds.
+ # We search at 1.5 * r so that there is some overlay in the search fields.
np_pose = msg_helpers.pose_to_numpy(srv.intial_position)
rot_mat = make_2D_rotation(
tf.transformations.euler_from_quaternion(np_pose[1])[2],
@@ -249,7 +249,6 @@ def polygon_generator(self, n=12):
class MarkerOccGrid(OccGridUtils):
-
"""
Handles updating occupancy grid when new data comes in.
TODO: Upon call can return some path to go to in order to find them.
diff --git a/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/rviz.py b/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/rviz.py
index c46dd18ea..e6af8929a 100644
--- a/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/rviz.py
+++ b/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/rviz.py
@@ -9,7 +9,6 @@
class RvizVisualizer:
-
"""Cute tool for drawing both depth and height-from-bottom in RVIZ"""
def __init__(self, topic="visualization/markers"):
diff --git a/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/visual_threshold_tools.py b/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/visual_threshold_tools.py
index 7ec7d04c9..f30275cfc 100644
--- a/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/visual_threshold_tools.py
+++ b/SubjuGator/perception/subjugator_perception/subjugator_vision_tools/visual_threshold_tools.py
@@ -63,7 +63,6 @@ def denormalize(val, _min, _max):
class ExtentDialog(traits.api.HasTraits):
-
"""A dialog to graphically adjust the extents of a threshold range"""
# Data extents
diff --git a/SubjuGator/perception/subjugator_perception/test/test_path_marker.py b/SubjuGator/perception/subjugator_perception/test/test_path_marker.py
index 4f3a621cc..5674ddf5a 100755
--- a/SubjuGator/perception/subjugator_perception/test/test_path_marker.py
+++ b/SubjuGator/perception/subjugator_perception/test/test_path_marker.py
@@ -17,7 +17,6 @@
class TestPathMarker(unittest.TestCase):
-
"""
Unit test for perception service finding orange path markers
Plays several bags with known pixel coordinates of path marker,
diff --git a/SubjuGator/simulation/subjugator_gazebo/diagnostics/gazebo_tests/common.py b/SubjuGator/simulation/subjugator_gazebo/diagnostics/gazebo_tests/common.py
index de7bc39f0..38a5baf41 100644
--- a/SubjuGator/simulation/subjugator_gazebo/diagnostics/gazebo_tests/common.py
+++ b/SubjuGator/simulation/subjugator_gazebo/diagnostics/gazebo_tests/common.py
@@ -8,7 +8,6 @@
class Job:
-
"""Inherit from this!"""
_job_name = "generic job"
diff --git a/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/shaders/shader_manager.py b/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/shaders/shader_manager.py
index edfb7d12f..192755207 100644
--- a/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/shaders/shader_manager.py
+++ b/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/shaders/shader_manager.py
@@ -36,7 +36,6 @@ def add_item(self, position, intensity):
class ShaderManager:
-
"""
This class is used when you want to have an entity switch out shaders at a specific time.
If you want to add another rule for when to switch out shaders:
diff --git a/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/shaders/shaders.py b/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/shaders/shaders.py
index d4a2e1f62..210a68e8e 100644
--- a/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/shaders/shaders.py
+++ b/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/shaders/shaders.py
@@ -65,7 +65,6 @@ def recursive_dictionary(self, path, text):
class Shaders:
-
"""A Shaders class, which automatically contains all of the shaders
in the shaders folder
WTF?
diff --git a/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/widgets/sub.py b/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/widgets/sub.py
index cbb628bad..144ec195d 100644
--- a/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/widgets/sub.py
+++ b/SubjuGator/simulation/subjugator_simulation/subjugator_sim_tools/widgets/sub.py
@@ -83,7 +83,6 @@ def make_visual(self, physical, position, thrust_indicators=False):
)
class ThrustGetter:
-
"""This is a pretty garbage thing, and will be replaced by the scenegraph system"""
def __init__(self, thruster_name, rdir):
diff --git a/SubjuGator/utils/subjugator_build_tools/include/subjugator_build_tools/backward.hpp b/SubjuGator/utils/subjugator_build_tools/include/subjugator_build_tools/backward.hpp
index 9c6f0316e..35f85d221 100644
--- a/SubjuGator/utils/subjugator_build_tools/include/subjugator_build_tools/backward.hpp
+++ b/SubjuGator/utils/subjugator_build_tools/include/subjugator_build_tools/backward.hpp
@@ -222,7 +222,7 @@ struct hashtable
using std::move;
} // namespace details
} // namespace backward
-#else // NOT BACKWARD_ATLEAST_CXX11
+#else // NOT BACKWARD_ATLEAST_CXX11
#include