+ battery_charger.md
diff --git a/docs/electrical/onboarding.md b/docs/electrical/onboarding.md
new file mode 100644
index 0000000..45d73e7
--- /dev/null
+++ b/docs/electrical/onboarding.md
@@ -0,0 +1,35 @@
+# Electrical Onboarding
+
+Welcome to the electrical team here at MIL! Our team is responsible for much of the
+team's electrical systems on the robots. This requires developing special hardware, circuitry,
+and embedded systems.
+
+:::{note}
+If you have not visited with the [welcome page](/welcome.md) and would like a
+more general overview of MIL, please check that page first!
+:::
+
+## Join the electrical Slack channel
+Like the other teams, we use Slack as our primary communication platform. Our
+Slack workspace can be found at [https://uf-mil.slack.com](https://uf-mil.slack.com/).
+Ask someone in MIL to invite you or email [ems@ufl.edu](mailto:ems@ufl.edu).
+
+Once you’re on Slack, be sure to join the [#electrical](https://app.slack.com/client/T6VBSPR50/C6VGAF2MA)
+channel. This is where we will post important updates about the electrical team,
+including meeting times.
+
+## Join the electrical GitHub
+Unlike the software and mechanical teams (who share a GitHub repository), we use
+a separate repository for the electrical team. As a result, you will need to be added
+to this organization. Once you're in Slack (or you've come to the lab), ask an electrical
+leader to add you to the GitHub organization. The organization can be found [here](https://github.com/uf-mil-electrical).
+
+We use several different repositories to store information. Typically one repo is used
+to hold information about one specific electrical design.
+
+## Complete the Getting Started Tutorial
+Now, complete the Getting Started Tutorial found on our GitHub [here](https://github.com/uf-mil-electrical/Getting-Started).
+This tutorial will walk you through gaining the skills you need to become a complete
+electrical wizard!
+
+If you need help with any part of the tutorial, please contact an electrical lead.
diff --git a/docs/extensions/attributetable.py b/docs/extensions/attributetable.py
new file mode 100644
index 0000000..53372cb
--- /dev/null
+++ b/docs/extensions/attributetable.py
@@ -0,0 +1,594 @@
+"""
+Credit goes to discord.py and its creators for creating most of this file:
+https://github.com/Rapptz/discord.py/blob/master/docs/extensions/attributetable.py
+"""
+
+import importlib
+import inspect
+import re
+from collections import OrderedDict, namedtuple
+from typing import List
+
+import sphinx.errors
+from docutils import nodes
+from docutils.nodes import Node
+from sphinx import addnodes
+from sphinx.locale import _
+from sphinx.util.docutils import SphinxDirective
+
+
+class attributetable(nodes.General, nodes.Element):
+ pass
+
+
+class attributetablecolumn(nodes.General, nodes.Element):
+ pass
+
+
+class attributetabletitle(nodes.TextElement):
+ pass
+
+
+class attributetableplaceholder(nodes.General, nodes.Element):
+ pass
+
+
+class cppattributetableplaceholder(nodes.General, nodes.Element):
+ pass
+
+
+class attributetablebadge(nodes.TextElement):
+ pass
+
+
+class attributetable_item(nodes.Part, nodes.Element):
+ pass
+
+
+def visit_attributetable_node(self, node):
+ """
+ Returns the starting HTML for the attribute table.
+ """
+ class_ = node["python-class"] if "python-class" in node else node["cpp-full-name"]
+ self.body.append(f'')
+
+
+def visit_attributetablecolumn_node(self, node):
+ """
+ Returns the starting HTML for a column of the attribute table. Just a div!
+ """
+ self.body.append(self.starttag(node, "div", CLASS="attribute-table-column"))
+
+
+def visit_attributetabletitle_node(self, node):
+ """
+ Returns the starting HTML for a title in the attribute table. Just a div!
+ """
+ self.body.append(self.starttag(node, "span"))
+
+
+def visit_attributetablebadge_node(self, node):
+ """
+ Returns the starting HTML for a badge in the attribute table. Just a div!
+ """
+ attributes = {
+ "class": "attribute-table-badge",
+ "title": node["badge-type"],
+ }
+ self.body.append(self.starttag(node, "span", **attributes))
+
+
+def visit_attributetable_item_node(self, node):
+ """
+ Returns the starting HTML for an entry in the attribute table. Just a div!
+ """
+ self.body.append(self.starttag(node, "li", CLASS="attribute-table-entry"))
+
+
+def depart_attributetable_node(self, node):
+ """
+ Returns the ending HTML for the attribute table.
+ """
+ self.body.append("
")
+
+
+def depart_attributetablecolumn_node(self, node):
+ """
+ Returns the ending HTML for a column in the attribute table.
+ """
+ self.body.append("")
+
+
+def depart_attributetabletitle_node(self, node):
+ """
+ Returns the ending HTML for a title in the attribute table.
+ """
+ self.body.append("")
+
+
+def depart_attributetablebadge_node(self, node):
+ """
+ Returns the ending HTML for a badge in the attribute table.
+ """
+ self.body.append("")
+
+
+def depart_attributetable_item_node(self, node):
+ """
+ Returns the ending HTML for an item in the attribute table.
+ """
+ self.body.append("")
+
+
+_name_parser_regex = re.compile(r"(?P[\w.]+\.)?(?P\w+)")
+
+
+class PyAttributeTable(SphinxDirective):
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {}
+
+ def parse_name(self, content):
+ path, name = _name_parser_regex.match(content).groups()
+ if path:
+ modulename = path.rstrip(".")
+ else:
+ modulename = self.env.temp_data.get("autodoc:module")
+ if not modulename:
+ modulename = self.env.ref_context.get("py:module")
+ if modulename is None:
+ raise RuntimeError(
+ f"modulename somehow None for {content} in {self.env.docname}.",
+ )
+
+ return modulename, name
+
+ def run(self):
+ """If you're curious on the HTML this is meant to generate:
+
+
+
+ However, since this requires the tree to be complete
+ and parsed, it'll need to be done at a different stage and then
+ replaced.
+ """
+ content = self.arguments[0].strip()
+ node = attributetableplaceholder("")
+ modulename, name = self.parse_name(content)
+ node["python-doc"] = self.env.docname
+ node["python-module"] = modulename
+ node["python-class"] = name
+ node["python-full-name"] = f"{modulename}.{name}"
+ return [node]
+
+
+_cpp_name_parser_regex = re.compile(r"(?P[\w.]+::)?(?P\w+)")
+
+
+class CppAttributeTable(SphinxDirective):
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {}
+
+ def parse_name(self, content):
+ path, name = _cpp_name_parser_regex.match(content).groups()
+ if path:
+ namespace = path.rstrip("::")
+ else:
+ namespace = self.env.temp_data.get("autodoc:module")
+ if not namespace:
+ namespace = self.env.ref_context.get("cpp:namespace")
+
+ return namespace, name
+
+ def run(self):
+ """If you're curious on the HTML this is meant to generate:
+
+
+
+ However, since this requires the tree to be complete
+ and parsed, it'll need to be done at a different stage and then
+ replaced.
+ """
+ content = self.arguments[0].strip()
+ node = cppattributetableplaceholder("")
+ namespace, name = self.parse_name(content)
+ node["cpp-doc"] = self.env.docname
+ node["cpp-namespace"] = namespace
+ node["cpp-class"] = name
+ node["cpp-full-name"] = content
+ return [node]
+
+
+def build_lookup_table(env):
+ # Given an environment, load up a lookup table of {full-class-name: objects}
+ result = {}
+ # Only for domains beginning with py
+ domain = env.domains["py"]
+
+ # Do not include domains containing these keywords - any of these domains
+ # will never be in an attribute table
+ ignored = {
+ "data",
+ "exception",
+ "module",
+ "class",
+ }
+
+ for fullname, x, objtype, docname, y, z in domain.get_objects():
+ if objtype in ignored:
+ continue
+
+ # Split the full name by the last dot (ie, into the class and attribute)
+ classname, _, child = fullname.rpartition(".")
+ try:
+ result[classname].append(child)
+ except KeyError:
+ result[classname] = [child]
+
+ # Return dict of objects as described above
+ return result
+
+
+TableElement = namedtuple("TableElement", "fullname label badge")
+
+
+def _parse_cpp_function_sig_children(children: List[Node]):
+ # Remove equal sign and everything after if found
+ if "=" in children:
+ equal_sign = children.index("=")
+ children = children[:equal_sign]
+
+ # Remove unnecessary keywords
+ to_remove = [" ", "const"]
+ children[:] = [child for child in children if child not in to_remove]
+
+ return children[-2]
+
+
+def _parse_cpp_attribute_sig_children(children: List[Node]):
+ # Remove equal sign and everything after if found
+ if "=" in children:
+ equal_sign = children.index("=")
+ children = children[:equal_sign]
+
+ # Remove array formatting
+ if "]" in children:
+ opening_bracket = children.index("[")
+ children = children[:opening_bracket]
+
+ children[:] = [child for child in children if child not in [" ", ""]]
+ return children[-1]
+
+
+def process_cppattributetable(app, doctree: Node, fromdocname):
+ # Setup parser used by Doxygen to parse XML
+ assert app.env is not None
+
+ # Begin dict for class' objects
+ classes = (
+ {}
+ ) # {'namespace::ClassName': OrderedDict((_('Attributes'), []), (_('Functions'), [])), 'ClassNameTwo': ...}
+ ids = {}
+
+ # Find all relevant C++ functions and attributes
+ current_section = None
+
+ # Throw error if user is attempting to put attribute table for enum classk
+ for node in doctree.traverse(siblings=True):
+ if hasattr(node, "attributes"):
+ if "cpp" in node.attributes["classes"] and any(
+ c in node.attributes["classes"] for c in ["class", "struct"]
+ ):
+ # Store current C++ struct or class section as namespace::ClassName or ClassName
+ current_section = node.children[0].astext()
+
+ # Remove class/struct prefix
+ current_section = re.sub(r"^.*(class )", "", current_section)
+ current_section = re.sub(r"^.*(struct )", "", current_section)
+
+ # Remove inheritance string
+ current_section = re.sub(r" : .*$", "", current_section)
+
+ # Store goto IDs for the current section
+ ids[current_section] = node.children[0].attributes["ids"][0]
+
+ # Store basic ordered dict for attributes and functions
+ classes[current_section] = OrderedDict(
+ [
+ (_("Attributes"), []),
+ (_("Functions"), []),
+ ],
+ )
+
+ elif all(c in node.attributes["classes"] for c in ["cpp", "function"]):
+ # Get the signature line of the function, where its name is stored
+ try:
+ descriptions = [
+ n.astext() for n in node[0][0].children if isinstance(n, Node)
+ ]
+ except IndexError:
+ continue
+
+ # If we found a name
+ if descriptions:
+ # Get the ID to link to
+ fullname = None
+ try:
+ fullname = (
+ node.children[0]
+ .children[0]
+ .children[0]
+ .attributes["ids"][0]
+ )
+ except Exception:
+ fullname = ""
+
+ # Parse the function signature into just its name
+ parsed = _parse_cpp_function_sig_children(descriptions)
+
+ # Assign the actual table element for the func
+ badge = attributetablebadge("func", "func")
+ badge["badge-type"] = _("function")
+ if current_section:
+ classes[current_section][_("Functions")].append(
+ TableElement(fullname=fullname, label=parsed, badge=badge),
+ )
+
+ elif all(c in node.attributes["classes"] for c in ["cpp", "var"]):
+ # Try to get signature lines for C++ variables
+ try:
+ descriptions = [
+ n.astext() for n in node.children[0][0] if isinstance(n, Node)
+ ]
+ except IndexError:
+ continue
+
+ if descriptions:
+ # Parse C++ attribute signature to get only attribute name
+ parsed = _parse_cpp_attribute_sig_children(descriptions)
+
+ # Get the ID to link to
+ fullname = (
+ node.children[0].children[0].children[0].attributes["ids"][0]
+ )
+
+ # Make table element
+ if current_section:
+ classes[current_section][_("Attributes")].append(
+ TableElement(fullname=fullname, label=parsed, badge=None),
+ )
+
+ elif isinstance(node, nodes.section):
+ # Reset current section with each new section
+ current_section = None
+
+ # For each C++ attribute table requested
+ for node in doctree.traverse(cppattributetableplaceholder):
+ target = node["cpp-full-name"]
+
+ # New change with Sphinx 5: simpler sigs
+ target = re.sub(r".*\:\:", "", target)
+
+ # Turn the table elements in a node
+ table = attributetable("")
+
+ # Throw error if not found in list of classes
+ if target not in classes:
+ print(target, classes)
+ raise sphinx.errors.ExtensionError(
+ "No C++ class or struct was found matching the "
+ f"{target} target provided. Please ensure that this class is purely "
+ "a C++ class or struct and not any other data structure. Additionally, "
+ "ensure that proper documentation was able to be generated without "
+ "the attribute table being used. If an error occurred, please open "
+ "an issue on our GitHub repo.",
+ )
+
+ for label, subitems in classes[target].items():
+ if not subitems:
+ continue
+ table.append(
+ class_results_to_node(label, sorted(subitems, key=lambda c: c.label)),
+ )
+
+ # Turn table into node
+ table["cpp-full-name"] = ids[target]
+
+ if not table:
+ node.replace_self([])
+ else:
+ node.replace_self([table])
+
+
+def process_attributetable(app, doctree, fromdocname):
+ # Build lookup table of module names and attributes
+ env = app.builder.env
+ lookup = build_lookup_table(env)
+
+ # For each node in the doctree
+ for node in doctree.traverse(attributetableplaceholder):
+ # Info about each node
+ modulename, classname, fullname = (
+ node["python-module"],
+ node["python-class"],
+ node["python-full-name"],
+ )
+
+ # Get class results
+ groups = get_class_results(lookup, modulename, classname, fullname)
+ table = attributetable("")
+ for label, subitems in groups.items():
+ if not subitems:
+ continue
+ table.append(
+ class_results_to_node(label, sorted(subitems, key=lambda c: c.label)),
+ )
+
+ table["python-class"] = fullname
+
+ if not table:
+ node.replace_self([])
+ else:
+ node.replace_self([table])
+
+
+def get_class_results(lookup: dict, modulename: str, name: str, fullname: str):
+ # Import checked module
+ module = importlib.import_module(modulename)
+ cls = getattr(module, name)
+
+ # Begin dict for class' objects
+ groups = OrderedDict(
+ [
+ (_("Attributes"), []),
+ (_("Methods"), []),
+ ],
+ )
+
+ # If the class has members, let's get them! If not, it has no members, and
+ # we can return nothing!
+ try:
+ members = lookup[fullname]
+ except KeyError:
+ return groups
+
+ # For each member of the module
+ for attr in members:
+ attrlookup = f"{fullname}.{attr}"
+ key = _("Attributes")
+ badge = None
+ label = attr
+ value = None
+
+ # Search up the class' inheritance tree for the implementation of the
+ # desired attribute, and break when we find it!
+ for base in cls.__mro__:
+ value = base.__dict__.get(attr)
+ if value is not None:
+ break
+
+ # If we found the value, let's document it!
+ if value is not None:
+ doc = value.__doc__ or ""
+
+ # Handle async functions; give them async badge and move them to Methods
+ if inspect.iscoroutinefunction(value) or doc.startswith("|coro|"):
+ key = _("Methods")
+ badge = attributetablebadge("async", "async")
+ badge["badge-type"] = _("coroutine")
+
+ # Handle class methods; give them the cls badge and move them to Methods
+ elif isinstance(value, classmethod):
+ key = _("Methods")
+ label = f"{name}.{attr}"
+ badge = attributetablebadge("cls", "cls")
+ badge["badge-type"] = _("classmethod")
+
+ # Handle all other methods, including decorators
+ elif inspect.isfunction(value):
+ if doc.startswith(("A decorator", "A shortcut decorator")):
+ # finicky but surprisingly consistent
+ badge = attributetablebadge("@", "@")
+ badge["badge-type"] = _("decorator")
+ key = _("Methods")
+ else:
+ key = _("Methods")
+ badge = attributetablebadge("def", "def")
+ badge["badge-type"] = _("method")
+
+ # Finally, with all of the compiled info, store it in the class' table
+ groups[key].append(TableElement(fullname=attrlookup, label=label, badge=badge))
+
+ # Return the class' info table
+ return groups
+
+
+def class_results_to_node(key, elements):
+ title = attributetabletitle(key, key)
+ ul = nodes.bullet_list("")
+ for element in elements:
+ ref = nodes.reference(
+ "",
+ "",
+ *[nodes.Text(element.label)],
+ internal=True,
+ refuri=f"#{element.fullname}",
+ anchorname="",
+ )
+ para = addnodes.compact_paragraph("", "", ref)
+ if element.badge is not None:
+ ul.append(attributetable_item("", element.badge, para))
+ else:
+ ul.append(attributetable_item("", para))
+
+ return attributetablecolumn("", title, ul)
+
+
+def setup(app):
+ app.add_directive("attributetable", PyAttributeTable)
+ app.add_directive("cppattributetable", CppAttributeTable)
+ app.add_node(
+ attributetable,
+ html=(visit_attributetable_node, depart_attributetable_node),
+ )
+ app.add_node(
+ attributetablecolumn,
+ html=(visit_attributetablecolumn_node, depart_attributetablecolumn_node),
+ )
+ app.add_node(
+ attributetabletitle,
+ html=(visit_attributetabletitle_node, depart_attributetabletitle_node),
+ )
+ app.add_node(
+ attributetablebadge,
+ html=(visit_attributetablebadge_node, depart_attributetablebadge_node),
+ )
+ app.add_node(
+ attributetable_item,
+ html=(visit_attributetable_item_node, depart_attributetable_item_node),
+ )
+ app.add_node(attributetableplaceholder)
+ app.add_node(cppattributetableplaceholder)
+ app.connect("doctree-resolved", process_attributetable)
+ app.connect("doctree-resolved", process_cppattributetable)
diff --git a/docs/extensions/builder.py b/docs/extensions/builder.py
new file mode 100644
index 0000000..881417a
--- /dev/null
+++ b/docs/extensions/builder.py
@@ -0,0 +1,89 @@
+"""
+Credit goes to discord.py and its creators for creating most of this file:
+https://github.com/Rapptz/discord.py/blob/master/docs/extensions/attributetable.py
+"""
+
+from sphinx.builders.html import StandaloneHTMLBuilder
+from sphinx.environment.adapters.indexentries import IndexEntries
+from sphinx.writers.html5 import HTML5Translator
+
+
+class DPYHTML5Translator(HTML5Translator):
+ def visit_section(self, node) -> None:
+ self.section_level += 1
+ self.body.append(self.starttag(node, "section"))
+
+ def depart_section(self, node) -> None:
+ self.section_level -= 1
+ self.body.append("\n")
+
+ def visit_table(self, node) -> None:
+ self.body.append('')
+ super().visit_table(node)
+
+ def depart_table(self, node) -> None:
+ super().depart_table(node)
+ self.body.append("
")
+
+
+class DPYStandaloneHTMLBuilder(StandaloneHTMLBuilder):
+ # This is mostly copy pasted from Sphinx.
+ def write_genindex(self) -> None:
+ # the total count of lines for each index letter, used to distribute
+ # the entries into two columns
+ genindex = IndexEntries(self.env).create_index(self, group_entries=False)
+ indexcounts = []
+ for _k, entries in genindex:
+ indexcounts.append(
+ sum(1 + len(subitems) for _, (_, subitems, _) in entries),
+ )
+
+ genindexcontext = {
+ "genindexentries": genindex,
+ "genindexcounts": indexcounts,
+ "split_index": self.config.html_split_index,
+ }
+
+ if self.config.html_split_index:
+ self.handle_page("genindex", genindexcontext, "genindex-split.html")
+ self.handle_page("genindex-all", genindexcontext, "genindex.html")
+ for (key, entries), count in zip(genindex, indexcounts):
+ ctx = {
+ "key": key,
+ "entries": entries,
+ "count": count,
+ "genindexentries": genindex,
+ }
+ self.handle_page(f"genindex-{key}", ctx, "genindex-single.html")
+ else:
+ self.handle_page("genindex", genindexcontext, "genindex.html")
+
+
+def add_custom_jinja2(app) -> None:
+ env = app.builder.templates.environment
+ env.tests["prefixedwith"] = str.startswith
+ env.tests["suffixedwith"] = str.endswith
+
+
+def add_builders(app) -> None:
+ """This is necessary because RTD injects their own for some reason."""
+ app.set_translator("html", DPYHTML5Translator, override=True)
+ app.add_builder(DPYStandaloneHTMLBuilder, override=True)
+
+ try:
+ original = app.registry.builders["readthedocs"]
+ except KeyError:
+ pass
+ else:
+ injected_mro = tuple(
+ base if base is not StandaloneHTMLBuilder else DPYStandaloneHTMLBuilder
+ for base in original.mro()[1:]
+ )
+ new_builder = type(original.__name__, injected_mro, {"name": "readthedocs"})
+ app.set_translator("readthedocs", DPYHTML5Translator, override=True)
+ app.add_builder(new_builder, override=True)
+
+
+def setup(app) -> None:
+ add_builders(app)
+ app.connect("builder-inited", add_custom_jinja2)
diff --git a/docs/extensions/exception_hierarchy.py b/docs/extensions/exception_hierarchy.py
new file mode 100644
index 0000000..cdf40e3
--- /dev/null
+++ b/docs/extensions/exception_hierarchy.py
@@ -0,0 +1,35 @@
+# Source:
+# https://github.com/Rapptz/discord.py/blob/3aa55ba1edf94bfbc8423bd4cbc2adbebc12ab9d/docs/extensions/exception_hierarchy.py
+
+from docutils import nodes
+from docutils.parsers.rst import Directive
+
+
+class exception_hierarchy(nodes.General, nodes.Element):
+ pass
+
+
+def visit_exception_hierarchy_node(self, node):
+ self.body.append(self.starttag(node, "div", CLASS="exception-hierarchy-content"))
+
+
+def depart_exception_hierarchy_node(self, node):
+ self.body.append("\n")
+
+
+class ExceptionHierarchyDirective(Directive):
+ has_content = True
+
+ def run(self):
+ self.assert_has_content()
+ node = exception_hierarchy("\n".join(self.content))
+ self.state.nested_parse(self.content, self.content_offset, node)
+ return [node]
+
+
+def setup(app):
+ app.add_node(
+ exception_hierarchy,
+ html=(visit_exception_hierarchy_node, depart_exception_hierarchy_node),
+ )
+ app.add_directive("exception_hierarchy", ExceptionHierarchyDirective)
diff --git a/docs/flooded_valve_box.jpg b/docs/flooded_valve_box.jpg
new file mode 100644
index 0000000..6a769cf
Binary files /dev/null and b/docs/flooded_valve_box.jpg differ
diff --git a/docs/images/collage.png b/docs/images/collage.png
new file mode 100644
index 0000000..6686a01
Binary files /dev/null and b/docs/images/collage.png differ
diff --git a/docs/images/gazebo/Bottom_Toolbar.png b/docs/images/gazebo/Bottom_Toolbar.png
new file mode 100644
index 0000000..de1fb6d
Binary files /dev/null and b/docs/images/gazebo/Bottom_Toolbar.png differ
diff --git a/docs/images/gazebo/Interface.png b/docs/images/gazebo/Interface.png
new file mode 100644
index 0000000..b6f5018
Binary files /dev/null and b/docs/images/gazebo/Interface.png differ
diff --git a/docs/images/gazebo/Labeled_Interface.png b/docs/images/gazebo/Labeled_Interface.png
new file mode 100644
index 0000000..871ddca
Binary files /dev/null and b/docs/images/gazebo/Labeled_Interface.png differ
diff --git a/docs/images/gazebo/Menus.png b/docs/images/gazebo/Menus.png
new file mode 100644
index 0000000..d6c39d6
Binary files /dev/null and b/docs/images/gazebo/Menus.png differ
diff --git a/docs/images/gazebo/Model_Editor.png b/docs/images/gazebo/Model_Editor.png
new file mode 100644
index 0000000..362f7cb
Binary files /dev/null and b/docs/images/gazebo/Model_Editor.png differ
diff --git a/docs/images/gazebo/Mouse.png b/docs/images/gazebo/Mouse.png
new file mode 100644
index 0000000..728c8fc
Binary files /dev/null and b/docs/images/gazebo/Mouse.png differ
diff --git a/docs/images/gazebo/TrackPad.png b/docs/images/gazebo/TrackPad.png
new file mode 100644
index 0000000..1231be5
Binary files /dev/null and b/docs/images/gazebo/TrackPad.png differ
diff --git a/docs/images/gazebo/Upper_Toolbar.png b/docs/images/gazebo/Upper_Toolbar.png
new file mode 100644
index 0000000..68e36e6
Binary files /dev/null and b/docs/images/gazebo/Upper_Toolbar.png differ
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..4e6035a
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,55 @@
+.. image:: images/collage.png
+
+Machine Intelligence Lab
+===============================
+Welcome to the documentation site for the Machine Intelligence Lab at the University of Florida, a robotics lab in Gainesville, Florida. Our lab has built `several robotic systems `_ since its inception several decades ago. Our current projects include:
+
+* **SubjuGator:** An autonomous, underwater submarine-like vehicle. Three-time champion of the AUVSI/ONR underwater competition. (`Website `_)
+* **NaviGator:** An autonomous surface vehicle (ASV) which has competed in several maritime competitions. Won the 2016 Maritime RobotX Challenge, and received fourth in the 2018 Maritime RobotX Challenge. (`Website `_)
+* **Virtual RobotX:** An new extension of the NaviGator project supporting virtual robotics.
+
+Our first meeting of the Fall 2021 season was recorded, and can be found `here `_.
+The meeting introduced MIL and featured a tour of our lab. It's a great introduction
+to what we do; we encourage you to watch!
+
+New Members
+-----------
+.. toctree::
+ :hidden:
+
+ welcome
+
+ mechanical/index
+ electrical/index
+ software/index
+
+ subjugator/index
+ navigator/index
+ reference/index
+ subjugator/reference
+ navigator/reference
+ design/design
+ infrastructure/index
+
+ culture
+ purchasing
+ branding
+ deprecated
+
+* **Interested software members**: Please read the :doc:`Software Getting Started Guide `.
+* **Interested electrical members**: Please read the :doc:`Electrical Onboarding Guide `
+* **Interested mechanical members**: Please read the :doc:`Mechanical Onboarding Guide `.
+
+Relevant Links
+--------------
+* **Websites:** `MIL Website `_ / `NaviGator `_ / `SubjuGator `_
+* **Source:** `GitHub `_
+* **Laboratory Resources:** :doc:`Purchasing ` / :doc:`Branding `
+* **Culture:** :doc:`Culture ` / :doc:`Technical Design `
+
+Software Reference
+------------------
+* **All Repository Source Documentation:** :doc:`Reference `
+* **Practices:** :doc:`Our Development Practices ` / :doc:`Scripts ` / :doc:`Extensions `
+* **Project Procedures:** :doc:`SubjuGator ` / :doc:`VRX `
+* **Getting Help:** :doc:`Development Help `
diff --git a/docs/indyav/autonomy_architecture.rst b/docs/indyav/autonomy_architecture.rst
new file mode 100644
index 0000000..81ce79c
--- /dev/null
+++ b/docs/indyav/autonomy_architecture.rst
@@ -0,0 +1,19 @@
+Autonomy Architecture
+=====================
+
+GO-Kart
+-------
+The Go-Kart will be a waypoint following autonomy. The optimal racing line will
+be supplied aprior and the vehicle will attempt to track the provided racing
+line.
+
+.. image:: preliminary_architecture_2_15_20.png
+ :width: 640px
+ :align: center
+ :height: 400px
+
+Indy Light Vehicle
+------------------
+In addition to tracking a optimal racing line, the indy light autonomy must
+also contend with other autonomous racers. This will require decision making
+and obstacle avoidance behavior.
diff --git a/docs/indyav/gator_double_dragon.jpg b/docs/indyav/gator_double_dragon.jpg
new file mode 100644
index 0000000..f5ecf49
Binary files /dev/null and b/docs/indyav/gator_double_dragon.jpg differ
diff --git a/docs/indyav/hardware/go_kart/electronics.rst b/docs/indyav/hardware/go_kart/electronics.rst
new file mode 100644
index 0000000..895707d
--- /dev/null
+++ b/docs/indyav/hardware/go_kart/electronics.rst
@@ -0,0 +1,3 @@
+Electronics Documentation
+=========================
+TODO
diff --git a/docs/indyav/hardware/go_kart/mechanical.rst b/docs/indyav/hardware/go_kart/mechanical.rst
new file mode 100644
index 0000000..85f14a2
--- /dev/null
+++ b/docs/indyav/hardware/go_kart/mechanical.rst
@@ -0,0 +1,3 @@
+Mechanical Documentation
+========================
+TODO
diff --git a/docs/indyav/hardware/go_kart/mechatronics.rst b/docs/indyav/hardware/go_kart/mechatronics.rst
new file mode 100644
index 0000000..5871123
--- /dev/null
+++ b/docs/indyav/hardware/go_kart/mechatronics.rst
@@ -0,0 +1,17 @@
+Mechatronics Documentation
+==========================
+
+Actuators
+---------
+
+Animatics Smart Motor
+*********************
+SM2337D
+
+
+
+Sensors
+-------
+* `Sylpase Infix-1 GNSS/INS `_
+* `Velodyne Puck (VLP-16) `_
+* `See3CAM_CU20 `_
diff --git a/docs/indyav/hardware/hardware.rst b/docs/indyav/hardware/hardware.rst
new file mode 100644
index 0000000..61a65ca
--- /dev/null
+++ b/docs/indyav/hardware/hardware.rst
@@ -0,0 +1,16 @@
+Hardware
+========
+
+Go-Kart
+-------
+
+.. toctree::
+ :maxdepth: 1
+
+ Electronics
+ Mechatronics
+ Mechanical
+
+Indy Light
+----------
+TBD
diff --git a/docs/indyav/index.rst b/docs/indyav/index.rst
new file mode 100644
index 0000000..5a4eaf3
--- /dev/null
+++ b/docs/indyav/index.rst
@@ -0,0 +1,28 @@
+Indy AV
+=====================
+Welcome to team Gator Double Dragon's documentation. The team is a collabortaion
+between the University of Florida and Kookmin University for the
+`Indy Autonomous Challenge `_.
+
+.. image:: gator_double_dragon.jpg
+ :width: 600px
+ :align: center
+ :height: 420px
+
+Collaborators
+-------------
+
+`Center for Intelligent Machines and Robotics `_, CIMAR
+
+`Machine Intelligence Laboratory `_, MIL
+
+`Nonlinear Controls and Robotics Lab `_, NCR
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Links
+
+ Getting Started on Indy AV
+ Autonomy Architecture
+ Hardware
+ Software
diff --git a/docs/indyav/onboarding.rst b/docs/indyav/onboarding.rst
new file mode 100644
index 0000000..4401033
--- /dev/null
+++ b/docs/indyav/onboarding.rst
@@ -0,0 +1,27 @@
+Getting Started on Indy AV
+==========================
+
+Collaboration
+-------------
+Make sure to checkout `Development <../development/index.html>`_ first.
+
+Slack
+*****
+Join the slack to keep updated on the development at `uf-cimar `_.
+Any valid @ufl.edu email will be able to create an account.
+
+Github
+******
+Documentation and all work (except CAD) for Indy AV will go in the `MIL REPO `_
+
+Grabcad
+*******
+We use GrabCAD Workbench to manage mechanical design files.
+
+Software
+--------
+We will follow MIL's `MIL's development practices <../development/development_guide.html>`_
+
+Mechanical
+----------
+We use SolidWorks as the primary CAD software for this project.
diff --git a/docs/indyav/preliminary_architecture_2_15_20.png b/docs/indyav/preliminary_architecture_2_15_20.png
new file mode 100644
index 0000000..e4d9137
Binary files /dev/null and b/docs/indyav/preliminary_architecture_2_15_20.png differ
diff --git a/docs/indyav/software/control/control.rst b/docs/indyav/software/control/control.rst
new file mode 100644
index 0000000..862eac8
--- /dev/null
+++ b/docs/indyav/software/control/control.rst
@@ -0,0 +1,28 @@
+Control
+=======
+
+.. toctree::
+ :maxdepth: 1
+
+ IndyAV Joydrive
+
+Control Packages
+----------------
+No software developed yet.
+
+Discussion
+-------------
+Initial development will start simple.
+
+Pure Pursuit Steering Control
+*****************************
+Initial implementations for the path tracking controller will be a pure pursuit controller
+
+PID Speed Control
+*****************
+The speed control will consist of some combination of proportional, integral, and derivative.
+The error state will be the delta between a desired and measured forward speed.
+
+Future Work
+-----------
+* MPC controller will probably be looked into.
diff --git a/docs/indyav/software/control/joydrive/joydrive.rst b/docs/indyav/software/control/joydrive/joydrive.rst
new file mode 100644
index 0000000..5221599
--- /dev/null
+++ b/docs/indyav/software/control/joydrive/joydrive.rst
@@ -0,0 +1,45 @@
+IndyAV Joydrive Utility
+=======================
+
+
+How to Use
+----------
+
+Setting up an Xbox 360 controller
+*********************************
+``roslaunch indyav_launch gazebo.launch``
+
+Plug in the controller and check to see if it is recognized.
+``ls /dev/input/``
+This outputs a list of input devices in the format shown below::
+
+ by-id event0 event2 event4 event6 event8 mouse0 mouse2 uinput
+ by-path event1 event3 event5 event7 js0 mice mouse1
+
+Joysticks will be listed as jsX.
+
+Running the utility
+*******************
+Launch the Joydrive.
+``roslaunch indyav_launch joydrive.launch``
+By default, js0 is used by the joydrive utility. To change the input device, pass the name of the input device using the "js" argument.
+``roslaunch indyav_launch joydrive.launch js:=js1``
+
+In a new panel, launch Gazebo for IndyAV.
+``roslaunch indyav_launch gazebo.launch``
+
+In a new panel, launch RVIZ for IndyAV.
+``indyviz``
+
+In a new panel, launch the Gazebo Client.
+``gazebogui``
+
+Using the utility
+*****************
+Moving the left joystick left and right steers the car.
+
+Depressing the right trigger accelerates the car. Releasing the trigger brakes the car.
+
+Optionally, one can view the values for the wheel velocity and steering angle by running the following in new panels:
+``rostopic echo /throttle``
+``rostopic echo /steering``
diff --git a/docs/indyav/software/localization.rst b/docs/indyav/software/localization.rst
new file mode 100644
index 0000000..dd59d02
--- /dev/null
+++ b/docs/indyav/software/localization.rst
@@ -0,0 +1,54 @@
+Localization
+============
+
+Localization Packages
+---------------------
+Sylphase INS
+
+Discussion
+----------
+Currently we are investigating 3 types of sensor to be used used for localization:
+
+Inertial Navigator Sensors and GNSS (GPS, GLONASS, etc.)
+********************************************************
+INS and GNSS are usually coupled into an single device.
+
+Pros
+####
+* Directly yields position and orientation data, minimal computation required.
+* RTK and other corrections can greatly boost the accuracy of the position measurement.
+
+Cons
+####
+* GNSS data rate is slow < 10Hz
+* Position can drift if too reliant on inertial sensors.
+* GNSS is known to produce large errors if environmental conditions negatively affect the signals.
+
+LIDAR Localization
+******************
+
+Pros
+####
+* High definition geometric data that can be compared to a know point cloud.
+* Plenty of existing algorithms to do this: e.g NDT Matching
+* Operates in almost any lighting conditions
+
+Cons
+####
+* Slow data acquisition rate, at high speeds a mechanical spinning LIDAR would not capture the world correctly
+* Somewhat costly, not as bad anymore
+* Mechanical spinning LIDARS will be affected my the fast movements of the vehicle.
+
+Camera Localization
+*******************
+Camera based localization would rely on algorithm suchs as [ORB-SLAM](https://webdiis.unizar.es/~raulmur/orbslam/) to determine the position and orientation of the sensor with respect to a pre-constructed map.
+
+Pros
+####
+* Cheaper than LIDARs most of the time
+* High data acquisition rate, 100+ FPS
+
+Cons
+####
+* Camera based computations can be costly which would reduce the effectiveness of their high data acquisition
+* Lighting can extremely affect the usability of the sensor.
diff --git a/docs/indyav/software/perception.rst b/docs/indyav/software/perception.rst
new file mode 100644
index 0000000..dc5b2b3
--- /dev/null
+++ b/docs/indyav/software/perception.rst
@@ -0,0 +1,45 @@
+Perception
+==========
+
+Perception Packages
+-------------------
+No software developed yet.
+
+Discussion
+----------
+If the assumption is that the vehicle will be able to localize relative to a preconstructed map, then what is left to perceive is only other racers on the track.
+
+Potential sensors
+
+LIDAR
+*****
+
+Pros
+####
+* Provides accurate geometric data.
+
+Cons
+####
+* Not as feature rich as images
+* Max data rate of ~20Hz
+
+Camera
+******
+
+Pros
+####
+* Feature rich data
+* A lot of research and development for this sensor
+
+Cons
+####
+
+Radar
+*****
+No previous experience with this sensor
+
+Pros
+####
+
+Cons
+####
diff --git a/docs/indyav/software/planning/indyav_path/path.rst b/docs/indyav/software/planning/indyav_path/path.rst
new file mode 100644
index 0000000..b75194f
--- /dev/null
+++ b/docs/indyav/software/planning/indyav_path/path.rst
@@ -0,0 +1,15 @@
+Path Package
+------------
+
+This is the package that has to do with all things path planning.
+
+
+To start the development of other systems, we are going to record a human driver's path and control for that path until we are confident in our non-path-planning systems.
+
+Programs
+^^^^^^^^
+.. toctree::
+ :maxdepth: 1
+
+ Path Recorder
+ Path Player
diff --git a/docs/indyav/software/planning/indyav_path/path_player.rst b/docs/indyav/software/planning/indyav_path/path_player.rst
new file mode 100644
index 0000000..3636cc7
--- /dev/null
+++ b/docs/indyav/software/planning/indyav_path/path_player.rst
@@ -0,0 +1,36 @@
+Path Player
+-----------
+
+This is a utility that we use to play back a path that we recorded from earlier, so that we can test systems not related to path planning.
+
+Path Player is just an instance of ``mil_tools TopicRecorder``. Its current behavior is that it will publish all messages in a bag file(our recorded path) in sequential order with correct timing between them. This utility is designed to be inherited from and the ``Play`` function overridden.
+
+Basic Usage Example
+^^^^^^^^^^^^^^^^^^^
+
+- Complete the `Path Recorder Basic Usage Example First `_.
+
+- Launch `SubjuGator <../../../../subjugator/index.html>`_ in gazebo and clear the kill.
+
+- In a new panel, play the previously recorded bag file.
+ ``roslaunch indyav_launch path_player.launch``
+
+- Visualize in Rviz by adding ``/path``.
+
+- Witness the new red arrow trace the path of SubjuGator from earlier.
+
+
+Source Files
+^^^^^^^^^^^^
+
+indyav_path PathPlayer:
+ source:
+ ``rosed indyav_path path_player.cpp``
+
+mil_tools TopicPlayer:
+ header:
+ ``rosed mil_tools topic_player.hpp``
+ source:
+ ``rosed mil_tools topic_player.cpp``
+launch file:
+ ``rosed indyav_launch path_player.launch``
diff --git a/docs/indyav/software/planning/indyav_path/path_recorder.rst b/docs/indyav/software/planning/indyav_path/path_recorder.rst
new file mode 100644
index 0000000..d1b5f1a
--- /dev/null
+++ b/docs/indyav/software/planning/indyav_path/path_recorder.rst
@@ -0,0 +1,53 @@
+Path Recorder
+-------------
+This is a Utility we use to save a human generated path in the global frame: ``/ecef``.
+
+Indyav Path Recorder inherits from the ``mil_tools TopicRecorder``. We override the CallBack function to record odometry messages at a fixed rate.
+
+Basic Usage Example
+^^^^^^^^^^^^^^^^^^^
+
+- Launch `SubjuGator <../../../../subjugator/index.html>`_ in gazebo, clear the kill, and bring up subviz.
+
+- In a new panel, launch the recorder on odom topic:
+ ``roslaunch indyav_launch path_recorder.launch record_topic:=/odom``
+
+ *NOTE: This will start to spew the warning :* ``path_recorder frame id is not in ECEF`` *. you can safely ignore this warning for this example.*
+
+- In a new panel, start recording:
+ ``service call /path/path_recorder/enable "data: true"``
+
+- In a new panel, command a move forward:
+ ``submove f 5``
+
+- Watch the sub move forward 5m in the rviz window
+
+- Stop recording in the same panel as you enabled (doesn't actually matter where this command is issued):
+ ``service call /path/path_recorder/enable "data: false"``
+
+- If you like, you can now kill the path recorder by going to the terminal where it was launch and pressing:
+ ``Ctrl + c``
+
+- Play back the recording as a normal rosbag on a different topic and visualize it:
+ ``rosbag play ~/test.bag /odom:=/odom2 -l``
+
+- Visualize this new topic in rviz by clicking `Add` and then `/odom2 -> Odometry`
+
+- Watch the red arrow advance from where the sub started to where the sub stopped updating approximately 10 times a second.
+
+Source Files
+^^^^^^^^^^^^
+indyav_path PathRecorder:
+ header:
+ ``rosed indyav_path path_recorder.hpp``
+ source:
+ ``rosed indyav_path path_recorder.cpp``
+
+mil_tools TopicRecorder:
+ header:
+ ``rosed mil_tools topic_recorder.hpp``
+ source:
+ ``rosed mil_tools topic_recorder.cpp``
+
+launch file:
+ ``rosed indyav_launch path_recorder.launch``
diff --git a/docs/indyav/software/planning/planning.rst b/docs/indyav/software/planning/planning.rst
new file mode 100644
index 0000000..ef2c137
--- /dev/null
+++ b/docs/indyav/software/planning/planning.rst
@@ -0,0 +1,15 @@
+Planning
+========
+
+This Directory has to do with all things robot planing. Currently, there is only path planning in here.
+
+
+Planning Packages
+-----------------
+.. toctree::
+ :maxdepth: 1
+
+ Path Package Documentation
+
+Discussion
+----------
diff --git a/docs/indyav/software/simulation/gazebo/gazebo.dot b/docs/indyav/software/simulation/gazebo/gazebo.dot
new file mode 100644
index 0000000..e0a3476
--- /dev/null
+++ b/docs/indyav/software/simulation/gazebo/gazebo.dot
@@ -0,0 +1,72 @@
+digraph indyav_gazebo
+{
+ ratio="compress";
+ graph[fontsize=25, dpi=400];
+ "BackWheelPlugin"->"indyav_car.urdf.xacro":w [label=" included by "];
+ "wheels.xacro"->"indyav_car.urdf.xacro":nw [label=" included by "];
+ "utils.xacro"->"indyav_car.urdf.xacro":n [label=" included by "];
+ "go_kart.xacro"->"indyav_car.urdf.xacro":ne [label=" included by "];
+ "sylphase.xacro"->"indyav_car.urdf.xacro":e [label=" included by "];
+ "indyav_car.urdf.xacro"->"indyav_car.urdf" [label=" interpreted into "];
+
+ "actuators.yaml"->"Controller manager" [label=" informs "]
+ "indyav_car.urdf"->"Controller manager" [label=" informs "]
+
+ "Robot Spawner";
+
+ "indyav_car.urdf" -> "Robot Spawner";
+
+
+
+
+ subgraph cluster_gazebo
+ {
+ compound=true;
+ style=outlined;
+ color=blue;
+ node [style=filled,color=white];
+ label = "Gazebo";
+ labeljust="l";
+ subgraph cluster_indyav_car
+ {
+ style=outlined;
+ color=blue;
+ node [style=filled,color=white];
+ label = "indyav_car"
+ labeljust="l";
+
+ back_wheel [label="BackWheelPlugin\n(Applies Thrust)"];
+ invis [style=invis, pos="0,0"];
+ sylphase_ins [label="sylphase_ins Plugin \n(give the gound truth odom)"];
+
+ right_wheel [label="right front wheel controller\n(controls the steering angle of the right \nfront wheel)"];
+ left_wheel[label="left front wheel controller\n(controls the steering angle of the left \nfront wheel)"];
+ }
+ }
+
+ "Robot Spawner"->invis[label="spawns"];
+
+ "Controller manager"->right_wheel
+ [label=" manages "];
+ "Controller manager"->left_wheel
+ [label=" manages "];
+
+ sylphase_ins->"/ins_odom"[label="Publishes"];
+ "/ins_odom"->"dumb_truth_tf"
+ [label="Subscribes"];
+
+ "dumb_truth_tf"->"Transform: enu <=> base_link"[label="Broadcasts"];
+
+ right_command [label="/car/simulated_hardware_controllers\n/steering/right/command", pos="-1,-1"];
+ right_command -> right_wheel [label="Subscribes"];
+ "simulated steering driver"-> right_command [label="Publishes"];
+
+
+ left_command [label="/car/simulated_hardware_controllers\n/steering/left/command"];
+ left_command -> left_wheel [label="Subscribes"];
+ "simulated steering driver"-> left_command [label="Publishes"];
+
+ "/steering"->"simulated steering driver"[label="Subscribes"];
+
+ "/throttle"->back_wheel[label="Subscribes"];
+}
diff --git a/docs/indyav/software/simulation/gazebo/gazebo.rst b/docs/indyav/software/simulation/gazebo/gazebo.rst
new file mode 100644
index 0000000..93eb0e8
--- /dev/null
+++ b/docs/indyav/software/simulation/gazebo/gazebo.rst
@@ -0,0 +1,61 @@
+IndyAV Gazebo Simulation
+========================
+
+
+How to Use
+----------
+
+Launch Gazebo for IndyAV
+************************
+``roslaunch indyav_launch gazebo.launch``
+
+Launch RVIZ for IndyAV
+**********************
+in a new panel
+``indyviz``
+(this represents what the robot knows)
+
+*NOTE: this will not if run in the docker container*
+
+Launch the gazebo client (visualizer and gui)
+*********************************************
+in a new panel
+``gazebogui``
+(this represents ground truth)
+
+*NOTE: this will not if run in the docker container*
+
+*NOTE: to kill the gazebo client after you are done, usually* ``Ctrl + \`` *isrequired*
+
+*NOTE:* ``gazebogui`` *is a custom alias we have setup to launch gazebo client with some parameters*
+
+Command a Steering angle
+************************
+in a new panel::
+
+ rostopic pub /steering indyav_control/SteeringStamped -r 10 '{header: {
+ seq: 0,
+ stamp: {
+ secs: 0,
+ nsecs: 0},
+ frame_id: ''},
+ steering_angle: 0.5}'
+
+Command throttle
+****************
+in a new panel::
+
+ rostopic pub /throttle indyav_control/RevsStamped -r 10 '{header: {
+ seq: 0,
+ stamp: {
+ secs: 0,
+ nsecs: 0},
+ frame_id: ''},
+ radians_per_second: 30.000}'
+
+and see the car drive in circles in both Rviz and gazebo client
+
+But How Does Any of This Work
+-----------------------------
+
+.. graphviz:: gazebo.dot
diff --git a/docs/indyav/software/simulation/gazebo/gazebo.svg b/docs/indyav/software/simulation/gazebo/gazebo.svg
new file mode 100644
index 0000000..bfc5111
--- /dev/null
+++ b/docs/indyav/software/simulation/gazebo/gazebo.svg
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+indyav_gazebo
+
+
+cluster_gazebo
+
+Gazebo
+
+
+cluster_indyav_car
+
+indyav_car
+
+
+
+BackWheelPlugin
+
+BackWheelPlugin
+
+
+
+indyav_car.urdf.xacro
+
+indyav_car.urdf.xacro
+
+
+
+BackWheelPlugin->indyav_car.urdf.xacro:w
+
+
+ included by
+
+
+
+indyav_car.urdf
+
+indyav_car.urdf
+
+
+
+indyav_car.urdf.xacro->indyav_car.urdf
+
+
+ interpreted into
+
+
+
+wheels.xacro
+
+wheels.xacro
+
+
+
+wheels.xacro->indyav_car.urdf.xacro:nw
+
+
+ included by
+
+
+
+utils.xacro
+
+utils.xacro
+
+
+
+utils.xacro->indyav_car.urdf.xacro:n
+
+
+ included by
+
+
+
+go_kart.xacro
+
+go_kart.xacro
+
+
+
+go_kart.xacro->indyav_car.urdf.xacro:ne
+
+
+ included by
+
+
+
+gazebo_ros_p3d
+
+gazebo_ros_p3d
+
+
+
+gazebo_ros_p3d->indyav_car.urdf.xacro:e
+
+
+ included by
+
+
+
+Controller manager
+
+Controller manager
+
+
+
+indyav_car.urdf->Controller manager
+
+
+ informs
+
+
+
+Robot Spawner
+
+Robot Spawner
+
+
+
+indyav_car.urdf->Robot Spawner
+
+
+
+
+
+actuators.yaml
+
+actuators.yaml
+
+
+
+actuators.yaml->Controller manager
+
+
+ informs
+
+
+
+right_wheel
+
+right front wheel controller
+(controls the steering angle of the right
+front wheel)
+
+
+
+Controller manager->right_wheel
+
+
+ manages
+
+
+
+left_wheel
+
+left front wheel controller
+(controls the steering angle of the left
+front wheel)
+
+
+
+Controller manager->left_wheel
+
+
+ manages
+
+
+
+
+Robot Spawner->invis
+
+
+spawns
+
+
+
+back_wheel
+
+BackWheelPlugin
+(Applies Thrust)
+
+
+
+p3d
+
+p3d Plugin
+(give the gound truth odom)
+
+
+
+/indyav_car/sensorsposition/ground_truth_odometry
+
+/indyav_car/sensorsposition/ground_truth_odometry
+
+
+
+p3d->/indyav_car/sensorsposition/ground_truth_odometry
+
+
+Publishes
+
+
+
+ground_truth_tf
+
+ground_truth_tf
+
+
+
+/indyav_car/sensorsposition/ground_truth_odometry->ground_truth_tf
+
+
+Subscribes
+
+
+
+Transform: map <=> base_link
+
+Transform: map <=> base_link
+
+
+
+ground_truth_tf->Transform: map <=> base_link
+
+
+Broadcasts
+
+
+
+right_command
+
+/car/simulated_hardware_controllers
+/steering/right/command
+
+
+
+right_command->right_wheel
+
+
+Subscribes
+
+
+
+simulated steering driver
+
+simulated steering driver
+
+
+
+simulated steering driver->right_command
+
+
+Publishes
+
+
+
+left_command
+
+/car/simulated_hardware_controllers
+/steering/left/command
+
+
+
+simulated steering driver->left_command
+
+
+Publishes
+
+
+
+left_command->left_wheel
+
+
+Subscribes
+
+
+
+/steering
+
+/steering
+
+
+
+/steering->simulated steering driver
+
+
+Subscribes
+
+
+
+/throttle
+
+/throttle
+
+
+
+/throttle->back_wheel
+
+
+Subscribes
+
+
+
diff --git a/docs/indyav/software/simulation/simulation.rst b/docs/indyav/software/simulation/simulation.rst
new file mode 100644
index 0000000..1ccc0ef
--- /dev/null
+++ b/docs/indyav/software/simulation/simulation.rst
@@ -0,0 +1,17 @@
+Simulation
+==========
+
+.. toctree::
+ :maxdepth: 1
+
+ IndyAV Gazebo
+
+
+Gazebo
+------
+We are using Gazebo with initial testing of algorithm until the official simulator becomes available.
+
+
+ANSYS VRXperience
+-----------------
+The official competition simulator has been stated to be [ANSYS VRXperience](https://www.ansys.com/products/systems/ansys-vrxperience). No other details have been given about the interface and hardware requirements.
diff --git a/docs/indyav/software/software.rst b/docs/indyav/software/software.rst
new file mode 100644
index 0000000..551be1f
--- /dev/null
+++ b/docs/indyav/software/software.rst
@@ -0,0 +1,19 @@
+Software
+========
+
+Middleware
+----------
+We are currently using ROS for its' ease of development. Which allows us to be
+able to prototype early algorithms. It is possible that this will change during
+the course of the competition as more real time requirements are encountered
+because of the speed of the vehicle.
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Elements of Autonomony
+
+ Control
+ Localization
+ Perception
+ Planning
+ Simulation
diff --git a/docs/infrastructure/ci.md b/docs/infrastructure/ci.md
new file mode 100644
index 0000000..de929fd
--- /dev/null
+++ b/docs/infrastructure/ci.md
@@ -0,0 +1,59 @@
+# Continuous Integration
+
+Continuous integration is a helpful software engineering practice completed in
+order to ensure code quality over a long period of time. Continuous integration
+ensures that multiple tests run on each commit, allowing you to see if your
+newly committed code may be causing problems. Code which "fails CI" (or doesn't
+pass one of the various tests) will not be merged into the master branch,
+because it causes problems.
+
+Currently, we use GitHub Actions as our CI provider. It provides quick check markers to
+show which specific tests failed for a given commit.
+
+## Architecture and Terminology
+:::{graphviz} ci_architecture.dot
+:::
+
+### Runner Environment
+
+Currently, our continuous integration is run in a Docker container on one of our
+computers, Shuttle. This container is given unlimited resources to the host
+machine in order to help jobs complete quickly.
+
+The Docker Compose file for this container is stored locally on Shuttle. To start
+up the Docker container, you will need to run `docker-compose up -d` inside
+`~/runners` (where the compose file is stored).
+
+### Runs, Jobs, Steps
+
+There are multiple pieces to the GitHub Actions CI. The largest piece is the run.
+This is the sum of all jobs in the run. Some runs may run more jobs than others.
+Currently, the CI job that's spun up on each commit runs around 15 jobs. Inside
+each job are multiple steps. Similar to a Dockerfile, each step specifies one
+action to do: setup Python, download the repo, and compile a package are all
+separate steps. Steps are shared between jobs.
+
+Each run is also associated with a graph showing the relationship between the
+jobs in the run. This is helpful to see what jobs other jobs depend on, as well
+as why a job might be failing.
+
+## Using CI
+
+Continuous integration aims to be functional and automatic, and fulfills this mission
+by automatically running when you push a new commit to any branch. However,
+sometimes you may want more control over the CI process.
+
+To view the output of a job more closely, click on the "Details" tab next to
+the status check of an action. You will then see each step of the job. You can
+view the logs of these steps to see what exactly the job executed.
+
+If you want to restart a job, click on the "Re-run all jobs" button. This will allow
+you to re-run the jobs. If the job is currently running (or stuck), you will likely
+need to cancel it before you will be allowed to re-run it.
+
+## Updating CI
+
+To update the CI process, you will need to change the GitHub Actions file, found
+in `~/.github/workflows`. Whenever you change the file and push your changes
+to the repo, you can head over to the "Actions" tab of the GitHub repo site
+to see how your new changes changed the CI process.
diff --git a/docs/infrastructure/ci_architecture.dot b/docs/infrastructure/ci_architecture.dot
new file mode 100644
index 0000000..4db7993
--- /dev/null
+++ b/docs/infrastructure/ci_architecture.dot
@@ -0,0 +1,127 @@
+digraph CIDiagram {
+ fontname="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif"
+ node [
+ shape=rounded
+ fontname="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif"
+ penwidth="2"
+ margin=0.25
+ ]
+ graph [
+ fontname="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif"
+ labeljust = l;
+ color = lightgrey;
+ ]
+ edge [
+ fontname="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif"
+ ]
+
+ subgraph blue_nodes {
+ node [
+ style="rounded,filled"
+ fillcolor="#aed6f5"
+ color="#349be8"
+ ]
+ b1 [label="Commit is pushed\n to any branch"]
+ b2 [label="Pull request is opened"]
+ }
+
+ subgraph green_nodes {
+ node [
+ style="rounded,filled"
+ fillcolor="#cce6bc"
+ color="#7fc256"
+ ]
+ green1 [label="Commit is marked\nas passing"];
+ green2 [label="Test passes"];
+ green3 [label="Docs preview\nis published"];
+ }
+
+ subgraph red_nodes {
+ node [
+ style="rounded,filled"
+ fillcolor="#f7bbba"
+ color="#ee5453"
+ ]
+ red1 [label = "Commit is marked as\nnon-passing"];
+ red2 [label = "Test fails"];
+ red3 [label = "Bot stops waiting\nand marks job as\nfailed"];
+ red4 [label = "Pull request is closed"];
+ }
+
+ subgraph gray_nodes {
+ node [
+ style="rounded,filled"
+ fillcolor="#d8dae3"
+ color="#666d80"
+ ]
+ gray1 [label = "Ensure that PR is\nopened by MIL members"];
+ gray2 [label = "Bot waits for CI\nto finish"];
+ gray3 [label = "Deploy docs to main\ndocumentation site"]
+ }
+
+ subgraph decision_nodes {
+ node [
+ shape=diamond
+ style="rounded,filled"
+ fillcolor="#f7f7f7"
+ color="#d6d6db"
+ penwidth="4"
+ margin=0.15
+ ]
+ d1 [label = "Job succeeded?"];
+ d2 [label = "pre-commit passes?"];
+ d3 [label = "CI passes?"];
+ d4 [label = "PR is opened\nby MIL member?"];
+ d5 [label = "Is master branch?"];
+ }
+
+ subgraph cluster_0 {
+ label = "GitHub Actions";
+ margin = 30;
+ node [
+ style="rounded,filled"
+ fillcolor="#d8dae3"
+ color="#666d80"
+ ]
+ g1 [label="Install dependencies"]
+ g2 [label="Build repository\nthrough catkin_make"]
+ g3 [label="Run catkin_make and\nensure tests pass"]
+ g4 [label = "Build documentation and\npublish as artifact"]
+ // g2 [label="pre-commit.ci"]
+ g1 -> g2 -> g3 -> g4;
+ }
+
+ subgraph cluster_1 {
+ // Labels
+ label = "pre-commit.ci";
+ margin = 30;
+
+ node [
+ style="rounded,filled"
+ fillcolor="#d8dae3"
+ color="#666d80"
+ ]
+
+ p1 [label = "Queue is loaded"];
+ p2 [label = "pre-commit hooks\nare evaluated"];
+ p1 -> p2;
+ }
+
+ b1 -> g1;
+ b2 -> p1;
+ b2 -> gray1;
+ b2 -> gray2;
+ g4 -> d1;
+ p2 -> d2;
+ gray1 -> d3;
+ d3 -> green3 [label = "Yes"];
+ d3 -> red3 [label = "No"];
+ gray2 -> d4;
+ d4 -> red4 [label = "No"];
+ d2 -> green2 [label = "Yes"];
+ d2 -> red2 [label = "No"];
+ d1 -> green1 [label = "Yes"];
+ green1 -> d5;
+ d5 -> gray3 [label = "Yes"];
+ d1 -> red1 [label = "No"];
+}
diff --git a/docs/infrastructure/file_server.md b/docs/infrastructure/file_server.md
new file mode 100644
index 0000000..5ae76a1
--- /dev/null
+++ b/docs/infrastructure/file_server.md
@@ -0,0 +1,24 @@
+# File Server
+MIL has a file server we use to store bag files, videos, etc.
+This fileserver is accessible from anywhere on the UF network.
+
+:::{warning}
+These docs have not been updated in a considerable amount of time. Please use
+caution when attempting to connect to the file server.
+:::
+
+## Mounting (Ubuntu)
+To connect, use
+
+ $ ./scripts/mount_fileserver
+
+The username will be the username of your MIL active directory account. Reach out in slack if you don't have one.
+The share is which file share you want. You can chose one of the following:
+
+* mil
+* navigator
+* subjugator
+
+To unmount all shares, run
+
+ $ ./scripts/umount_fileserver
diff --git a/docs/infrastructure/index.rst b/docs/infrastructure/index.rst
new file mode 100644
index 0000000..4dfba72
--- /dev/null
+++ b/docs/infrastructure/index.rst
@@ -0,0 +1,11 @@
+Infrastructure
+======================
+Various docs related to infrastructure systems in MIL such as servers and networking.
+
+.. toctree::
+ Networking
+ Network Box
+ Continuous Integration
+ File Server
+ Solar Park
+ shipping
diff --git a/docs/infrastructure/network.rst b/docs/infrastructure/network.rst
new file mode 100644
index 0000000..3f7b011
--- /dev/null
+++ b/docs/infrastructure/network.rst
@@ -0,0 +1,171 @@
+MIL Network
+###########
+
+MIL uses a standardized network infrastruction that is available
+in MIL's rooms and is duplicated for field testing by the :doc:`network box`.
+
+LAN
+***
+The MIL Lan uses subnet ``192.168.37.0`` with mask ``255.255.255.0``. In other words,
+all local devices on MIL's network will have an ipv4 address in the form ``192.168.37.x``.
+
+Allocation Table
+================
+
+The following is a list of expected static IP addresses on MIL networks:
+
++------------------------+--------------------------+
+| IP | Name |
++========================+==========================+
+| **Network Infrastructure (19)** |
++------------------------+--------------------------+
+| 192.168.37.1 | Router |
++------------------------+--------------------------+
+| 192.168.37.19 | |
++------------------------+--------------------------+
+| **Physical Servers (9)** |
++------------------------+--------------------------+
+| 192.168.37.20 | esxi-1 |
++------------------------+--------------------------+
+| 192.168.37.21 | idrac-esxi-1 |
++------------------------+--------------------------+
+| 192.168.37.29 | |
++------------------------+--------------------------+
+| **Virtualized Servers (19)** |
++------------------------+--------------------------+
+| 192.168.37.30 | balin |
++------------------------+--------------------------+
+| 192.168.37.31 | dc-1 |
++------------------------+--------------------------+
+| 192.168.37.32 | dc-2 |
++------------------------+--------------------------+
+| 192.168.37.33 | fs-1 |
++------------------------+--------------------------+
+| 192.168.37.34 | web |
++------------------------+--------------------------+
+| 192.168.37.35 | pwd |
++------------------------+--------------------------+
+| 192.168.37.36 | |
++------------------------+--------------------------+
+| 192.168.37.37 | acs |
++------------------------+--------------------------+
+| 192.168.37.38 | pdm |
++------------------------+--------------------------+
+| 192.168.37.39 | av |
++------------------------+--------------------------+
+| 192.168.37.40 | svn |
++------------------------+--------------------------+
+| 192.168.37.41 | |
++------------------------+--------------------------+
+| 192.168.37.42 | app-1 |
++------------------------+--------------------------+
+| 192.168.37.49 | |
++------------------------+--------------------------+
+| **MIL Common (9)** |
++------------------------+--------------------------+
+| 192.168.37.50 | com-gateway |
++------------------------+--------------------------+
+| 192.168.37.51 | com-velodyne-vlp16 |
++------------------------+--------------------------+
+| 192.168.37.52 | com-sick-lms111 |
++------------------------+--------------------------+
+| 192.168.37.53 | com-teledyne-p900 |
++------------------------+--------------------------+
+| 192.168.37.59 | |
++------------------------+--------------------------+
+| **SubjuGator (9)** |
++------------------------+--------------------------+
+| 192.168.37.60 | sub8 |
++------------------------+--------------------------+
+| 192.168.37.61 | navtube (RPi) |
++------------------------+--------------------------+
+| 192.168.37.62 | downcam |
++------------------------+--------------------------+
+| 192.168.37.63 | ipmi |
++------------------------+--------------------------+
+| 192.168.37.69 | |
++------------------------+--------------------------+
+| **Reserved (9)** |
++------------------------+--------------------------+
+| 192.168.37.70 | |
++------------------------+--------------------------+
+| 192.168.37.79 | |
++------------------------+--------------------------+
+| **NaviGator (9)** |
++------------------------+--------------------------+
+| 192.168.37.80 | nav-ubnt-shore |
++------------------------+--------------------------+
+| 192.168.37.81 | nav-ubnt-wamv |
++------------------------+--------------------------+
+| 192.168.37.82 | nav-wamv |
++------------------------+--------------------------+
+| 192.168.37.89 | |
++------------------------+--------------------------+
+| **Reserved (9)** |
++------------------------+--------------------------+
+| 192.168.37.90 | |
++------------------------+--------------------------+
+| 192.168.37.95 | waterlinked (sub8 DVL) |
++------------------------+--------------------------+
+| 192.168.37.99 | |
++------------------------+--------------------------+
+| **Reserved Clients (19)** |
++------------------------+--------------------------+
+| 192.168.37.100 | cad-1 |
++------------------------+--------------------------+
+| 192.168.37.101 | cad-2 |
++------------------------+--------------------------+
+| 192.168.37.102 | shuttle |
++------------------------+--------------------------+
+| 192.168.37.103 | johnny-five |
++------------------------+--------------------------+
+| 192.168.37.119 | |
++------------------------+--------------------------+
+| **Assigned Clients (29)** |
++------------------------+--------------------------+
+| 192.168.37.120 | WLC0002 |
++------------------------+--------------------------+
+| 192.168.37.121 | daniel |
++------------------------+--------------------------+
+| 192.168.37.125 | keith |
++------------------------+--------------------------+
+| 192.168.37.137 | cbrxyz (cameron) |
++------------------------+--------------------------+
+| 192.168.37.140 | |
++------------------------+--------------------------+
+| **DHCP Pool (99)** |
++------------------------+--------------------------+
+| 192.168.37.150 | DHCP Pool Start |
++------------------------+--------------------------+
+| 192.168.37.249 | DHCP Pool End |
++------------------------+--------------------------+
+| **Reserved (4)** |
++------------------------+--------------------------+
+| 192.168.37.250 | |
++------------------------+--------------------------+
+| 192.168.37.253 | |
++------------------------+--------------------------+
+| 192.168.37.254 | new pfsense vm |
++------------------------+--------------------------+
+
+DHCP
+****
+The MIL network has a DHCP server which will assign a local IP to connected
+devices automatically. Some important devices, such as servers and vehicles, have
+a static IP address. Other devices are given the next unused IP from the pool
+within ``192.168.37.150`` to ``192.168.37.249``.
+
+Connect to Robot / other ROS networks
+*************************************
+ROS can be configured to talk only on your local machine, or allow communication
+from your machine to another, such as one of our robots or a simulation server.
+
+This is done using `ROS environment variables `_.
+
+Assuming you have followed the :doc:`Getting Started Guide `,
+you can use the function ``ros_connect`` to set this up.
+
+Run ``ros_connect -h`` for an up to date list of options.
+For example, run ``ros_connect sub`` to setup this terminal (and children terminals,
+such as a ``tmux`` session) to allow your ros nodes, such as ``rviz``, to talk to
+the ros nodes on SubjuGator.
diff --git a/docs/infrastructure/network_box.jpg b/docs/infrastructure/network_box.jpg
new file mode 100644
index 0000000..500819f
Binary files /dev/null and b/docs/infrastructure/network_box.jpg differ
diff --git a/docs/infrastructure/network_box.rst b/docs/infrastructure/network_box.rst
new file mode 100644
index 0000000..84c6530
--- /dev/null
+++ b/docs/infrastructure/network_box.rst
@@ -0,0 +1,89 @@
+Network Box
+===========
+
+.. figure:: network_box.jpg
+ :alt: An image of the network box with one ethernet connection.
+
+The Network Box is a pelican case containing the components needed to
+duplicate the network while out testing or at competition. It is
+intended to make networking in these environments seamless and portable.
+The box is powered by a UPS so can operate for roughly an hour without
+being plugged into a wall outlet.
+
+Usage
+-----
+
+To use the Network Box:
+
+- If possible, plug the box into wall power using the special cable.
+- Turn the box on by holding down the ON button until you hear a beep and the
+ RED led turns on.
+- Connect your/other developer laptops via ethernet to any of the top ports BESIDES
+ the one labeled POE.
+
+ - Be sure your laptop is configured to automatically configure network over DHCP.
+ - If your laptop does not have Ethernet (RJ45), you can use one of the provided
+ adapters inside the box.
+
+- Connect the vehicle to the box. If connecting the Ubiquitii Antenna, connect
+ it to the POE port.
+- Wait a few minutes until your computer reports it is connected to the network.
+- To verify functionality, try pinging the vehicle or accessing the config panel.
+
+IO
+--------
+- 7 LAN connections on the outside of the box connected to the internal
+ switch
+
+ - 1 labeled POE and is connected to a Ubiquity POE injector used to
+ connect the Ubuiquity antenna
+
+- 1 WAN ethernet which connects directly to the PFsense router WAN port
+- A power cable
+- Internal WIFI antena
+- Labeled On/Off button (must hold)
+- Red power indicator LED
+
+Internal
+--------
+- `TREDnet TI-G80 8-port gigabit switch `_
+- `Xtreme J60-OE350 AC UPS `_
+- `Protectli FW10408 PFsense router `_
+- AC to 12v 5A DC adapter spliced to power both the switch and router
+- Ubiquiti GP-A240-050G POE injector
+- 2 Amazon Basics USB to RJ45 devices velcrowed to the lid for
+ developers without a RJ45 port
+
+Configuring
+-----------
+
+.. warning::
+
+ Bad changes to the network box config can break communication between developers
+ and robots. Proceed with caution.
+
+You can configure things such as the WAN (internet) connection, DHCP server, etc by
+logging into the PFsense web panel at https://192.168.37.1 (accept the invalid
+certificate). Ask a MIL leader for the login credentials.
+
+Backup / Restore
+----------------
+We store the XML config of the router within the repo.
+You can update this config or restore it from the web panel at
+https://192.168.37.1/diag_backup.php.
+
+You can download the pfSense config XML file by clicking :download:`here <../../infra/network-box/pfsense_config.xml>`.
+
+WAN Setup
+~~~~~~~~~
+
+.. warning::
+
+ Do not connect the MIL network or any other network using our subnet to the
+ WAN port. This can cause serious issues for both networks as both will have
+ an active DHCP server.
+
+At competition, we are often given a WAN (internet) cable. Plug this cable into
+the WAN port on the box. Once connected, try pinging an internet server with
+
+ $ ping 8.8.8.8
diff --git a/docs/infrastructure/shipping.md b/docs/infrastructure/shipping.md
new file mode 100644
index 0000000..d0636bf
--- /dev/null
+++ b/docs/infrastructure/shipping.md
@@ -0,0 +1,43 @@
+# Shipping
+
+Eventually, our robots are going to need to be shipped to the competition locations.
+To do this, we ship them, as they're way too big to carry on a plane!
+
+## Packing List
+
+The first step of shipping is making a packing list. This list includes everything
+that we need to pack - missing even one item is annoying and costly, so having
+an absolute list is helpful. We already have packing lists for both robots, but
+these can be added to and removed from as needed.
+
+As you pack, reference the list and check off items as you go so you don't wonder
+why you can't find an item. The packing list will also be referenced when you
+pack up at the competition site after the competition is over; it helps to ensure
+you didn't miss anything accidentally.
+
+## Shipping the Robot
+
+To ship the robot, you will need to use a freight shipper, as the robot's box
+is massive and heavy. Freight shipping is meant for items like this. Multiple
+carriers offer freight shipping in the United States, but the university has some
+deals with some of the carriers. Check with Dr. Schwartz about this.
+
+## Shipping Materials
+
+To ship materials, you can use ground shipping. We have multiple Pelican cases
+for shipping materials, each of which is shipped separately.
+
+## Batteries
+
+One problematic item in shipping is a case of batteries. Due to their lithium
+ion base, many shipping carriers won't take batteries without special precautions.
+You will need to review these in order to ship them through standard shipping.
+For some locations, it may be easier to buy batteries at the competition site
+rather than to take batteries with you.
+
+## Note
+
+Whenever a package is received in MIL, an email needs to be sent to Dr. Schwartz.
+The email should contain the sender's name of the package, and a picture of the
+packing receipt, if one is included. This should be done by the lab member who
+opens up the package.
diff --git a/docs/infrastructure/solar_park.md b/docs/infrastructure/solar_park.md
new file mode 100644
index 0000000..32bafb0
--- /dev/null
+++ b/docs/infrastructure/solar_park.md
@@ -0,0 +1,7 @@
+# Solar Park
+
+Solar Park is a UF-associated storage site where we store our pelican cases and
+the shipping box for the [WAM-V](../navigator/index).
+
+To get access to the Solar Park facility, please talk to a leader. It's common
+for materials to be moved to and from the facility.
diff --git a/docs/mechanical/index.rst b/docs/mechanical/index.rst
new file mode 100644
index 0000000..b08ab2a
--- /dev/null
+++ b/docs/mechanical/index.rst
@@ -0,0 +1,13 @@
+Mechanical
+=====================
+Welcome to documentation regarding the mechanical team of MIL! Our team is responsible
+for the construction and maintenance of the mechanical structures of the submarine.
+
+To get started, checkout the onboarding page!
+
+.. toctree::
+ :maxdepth: 1
+
+ Onboarding
+ Resources
+ Maintenance
diff --git a/docs/mechanical/maintenance.md b/docs/mechanical/maintenance.md
new file mode 100644
index 0000000..63561c6
--- /dev/null
+++ b/docs/mechanical/maintenance.md
@@ -0,0 +1,12 @@
+# Maintenance
+
+## CNC
+- After each use of the machine, be sure to clean the dust on the platform and drive unit. Use compressed air to blow dust out of the control box (Do not use brushes or any other tools which could produce electrostatic electricity), check the screws of the wire plugs to ensure an optimal contact.
+
+- The rails need to be lubed weekly (hg50 linear bearings but not 100% sure). It may even have provisions for internal lube but either way this should be conducted to preserve the life of the rails.If machine is not used often, lubing frequency can be decreased.
+
+- The coolant needs to be either a legit spindle coolant or antifreeze mixture to kill bacteria. This will do two things at least: preserve the life of the spindle with better cooling properties and also decrease the buildup inside. If water is used for coolant, it can get slimy. As a quick alternative distilled water can be used. Watch out for blocked sediment in the tubes.
+
+- Keep plenty of isopropyl on hand for aluminum coolant.
+
+- The lead screw/ballscrews need some lube from time to time. White lithium spray is good as far as our knowledge goes but more research needs to be done to find the best method
diff --git a/docs/mechanical/onboarding.md b/docs/mechanical/onboarding.md
new file mode 100644
index 0000000..ab3f703
--- /dev/null
+++ b/docs/mechanical/onboarding.md
@@ -0,0 +1,55 @@
+# Mechanical Onboarding
+
+Welcome to MIL - we're excited to hear that you'd like to join the mechanical team!
+The mechanical team is responsible for the design and construction of several
+components of the robots. As a mechanical member, you will be engaging with CAD
+files mostly.
+
+:::{note}
+If you have not visited with the [welcome page](/welcome.md) and would like a
+more general overview of MIL, please check that page first!
+:::
+
+## Join the mechanical channel
+Like the other teams, we use Slack as our primary communication platform. Our
+Slack workspace can be found at [https://uf-mil.slack.com](https://uf-mil.slack.com/).
+Ask someone in MIL to invite you or email [andrespulido@ufl.edu](mailto:andrespulido@ufl.edu).
+
+Once you’re on Slack, be sure to join the [#mechanical](https://uf-mil.slack.com/messages/C6UQUU78Q)
+channel. This is where we will post important updates about the mechanical team,
+including meeting times.
+
+## Join our Github
+We keep track of our tasks through GitHub issues. In order to contribute to tasks,
+you need to create an account in **GitHub** and then email [andrespulido@ufl.edu](mailto:andrespulido@ufl.edu)
+for access to the MIL GitHub organization. Alternatively, you can ask a MIL leader
+you know to add you to the organization.
+
+You can find the list of issues [here](https://github.com/uf-mil/mil/issues).
+You will notice that there are other issues for the software and electrical teams,
+which isn't super helpful for you (unless you want to help out those teams as well!).
+To filter for Mechanical tasks, click the `Label` dropdown, and choose the
+`mechanical` label.
+
+When you are first getting started, you may also want to find a task that is good
+for new members. To do this, also select for the `good first issue` using the `Label`
+dropdown, like you did to choose the `mechanical` label.
+
+When you find a task, make sure to make yourself assigned to it. You can do this
+in the GitHub UI: click on a task, and on the righthand sidebar, click `Assignees`
+and find your username. This will let the other mechanical members and leaders know
+that you are working on that task.
+
+## Join our GrabCAD
+You should also ask a leader about joining the mechanical GrabCAD, which is where
+we store all of our CAD files.
+
+## Start to get familiar with our technical projects
+Below are some of our current projects:
+* Subjugator 8
+* Subjugator 9 (WIP)
+* NaviGator
+* [Drone](/navigator/drone.md)
+
+For good mechanical resources, check out the [Resources](/mechanical/resources.md)
+ page.
diff --git a/docs/mechanical/resources.md b/docs/mechanical/resources.md
new file mode 100644
index 0000000..ff65b60
--- /dev/null
+++ b/docs/mechanical/resources.md
@@ -0,0 +1,11 @@
+# Resources
+
+Here is a list of the resources we recommend to getting started designing killer autonomous submarines and boats:
+
+- **CAD**: Computer Aided Manufacturing is the software where we create 3D models of parts and assemblies. Here is the [webpage of Prof. Crane](http://www.ccrane3.com/eml2023/pages/videos.html), one of our advisors, where he teaches Solidworks, the CAD software we use. If you need help installing Solidworks talk to any mechanical member in the lab.
+- **Design Resources**: The [Design and Manufacturing Lab (DML) website](https://mae.ufl.edu/designlab/) has a ton of resources. Feel free to navigate through the website and learn anything you find interesting. Recommended read in the website:
+ -Design for Manufacturability, specifically DFM examples
+ -The course video, to learn the common manufacturing process available in UF
+ -Facility Safe NOTE: a senior member of the lab **must** be present if you want to use machinery
+ -Solidwork & Lab resources
+- **CNC**: Watch these two videos made by Daniel Prestridge, ex-CIMAR, about [CNC Setup](https://youtu.be/fhrf0OuGvbQ) and [extra info](https://youtu.be/9tTzEAX3MPo)
diff --git a/docs/navigator/drone.md b/docs/navigator/drone.md
new file mode 100644
index 0000000..1fd6213
--- /dev/null
+++ b/docs/navigator/drone.md
@@ -0,0 +1,12 @@
+# Drone Project
+
+## Comments by Sean (Founder of Aerotestra)
+
+- He can provide help with the OS systems and the current state of the vehicle. Confirm that whatever is inside is updated, autopilot can be controlled through a telemetry interface. Drone uses the ardupilot, which Jarrod Sanders has volunteered to become familiar with and keep communicating with Sean.
+- There is no specific documentation for our vehicle because it is a customized vehicle. But he will send us the user manual.
+- Sean will send us an [ardupilot replacement](https://ardupilot.org/) he has laying around.
+- He mentioned that the [AR2.5](https://ardupilot.org/copter/docs/common-apm25-and-26-overview.html) ardupilot is a bit outdated and he recommends Pixhawk but we might get away with it if it's working properly. He mentioned that there could be corrosion problems, expanded Teflon since it is semipermeable could be used in the enclosure to reduce exposure to water.
+- He recommended to also check the bearings in the motor to check for corrosion and resistance when turning. If there is, consider replacing the motors.
+- He will send us a telemetry unit, and the ground unit. Also, he will send a selection bag with rubber gaskets for the GPS enclosure.
+- Next steps are to get [Mission Planner](https://ardupilot.org/planner/) on a laptop and interface with the vehicle. Then research how to interface with ROS.
+- He also recommended and , for landing.
diff --git a/docs/navigator/index.rst b/docs/navigator/index.rst
new file mode 100644
index 0000000..1ec2053
--- /dev/null
+++ b/docs/navigator/index.rst
@@ -0,0 +1,52 @@
+NaviGator
+=========
+Welcome to documentation regarding the NaviGator autonomous vehicle at MIL. The following
+documentation is not restricted to any particular team, and instead is simply connected
+by the relationship to this specific robot.
+
+Current Projects
+----------------
+We have documentation on projects which are current. Many of the following systems
+are being created in preparation for the November 2022 competition in Sydney, Australia.
+
+.. toctree::
+ :maxdepth: 1
+
+ Drone
+ lidar
+
+Procedures
+----------
+Procedures related to operation of the NaviGator AMS.
+
+.. toctree::
+ :maxdepth: 2
+
+ Testing Day Checklist
+ networking
+
+Software
+--------
+
+.. toctree::
+ :maxdepth: 2
+
+ simulating.md
+
+Lessons Learned + Reflections
+-----------------------------
+Lessons we've learned throughout the process that are helpful for future projects.
+
+.. toctree::
+ :maxdepth: 2
+
+ lessons22
+
+Past Projects
+-------------
+We also have documentation on projects which we competed in in the past.
+
+.. toctree::
+ :maxdepth: 1
+
+ VRX (April 2022)
diff --git a/docs/navigator/lessons22.md b/docs/navigator/lessons22.md
new file mode 100644
index 0000000..2560754
--- /dev/null
+++ b/docs/navigator/lessons22.md
@@ -0,0 +1,127 @@
+# Lessons from RobotX 2022
+
+
+
+Throughout the entire process leading up to and during RobotX 2022, Team
+NaviGator had fun, was able to accomplish a lot, and met a lot of great new
+friends. The learned a lot along the way and wanted to record these points for
+future teams to learn from!
+
+## Overall Improvements
+
+* **Each and every system should be _finished_ at least one month before the
+ competition.** - At RobotX 2022, our kill system was not completed before the
+ team left for the competition in Australia. Unfortunately, this prevented the
+ team from being able to run NaviGator in the water, as a kill system is
+ required for the competition. At least one leader should ensure that every
+ system is completed at least one month before the competition. This does not
+ necessarily require the system to be _perfect_, only ready to go.
+* **Mechanical, electrical, and software should meet throughout the design
+ process.** - While each team got together at the start of the semester to
+ discuss the design plan for NaviGator, this meeting was not enough to sustain
+ good progress throughout the semester. Each of the teams sometimes became
+ confused about what the other teams needed, and overall, the teams lost sync
+ with each other. By having regular meetings, teams can make sure that they
+ are working towards the same goal.
+* **We should have more design reviews from mentors.** - Mentors are an important
+ part of the design process. Mentors can catch design flaws in systems quicker
+ than students can, and can show students how to improve their designs. These
+ design reviews do not need to be super frequent, but could maybe occur when a
+ new system is being designed.
+
+## Shipping Improvements
+
+* **We should bring more materials over air rather than shipping them.** - If
+ cost allows, we should aim to bring more materials ourselves by plane rather
+ than shipping. Shipping can be a hastle and is subject to more delays than
+ bringing carry-ons or checking luggage. Furthermore, bringing less by
+ shipping can shorten our shipping manifest, making the entire shipping
+ process easier. One note about checking equipment is that it is likely to get
+ tossed around a significant amount during travel. Therefore, we will need to
+ pack materials cautiously, with the idea that the materials will be damaged
+ during shipping.
+* **Materials should be packed with failure in mind.** - At RobotX 2022, we
+ found out that one of our critical sensors, our LIDAR, broke. During
+ shipping, it had only been packed in a layer of bubble wrap and placed into a
+ Pelican case. This type of shipment is likely not safe for the LIDAR;
+ instead, it should have been placed in a custom shipping case. By asking
+ ourselves, "How could this item get destroyed in shipping?", we could
+ possibly prevent some breakage from occurring.
+* **Packing/parts lists need to be made for each Pelican case taken.** - No
+ packing lists were made for any of the Pelicans shipped to the competition
+ site. This presented a challenge, as we weren't sure what was in each Pelican
+ case, and whether we had brought all that we needed to bring. Before we left
+ for the competition (after the Pelicans had shipped), we wondered, "Did we
+ bring [network box](/infrastructure/network_box.rst)?", but because no
+ packing lists were available, we had no idea.
+
+## Mechanical Improvements
+
+* **Use an organizer for tools.** - Having cases/methods for keeping tools
+ organized helps keep everyone's sanity at bay, and makes finding tools quick.
+ It is quicker to tell when tools have gone missing (as each tool now has a
+ dedicated spot in the organizer), and which tool is missing. Furthermore, it
+ becomes easier for software members, electrical members, and mentors to find
+ tools, even if they maybe are not acquainted with a deep knowledge of the
+ mechanical team.
+* **Focus on bringing less and staying more organized.** - At RobotX 2022, we
+ were one of the teams who had brought the most equipment, yet we had a hard
+ time finding much of it. Building off of the point above, we should aim to be
+ more organized with what we bring, so that we are able to bring less. When
+ tools are compactly organized into a container and each tool has a distinct
+ purpose for the robot, there is less of a need to bring several sets of
+ miscellaneous tools. Instead, we focus on bringing what we surely need to ace
+ the competition.
+* **We should have a fully updated CAD model.** - Having a fully updated CAD
+ model can help us identify the position of each distinct part of NaviGator.
+ This is helpful for assembly, identifying what tools are needed for the
+ competition, and packing.
+* **Consider buying individual toolboxes for mechanical leaders.** - Mechanical
+ leaders often have to complete many quick tasks when assembling,
+ disassembling, and fixing NaviGator. It would help the leaders complete their
+ tasks quicker if they were able to have a set of tools ready on hand. With
+ this toolset, they would not need to share tools as often or return to the
+ pelicans/organizers to refill/return their tools. However, it was stressed
+ that if this is implemented, the tools should be of high quality.
+
+## Electrical Improvements
+
+* **Team members should be more readily taught the electrical systems behind
+ NaviGator.** - One issue for new electrical members is that they do not learn
+ about the electrical system currently implemented on NaviGator. While
+ electrical tutorials cover the basics of Altium and designing a circuit and
+ PCB, the tutorials do not cover the electrical system in place on NaviGator.
+ This can be a barrier to having new electrical members contribute to the
+ electrical system on NaviGator.
+* **The onboarding process should be improved.** - Currently, the onboarding
+ process is alright, but it could be improved. Currently, it's lengthy,
+ written in PDFs stored in a random GitHub repository, and it contains outdated
+ information. Rather, this could be updated to be more interactive or helpful
+ to the reader (by way of YouTube videos, websites, or more streamlined PDFs).
+ Furthermore, many electrical members drop out of MIL during the electrical
+ onboarding process, suggesting that they may be frustrated with how the
+ process is currently done.
+
+## Software Improvements
+
+* **The goal should be to branch off of `master` as soon as possible.** - When
+ preparing for RobotX 2022, we had several branches for testing new features.
+ Some of the branches had branched off of other branches, which branched off
+ of other branches, etc. By the end, many of the branches had diverged
+ significantly from `master` and other members could not find which branch was
+ actually being used. By encouraging a quick merge back into `master`, we can
+ ship features more quickly, make development more transparent and accessible,
+ and reduce the number of random branches.
+* **More redundancy and quality should be added into solutions.** - While the
+ software team was able to complete many of the high-level missions, these
+ missions often took shortcuts or skimped on quality. No integration tests
+ were added for many of the missions, and very few of them had their approach
+ documented for other members to review. We should ask ourselves, "How might
+ this implementation become broken?", and then continually improve our code
+ from there.
+* **We need to understand how older packages function.** - Many of core
+ NaviGator's libraries and systems could not be understand by any of the
+ software members who attended RobotX 2022. This presents a challenge, because
+ as soon as these implementations break, no one knows what could be wrong
+ without a lengthy debugging session. Rather, we nede to be able to intensely
+ understand the math, logic, and code behind what core packages implement.
diff --git a/docs/navigator/lidar.md b/docs/navigator/lidar.md
new file mode 100644
index 0000000..6c8eb26
--- /dev/null
+++ b/docs/navigator/lidar.md
@@ -0,0 +1,17 @@
+# LIDAR
+
+One necessary instrument on NaviGator is its LIDAR system. This system is able
+to generate a 3D PointCloud of the surrounding area.
+
+## Simulation
+
+Because the instrument is necessary for the boat to move, the component also
+must be simulated in the Gazebo environment. This is done with the help of a few
+tools.
+
+The Virtual RobotX competition, pioneered by the Open Source Robotics Foundation,
+launched with a set of tools for simulating boats on water. One of these tools
+uses [another Gazebo plugin](https://bitbucket.org/DataspeedInc/velodyne_simulator/)
+in order to create a simulated Velodyne LIDAR component. The VRX competition
+tools provide a helpful model and component architecture, while the plugin
+provides the functionality to generate the actual LIDAR beams.
diff --git a/docs/navigator/networking.dot b/docs/navigator/networking.dot
new file mode 100644
index 0000000..91ff609
--- /dev/null
+++ b/docs/navigator/networking.dot
@@ -0,0 +1,35 @@
+digraph G {
+ rankdir=LR
+
+ subgraph cluster_0 {
+ style=filled;
+ color=lightgrey;
+ node [style=filled,color=white];
+ a0 [label = "User X"];
+ a1 [label = "User 2"];
+ a2 [label = "User 1"];
+ aa [label = "Network Box"]
+ au [label = "Rocket AC Base Station"]
+ an [label = "Rocket AC Antenna"]
+ label = "shore";
+ }
+
+ subgraph cluster_1 {
+ style=filled;
+ color=lightgrey;
+ node [style=filled,color=white];
+ n0 [label = "Rocket AC Access Point"]
+ n1 [label = "Computer"]
+ label = "navigator";
+ }
+
+ a0 -> aa [style="dashed", label = "Ethernet", dir=both]
+ a1 -> aa [dir=both]
+ a2 -> aa [dir=both]
+ aa -> au [dir=both, label = "POE"]
+ au -> an [dir=both, label = "Physical Connection"]
+
+ n0 -> n1 [label = "Ethernet", dir=both]
+
+ an -> n0 [dir = both, label = "5GHz Band"]
+}
diff --git a/docs/navigator/networking.md b/docs/navigator/networking.md
new file mode 100644
index 0000000..0f0c16c
--- /dev/null
+++ b/docs/navigator/networking.md
@@ -0,0 +1,50 @@
+# Networking with Navigator
+
+Connecting to NaviGator is typically done by connecting a base station on the shore
+to an access point on the boat. Furthermore, the network box is used by end users
+to connect to the base station on the shore. This setup allows us to have a reliable
+connection to NaviGator without needing to extend a _very_ long Ethernet cable to
+NaviGator.
+
+## Architecture
+:::{graphviz} networking.dot
+:::
+
+## Network Box
+
+The network box comes with a suite of open ports: some for networking, others for
+power. The back of NaviGator has ports for receiving power, while the top of
+NaviGator has Ethernet ports for transmitting data to clients over Ethernet. One
+of these switches is labelled POE (the middle connector in the top row, near the
+red light). This connector should only be used for POE connections, usually to
+power the base station over Ethernet.
+
+Inside the network box, you'll find tools for handling power and connectivity. Notably,
+a gigabit switch, POE injector, and power supply. These should rarely be touched.
+Usually, configuration is best managed through the HTML network UIs, which are
+accessible from special IPs.
+
+:::{warning}
+Triggering the reset pin on the POE injector will reset the Rocket AC base station
+configuration, likely disrupting your network connection. Before pressing this pin,
+ensure that you have a backup of the device configuration.
+:::
+
+## Rocket AC Base Station and Antenna
+
+A critical component of the network infrastructure is the Rocket AC base station
+and connected antenna. This large standing device is connected to the network
+box through POE.
+
+The device should be aimed towards the boat to receive the best connection, although
+this does not need to be a perfectly straight line.
+
+To configure the Rocket AC device after a reset, you can use a web UI known as airOS, provided
+by the device. To connect, set your own IP to `192.168.1.XXX`, where `XXX` is some
+number that is not 20. Then, connect to the device through `192.168.1.20`. This
+also works for the Rocket AC access point located on the boat.
+
+To access the airOS interface of the Rocket AC device after having setup the device,
+visit the IP address of the device (commonly `192.168.37.80` for the Rocket AC on
+shore and `192.168.37.81` for the Rocket AC on NaviGator) in your browser. The
+credentials for the device are physically located near the device.
diff --git a/docs/navigator/reference.rst b/docs/navigator/reference.rst
new file mode 100644
index 0000000..7a21dbe
--- /dev/null
+++ b/docs/navigator/reference.rst
@@ -0,0 +1,475 @@
+NaviGator Software Reference
+============================
+
+Below is the software reference for Navigator-specific systems.
+
+Services
+--------
+MessageDetectDock
+^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_msgs.srv.MessageDetectDockRequest
+
+.. class:: navigator_msgs.srv.MessageDetectDockRequest
+
+ The request class for the ``navigator_msgs/MessageDetectDock`` service.
+
+ .. attribute:: color
+
+ The color of the shape.
+
+ :type: str
+
+ .. attribute:: ams_status
+
+ The AMS status.
+
+ :type: int
+
+.. attributetable:: navigator_msgs.srv.MessageDetectDockResponse
+
+.. class:: navigator_msgs.srv.MessageDetectDockResponse
+
+ The response class for the ``navigator_msgs/MessageDetectDock`` service.
+
+ .. attribute:: message
+
+ A message in response to the process.
+
+ :type: str
+
+MessageEntranceExitGate
+^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_msgs.srv.MessageEntranceExitGateRequest
+
+.. class:: navigator_msgs.srv.MessageEntranceExitGateRequest
+
+ The request class for the ``navigator_msgs/MessageEntranceExitGate`` service.
+
+ .. attribute:: entrance_gate
+
+ The entrance gate relevant to the task.
+
+ :type: int
+
+ .. attribute:: exit_gate
+
+ The exit gate relevant to the task.
+
+ :type: int
+
+.. attributetable:: navigator_msgs.srv.MessageEntranceExitGateResponse
+
+.. class:: navigator_msgs.srv.MessageEntranceExitGateResponse
+
+ The response class for the ``navigator_msgs/MessageEntranceExitGate`` service.
+
+ .. attribute:: message
+
+ A message in response to the process.
+
+ :type: str
+
+MessageFindFling
+^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_msgs.srv.MessageFindFlingRequest
+
+.. class:: navigator_msgs.srv.MessageFindFlingRequest
+
+ The request class for the ``navigator_msgs/MessageFindFling`` service.
+
+ .. attribute:: color
+
+ The color of the shape.
+
+ :type: str
+
+ .. attribute:: ams_status
+
+ The AMS status (1=scanning, 2=flinging)
+
+ :type: int
+
+.. attributetable:: navigator_msgs.srv.MessageFindFlingResponse
+
+.. class:: navigator_msgs.srv.MessageFindFlingResponse
+
+ The response class for the ``navigator_msgs/MessageFindFling`` service.
+
+ .. attribute:: message
+
+ A message in response to the process.
+
+ :type: str
+
+MessageFollowPath
+^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_msgs.srv.MessageFollowPathRequest
+
+.. class:: navigator_msgs.srv.MessageFollowPathRequest
+
+ The request class for the ``navigator_msgs/MessageFollowPath`` service.
+
+ .. attribute:: finished
+
+ The bool to say if we are finished following the path. (1=in progress 2=completed)
+
+ :type: int
+
+.. attributetable:: navigator_msgs.srv.MessageFollowPathResponse
+
+.. class:: navigator_msgs.srv.MessageFollowPathResponse
+
+ The response class for the ``navigator_msgs/MessageFollowPath`` service.
+
+ .. attribute:: message
+
+ A message in response to the process.
+
+ :type: str
+
+MessageWildlifeEncounter
+^^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_msgs.srv.MessageWildlifeEncounterRequest
+
+.. class:: navigator_msgs.srv.MessageWildlifeEncounterRequest
+
+ The request class for the ``navigator_msgs/MessageWildlifeEncounter`` service.
+
+ .. attribute:: buoy_array
+
+ List of buoys (R, G, B) representing the order of the wildlife traversal
+
+ :type: string[]
+
+.. attributetable:: navigator_msgs.srv.MessageWildlifeEncounterResponse
+
+.. class:: navigator_msgs.srv.MessageWildlifeEncounterResponse
+
+ The response class for the ``navigator_msgs/MessageWildlifeEncounter`` service.
+
+ .. attribute:: message
+
+ A message in response to the process.
+
+ :type: str
+
+MessageUAVReplenishment
+^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_msgs.srv.MessageUAVReplenishmentRequest
+
+.. class:: navigator_msgs.srv.MessageUAVReplenishmentRequest
+
+ The request class for the ``navigator_msgs/MessageUAVReplenishment`` service.
+
+ .. attribute:: uav_status
+
+ The UAV status # 1=stowed, 2=deployed, 3=faulted
+
+ :type: int
+
+ .. attribute:: item_status
+
+ The item status # 0=not picked up, 1=picked up, 2=delivered
+
+ :type: int
+
+.. attributetable:: navigator_msgs.srv.MessageUAVReplenishmentResponse
+
+.. class:: navigator_msgs.srv.MessageUAVReplenishmentResponse
+
+ The response class for the ``navigator_msgs/MessageUAVReplenishment`` service.
+
+ .. attribute:: message
+
+ A message in response to the process.
+
+ :type: str
+
+MessageUAVSearchReport
+^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_msgs.srv.MessageUAVSearchReportRequest
+
+.. class:: navigator_msgs.srv.MessageUAVSearchReportRequest
+
+ The request class for the ``navigator_msgs/MessageUAVSearchReport`` service.
+
+ .. attribute:: object1
+
+ The object found (R or N)
+
+ :type: string
+
+ .. attribute:: object1_latitude
+
+ The latitude of object 1
+
+ :type: float64
+
+ .. attribute:: object1_n_s
+
+ The N/S of object 1
+
+ :type: string
+
+ .. attribute:: object1_longitude
+
+ The longitude of object 1
+
+ :type: float64
+
+ .. attribute:: object1_e_w
+
+ The E/W of object 1
+
+ :type: string
+
+ .. attribute:: object2
+
+ The object found (R or N)
+
+ :type: string
+
+ .. attribute:: object2_latitude
+
+ The latitude of object 2
+
+ :type: float64
+
+ .. attribute:: object2_n_s
+
+ The N/S of object 2
+
+ :type: string
+
+ .. attribute:: object2_longitude
+
+ The longitude of object 2
+
+ :type: float64
+
+ .. attribute:: object2_e_w
+
+ The E/W of object 2
+
+ :type: string
+
+ .. attribute:: uav_status
+
+ The UAV status # 1=manual, 2=autonomous, 3=faulted
+
+ :type: int
+
+.. attributetable:: navigator_msgs.srv.MessageUAVSearchReportResponse
+
+.. class:: navigator_msgs.srv.MessageUAVSearchReportResponse
+
+ The response class for the ``navigator_msgs/MessageUAVSearchReport`` service.
+
+ .. attribute:: message
+
+ A message in response to the process.
+
+ :type: str
+
+ScanTheCodeMission
+^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_msgs.srv.ScanTheCodeMissionRequest
+
+.. class:: navigator_msgs.srv.ScanTheCodeMissionRequest
+
+ The request class for the ``navigator_msgs/ScanTheCodeMission`` service.
+
+ .. attribute:: object
+
+ The perception object to look for.
+
+ :type: PerceptionObject
+
+.. attributetable:: navigator_msgs.srv.ScanTheCodeMissionResponse
+
+.. class:: navigator_msgs.srv.ScanTheCodeMissionResponse
+
+ The response class for the ``navigator_msgs/ScanTheCodeMission`` service.
+
+ .. attribute:: observing
+
+ ???
+
+ :type: bool
+
+ .. attribute:: found
+
+ Whether the buoy was found.
+
+ :type: bool
+
+ .. attribute:: colors
+
+ The colors shown by the buoy.
+
+ :type: List[str]
+
+
+AUVSI Communication
+-------------------
+Below outline classes that are used to allow NaviGator to communicate with AUVSI-specific
+platforms.
+
+RobotXEntranceExitGateMessage
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.RobotXEntranceExitGateMessage
+
+.. autoclass:: navigator_robotx_comms.RobotXEntranceExitGateMessage
+ :members:
+
+RobotXDetectDockMessage
+^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.RobotXDetectDockMessage
+
+.. autoclass:: navigator_robotx_comms.RobotXDetectDockMessage
+ :members:
+
+RobotXFindFlingMessage
+^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.RobotXFindFlingMessage
+
+.. autoclass:: navigator_robotx_comms.RobotXFindFlingMessage
+ :members:
+
+RobotXFollowPathMessage
+^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.RobotXFollowPathMessage
+
+.. autoclass:: navigator_robotx_comms.RobotXFollowPathMessage
+ :members:
+
+RobotXHeartbeatMessage
+^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.RobotXHeartbeatMessage
+
+.. autoclass:: navigator_robotx_comms.RobotXHeartbeatMessage
+ :members:
+
+RobotXWildlifeEncounterMessage
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.RobotXWildlifeEncounterMessage
+
+.. autoclass:: navigator_robotx_comms.RobotXWildlifeEncounterMessage
+ :members:
+
+RobotXScanCodeMessage
+^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.RobotXScanCodeMessage
+
+.. autoclass:: navigator_robotx_comms.RobotXScanCodeMessage
+ :members:
+
+RobotXUAVReplenishmentMessage
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.RobotXUAVReplenishmentMessage
+
+.. autoclass:: navigator_robotx_comms.RobotXUAVReplenishmentMessage
+ :members:
+
+RobotXUAVSearchReportMessage
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.RobotXUAVSearchReportMessage
+
+.. autoclass:: navigator_robotx_comms.RobotXUAVSearchReportMessage
+ :members:
+
+RobotXStartServices
+^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.nodes.robotx_comms_client.RobotXStartServices
+
+.. autoclass:: navigator_robotx_comms.nodes.robotx_comms_client.RobotXStartServices
+ :members:
+
+RobotXClient
+^^^^^^^^^^^^
+.. attributetable:: navigator_robotx_comms.nodes.robotx_comms_client.RobotXClient
+
+.. autoclass:: navigator_robotx_comms.nodes.robotx_comms_client.RobotXClient
+ :members:
+
+:mod:`navigator_ball_launcher` - Ball launcher
+----------------------------------------------
+
+.. automodule:: navigator_ball_launcher
+ :members:
+
+ReleaseBallPacket
+^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_ball_launcher.ReleaseBallPacket
+
+.. autoclass:: navigator_ball_launcher.ReleaseBallPacket
+ :members:
+
+SetSpinPacket
+^^^^^^^^^^^^^
+.. attributetable:: navigator_ball_launcher.SetSpinPacket
+
+.. autoclass:: navigator_ball_launcher.SetSpinPacket
+ :members:
+
+:mod:`navigator_drone_comm` - Boat-drone communication standard
+---------------------------------------------------------------
+
+.. automodule:: navigator_drone_comm
+ :members:
+
+HeartbeatReceivePacket
+^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_drone_comm.HeartbeatReceivePacket
+
+.. autoclass:: navigator_drone_comm.HeartbeatReceivePacket
+ :members:
+
+HeartbeatSetPacket
+^^^^^^^^^^^^^^^^^^
+.. attributetable:: navigator_drone_comm.HeartbeatSetPacket
+
+.. autoclass:: navigator_drone_comm.HeartbeatSetPacket
+ :members:
+
+GPSDronePacket
+^^^^^^^^^^^^^^
+.. attributetable:: navigator_drone_comm.GPSDronePacket
+
+.. autoclass:: navigator_drone_comm.GPSDronePacket
+ :members:
+
+EStopPacket
+^^^^^^^^^^^
+.. attributetable:: navigator_drone_comm.EStopPacket
+
+.. autoclass:: navigator_drone_comm.EStopPacket
+ :members:
+
+StopPacket
+^^^^^^^^^^
+.. attributetable:: navigator_drone_comm.StopPacket
+
+.. autoclass:: navigator_drone_comm.StopPacket
+ :members:
+
+StartPacket
+^^^^^^^^^^^
+.. attributetable:: navigator_drone_comm.StartPacket
+
+.. autoclass:: navigator_drone_comm.StartPacket
+ :members:
+
+Color
+^^^^^
+.. attributetable:: navigator_drone_comm.Color
+
+.. autoclass:: navigator_drone_comm.Color
+ :members:
+
+TargetPacket
+^^^^^^^^^^^^
+.. attributetable:: navigator_drone_comm.TargetPacket
+
+.. autoclass:: navigator_drone_comm.TargetPacket
+ :members:
diff --git a/docs/navigator/robotx2022_team_photo.jpg b/docs/navigator/robotx2022_team_photo.jpg
new file mode 100644
index 0000000..3c9f437
Binary files /dev/null and b/docs/navigator/robotx2022_team_photo.jpg differ
diff --git a/docs/navigator/simulating.md b/docs/navigator/simulating.md
new file mode 100644
index 0000000..4dd8aa4
--- /dev/null
+++ b/docs/navigator/simulating.md
@@ -0,0 +1,64 @@
+# Simulating NaviGator
+
+If we had to test all of our new code on the physical build of NaviGator each time
+we made a change, we'd never be able to make changes quickly! Therefore, when
+making changes, it's recommended to simulate them before deploying NaviGator
+in a physical testing environment. Luckily, we have a great simulation environment,
+powered by VRX.
+
+## VRX
+
+[VRX](https://github.com/osrf/vrx) is a simulation environment for aquatic unmanned vehicles, developed by the
+[Open Source Robotics Foundation](https://www.openrobotics.org/). It was originally
+developed for the RobotX competition, and it has continued development in strong
+collaboration with RoboNation, the organization running RobotX. Eventually, the
+VRX competition was launched, which was an exclusively-virtual robotics competition
+that used the VRX platform as a simulator.
+
+VRX is a powerful simulator built on top of [Gazebo](https://gazebosim.org), a standard
+simulator for ROS environments. In VRX, you can customize the vehicle used in the simulator,
+as well as the surrounding environmental conditions (such as the wind, waves, fog,
+and ambient light). Also, the VRX platform typically provides world files and object
+models that are similar to actual task elements used in the biannual international RobotX competition,
+which MIL competes in.
+
+## Launching the NaviGator simulation
+
+To launch the simulation for NaviGator, run the following command in your terminal:
+```bash
+roslaunch navigator_launch simulation.launch --screen
+```
+
+There are some variables you can provide to this launch file to customize the
+simulation environment. These include:
+
+* `use_mil_world`: If `true`, use world files from `navigator_gazebo` (our own
+ ROS package built for NaviGator). Otherwise, use world files from `vrx_gazebo`
+ (aka, world files provided to everyone in VRX). Default: `false`.
+* `world`: Which world file to launch. Typically, there are several world files,
+ each of which will focus on one part of the competition.
+
+## Viewing and inspecting the environment
+
+Now, you've launched the simulation environment, but you're not actually able
+to see NaviGator -- what gives? At this point, you can run one of two commands.
+
+```bash
+gazebogui
+```
+
+`gazebogui` will launch Gazebo, which will provide a beautiful, high-level view
+of the simulation.
+
+```bash
+nviz
+```
+
+`nviz` will launch Rviz, which will give you a much more granular view of NaviGator.
+Here, you can inspect the frames and joints that make up NaviGator, the inputs of
+its sensors, etc.
+
+## Doing things
+
+At this point, it should be just like NaviGator is in the lake -- you can run
+missions, move NaviGator around using `nmove`, or take a peek at the cameras/sensors.
diff --git a/docs/navigator/testing_checklist.rst b/docs/navigator/testing_checklist.rst
new file mode 100644
index 0000000..41a6508
--- /dev/null
+++ b/docs/navigator/testing_checklist.rst
@@ -0,0 +1,126 @@
+Testing Checklist
+=================
+Below is a checklist that should be completed before we leave to test NaviGator
+at a testing site. The following list helps to ensure that we have all necessary
+equipment at the testing site.
+
+.. warning::
+
+ This list should always be followed (as we've learned :doc:`time <../subjugator/lessons19>`
+ and :doc:`time again <../subjugator/lessons22>`).
+
+.. |uc| raw:: html
+
+
+
+Packing
+-------
+
+Equipment
+^^^^^^^^^
+|uc| Radios
+ - |uc| Radio Handset Box
+ - |uc| Radio Base Station Box
+|uc| Generators
+ - |uc| Gas cans
+ - |uc| Funnel
+
+Boat and Trailers
+^^^^^^^^^^^^^^^^^
+|uc| Boat prep
+ - |uc| Attach lidar
+ - |uc| Attach camera covers
+ - |uc| Stow wifi antenna, light post
+ - |uc| Strap computer box closed
+ - |uc| Stow batteries in main trailer
+ - |uc| Detach the large RF kill antenna
+ - |uc| Detach ball launcher tube
+ - |uc| Make sure hydrophone mount it horizontal
+ - |uc| Landing pad is detached
+ - |uc| check for no loose fasteners
+|uc| Boat trailer prep
+ - |uc| Strap pontoons down on both sides
+ - |uc| Check boat trailer lights
+|uc| Main trailer prep
+ - |uc| Check main trailer lights
+ - |uc| Food
+ - |uc| Water
+ - |uc| Gatorade
+ - |uc| Packaged snacks
+
+Mechanical
+^^^^^^^^^^
+|uc| Challenge elements
+|uc| Tape Measure
+|uc| 7/16 wrench
+|uc| 5/32 Allen Key
+|uc| Duct tape and scissor
+|uc| Pliers
+|uc| Flat-head screwdriver
+|uc| O'ring grease (Molykote 55)
+|uc| Cable grease (Molykote 44)
+|uc| Large and small zip ties
+
+Electrical
+^^^^^^^^^^
+|uc| Batteries
+ - |uc| Spare battery set
+ - |uc| Battery charger
+ - |uc| Multimeter
+ - |uc| Battery bolt wrench
+
+|uc| Electrical Box
+
+Software
+^^^^^^^^
+|uc| Ubiquity
+
+|uc| Network Box
+
+Set Up
+------
+
+Equipment
+^^^^^^^^^
+|uc| Radios
+ - |uc| Start charging handsets
+ - |uc| Attach lanyards to handsets
+ - |uc| Connect base station to power
+|uc| Generators
+ - |uc| Check fuel level
+ - |uc| Powering up
+ - |uc| Connect balance leads and check grounds
+ - |uc| Start both generators
+ - |uc| Connect to the trailer's power lead
+
+Boat and Trailers
+^^^^^^^^^^^^^^^^^
+|uc| Boat
+ - |uc| Remove lidar and camera covers
+ - |uc| Deploy wifi antenna, light post, rf antenna
+ - |uc| Remove computer box strap
+ - |uc| Attach batteries
+|uc| Boat trailer
+ - |uc| Unstrap pontoons on both sides
+ - |uc| Disconnect boat trailer lights
+|uc| Main trailer
+ - |uc| Deploy trailer chocks
+ - |uc| Set out cooler, chairs, pop-up, snacks, ice, drinks
+
+Mechanical
+^^^^^^^^^^
+|uc| Assemble and deploy challenge elements
+
+Electrical
+^^^^^^^^^^
+|uc| Batteries
+ - |uc| Spare battery set
+ - |uc| Battery charger
+ - |uc| Multimeter
+ - |uc| Battery bolt wrench
+
+Software
+^^^^^^^^
+|uc| Deploy the Ubiquity
+
+|uc| Power and deploy the network box
diff --git a/docs/navigator/vrx.rst b/docs/navigator/vrx.rst
new file mode 100644
index 0000000..f3a59e4
--- /dev/null
+++ b/docs/navigator/vrx.rst
@@ -0,0 +1,167 @@
+VRX
+===
+This page provides general info about developing for `VRX `_,
+a simulated competition based on the real-life RobotX challenge.
+
+MIL participates both in VRX and RobotX. Most code for this is hosted under ``NaviGator/``.
+
+.. warning::
+
+ Please go through the `getting started guide <../../software/getting_started.html>`_ before going through this tutorial.
+
+
+Verifying that the VRX Environment is Functional / Playing Around in VRX
+------------------------------------------------------------------------
+
+Launch VRX
+^^^^^^^^^^
+In one panel, run:
+
+.. code-block:: bash
+
+ $ roslaunch navigator_launch vrx.launch --screen
+
+This will launch the NaviGator Code and the VRX code in the same container.
+
+Run RVIZ
+~~~~~~~~
+You can visualize things by running:
+
+.. code-block:: bash
+
+ $ vrxviz
+
+Give a move command
+^^^^^^^^^^^^^^^^^^^
+Give NaviGator a move command with:
+
+.. code-block:: bash
+
+ $ nmove forward 5m
+
+See the current odometry
+^^^^^^^^^^^^^^^^^^^^^^^^
+Try streaming the content of a rostopic:
+
+.. code-block:: bash
+
+ $ rostopic echo /odom
+
+Quick testing
+-------------
+The official VRX system runs our code and the simulator in separated, isolated containers to prevent cheating.
+However, for normal development in can be helpful to simply run both in the same container.
+To do this, run:
+
+.. code-block:: bash
+
+ $ roslaunch navigator_launch vrx.launch run_task:=True world:= --screen
+
+Where `` is the name of a world under ``~/catkin_ws/src/mil/NaviGator/simulation/VRX/vrx/vrx_gazebo/worlds``.
+
+For example, run:
+
+.. code-block:: bash
+
+ $ roslaunch navigator_launch vrx.launch run_task:=True world:=stationkeeping_task --screen
+
+to test out the station keeping scenario.
+
+If you wish to see a world with multiple challenges at once (e.g. for testing lidar), try `example_course`.
+
+The `run_task:=True` flag tells the mission server to immediately run the VRX mission. Set this to `False` if you wish to manually start the mission.
+
+Preparing submission
+--------------------
+
+The recommended workflow for submitting our code to vrx is:
+
+Run the dev container:
+
+.. code-block:: bash
+
+ $ ./scripts/run_development_container
+
+#. Branch from the repo and edit whatever files you want to change with what ever text editor you want. Any changes you make to the files from your host machine will immediately show up in the container and when you re-run(for python changes)/ compile(for cpp changes) these changes will immediately take effect. Do the bulk of your development in this stage running mil and vrx code in the same container for fast turn around time in testing.
+
+#. Once you are satisfied with running your code in the development container, you can move on to running your changes against the VRX server. This is how we will be evaluated by OSRF.
+
+#. Make a Trial Container:
+
+ #. Commit and push your changes to a git hub repository on a branch. ie: `my_branch` at `https://github.com/ME/mil.git`
+
+ #. Navigate to the root of the repo:
+
+ .. code-block:: bash
+
+ $ mil
+
+ .. code-block:: bash
+
+ $ ./scripts/build_vrx_trial_container my_branch https://github.com/ME/mil.git
+
+ If you pushed to the uf-mil github, run:
+
+ .. code-block:: bash
+
+ $ ./scripts/build_vrx_trial_container my_branch
+
+ .. note::
+
+ Make sure when building your trial container, that the code actually compiles.
+
+Run your container with a terminal for sanity check. Make sure your container
+actually does what you want when it starts up:
+
+.. code-block:: bash
+
+ $ ./scripts/run_vrx_trial_container my_branch
+
+Now you should have a trial container! Follow the instructions at `https://bitbucket.org/osrf/vrx-docker/src/default/` to run this container against the vrx server.
+
+How to Download and Replay logs from Phase 3 of VRX (2019)
+----------------------------------------------------------
+
+To Download the Logs
+^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: bash
+
+ $ ./NaviGator/simulation/VRX/vrx_logs/2019/download_logs.bash
+
+To Play a Log
+^^^^^^^^^^^^^
+
+.. code-block:: bash
+
+ $ ./NaviGator/simulation/VRX/vrx_logs/play_log.bash
+
+i.e. to play the 2019 docking task run 0:
+
+.. code-block:: bash
+
+ $ ./NaviGator/simulation/VRX/vrx_logs/play_log.bash 2019 dock 0
+
+To Download the Videos:
+^^^^^^^^^^^^^^^^^^^^^^^
+.. code-block:: bash
+
+ $ ./NaviGator/simulation/VRX/vrx_logs/2019/download_videos.bash
+
+To Play a Video:
+^^^^^^^^^^^^^^^^
+.. code-block:: bash
+
+ $ mplayer NaviGator/simulation/VRX/vrx_logs/2019/vrx_2019_videos/.mp4
+
+i.e. to play the 2019 docking task run 1:
+
+.. code-block:: bash
+
+ $ mplayer NaviGator/simulation/VRX/vrx_logs/2019/vrx_2019_videos/dock1.mp4
+
+.. warning::
+
+ Not all tasks and runs have a video. Navigate to
+ `$MIL_REPO/NaviGator/simulation/VRX/vrx_logs/2019/vrx_2019_videos` to see
+ the available videos.
diff --git a/docs/purchasing.rst b/docs/purchasing.rst
new file mode 100644
index 0000000..02ed8c9
--- /dev/null
+++ b/docs/purchasing.rst
@@ -0,0 +1,42 @@
+Purchasing
+==========
+Purchasing and shipping is integral to the proper and efficient functioning of our laboratory. Purchasing helps us to build complex projects, learn about new engineering techniques and tools, and most importantly, enjoy our time in MIL. However, if purchasing is not done correctly, annoying issues can arise! To prevent these, read below before making your first purchase.
+
+Food and Beverage
+-----------------
+* **Beverage Vendors:** When buying beverages, you must buy **Pepsi** (including Gatorade and Aquafina, notably). You **cannot** buy other products, including Coke or Dr. Pepper products.
+* **Meal Reimbursement Limits:** When buying meals, there are limits for reimbursements set by UF per meal. They are:
+ * **Breakfast**: $6/person
+ * **Lunch**: $12/person
+ * **Dinner**: $19/person
+* **Buying Pizza:** When purchasing pizza, please use coupons rather than paying full menu price for the pizzas.
+
+Submitting reimbursements
+-------------------------
+When submitting receipts for reimbursements (for whatever), please ensure:
+
+* You have **signed** the physical receipt with your name, UFID, and signature. You can do this electronically, if it's easier.
+* You have submitted the receipt in a **timely** manner (ie, don't submit it six months after the purchase date).
+* You provide the reason for the purchase, and if it is for food, who was in attendance at the event.
+
+If you've met the above criteria, feel free to email your receipt to Dr. Schwartz! Please include an appropriate subject.
+
+Making online purchases
+-----------------------
+When making purchases online, remember to follow practices specific to the business you're buying from.
+
+Amazon
+~~~~~~
+Only approved faculty members can purchase from Amazon. Therefore, if you'd like
+to purchase something from Amazon (such as even more monitors), the best route is
+to go through someone like Dr. Schwartz.
+
+Other Websites
+~~~~~~~~~~~~~~
+When purchasing from other websites, make sure that your purchases are **tax-exempt.**
+If you need help completing this, contact a faculty or member familiar with making
+tax-exempt purchases.
+
+Furthermore, when creating new accounts for websites for purchasing, ensure that
+the passwords are added to the team's Bitwarden, so other members can access it
+once you graduate/leave/sadly get eaten by an alligator in Lake Alice.
diff --git a/docs/reference/actions.rst b/docs/reference/actions.rst
new file mode 100644
index 0000000..44b73b1
--- /dev/null
+++ b/docs/reference/actions.rst
@@ -0,0 +1,437 @@
+Actions
+-------
+
+Path Planner
+^^^^^^^^^^^^
+
+MoveAction
+~~~~~~~~~~
+
+.. attributetable:: navigator_path_planner.msg.MoveAction
+
+.. class:: navigator_path_planner.msg.MoveAction
+
+ A custom message representing the general movement of an entire system.
+
+ .. attribute:: action_goal
+
+ The goal for an action's movement.
+
+ :type: MoveActionGoal
+
+ .. attribute:: action_result
+
+ The result of a move action's result.
+
+ :type: MoveActionResult
+
+ .. attribute:: action_feedback
+
+ The feedback for an action movement.
+
+ :type: MoveActionFeedback
+
+MoveActionResult
+~~~~~~~~~~~~~~~~
+.. attributetable:: navigator_path_planner.msg.MoveActionResult
+
+.. class:: navigator_path_planner.msg.MoveActionResult
+
+ A custom message representing the result of a system's movement.
+
+ .. attribute:: header
+
+ The header for the message.
+
+ :type: Header
+
+ .. attribute:: status
+
+ The status of the system in its movement.
+
+ :type: GoalStatus
+
+ .. attribute:: result
+
+ The result of the movement
+
+ :type: MoveResult
+
+MoveActionFeedback
+~~~~~~~~~~~~~~~~~~
+.. attributetable:: navigator_path_planner.msg.MoveActionFeedback
+
+.. class:: navigator_path_planner.msg.MoveActionFeedback
+
+ A custom message representing the feedback of a system's movement.
+
+ .. attribute:: header
+
+ The header for the message.
+
+ :type: Header
+
+ .. attribute:: status
+
+ The status of the system in its movement.
+
+ :type: GoalStatus
+
+ .. attribute:: feedback
+
+ The feedback of the movement.
+
+ :type: MoveFeedback
+
+MoveActionGoal
+~~~~~~~~~~~~~~
+.. attributetable:: navigator_path_planner.msg.MoveActionGoal
+
+.. class:: navigator_path_planner.msg.MoveActionGoal
+
+ A custom message representing the goal of an object's action movement.
+
+ .. attribute:: header
+
+ The header for the message.
+
+ :type: Header
+
+ .. attribute:: goal_id
+
+ The ID of the goal.
+
+ :type: GoalID
+
+ .. attribute:: goal
+
+ The goal to move to.
+
+ :type: MoveGoal
+
+MoveFeedback
+~~~~~~~~~~~~~~~~~~
+.. attributetable:: navigator_path_planner.msg.MoveFeedback
+
+.. class:: navigator_path_planner.msg.MoveFeedback
+
+ A custom message representing the feedback of a system's movement.
+
+ .. attribute:: behavior
+
+ A description of the behavior.
+
+ :type: str
+
+ .. attribute:: tree_size
+
+ The size of the lqRRT tree.
+
+ :type: int
+
+ .. attribute:: tracking
+
+ ???
+
+ :type: bool
+
+ .. attribute:: distance
+
+ ???
+
+ :type: List[float]
+
+ .. attribute:: time_till_next_branch
+
+ ???
+
+ :type: float
+
+MoveGoal
+~~~~~~~~
+.. attributetable:: navigator_path_planner.msg.MoveGoal
+
+.. class:: navigator_path_planner.msg.MoveGoal
+
+ A custom message representing the goal of an object's movement.
+
+ .. attribute:: HOLD
+
+ A constant string representing to hold the object's movement. Actually
+ equally to ``hold``.
+
+ :type: str
+
+ .. attribute:: DRIVE
+
+ A constant string representing to using driving movement. Actually
+ equally to ``drive``.
+
+ :type: str
+
+ .. attribute:: DRIVE_SMOOTH
+
+ A constant string representing to using a smooth driving movement. Actually
+ equally to ``drive!``.
+
+ :type: str
+
+ .. attribute:: SKID
+
+ A constant string representing a skidding movement. Actually
+ equally to ``skid``.
+
+ :type: str
+
+ .. attribute:: SPIRAL
+
+ A constant string representing a spiral movement. Actually
+ equally to ``spiral``.
+
+ :type: str
+
+ .. attribute:: BYPASS
+
+ A constant string representing a spiral movement. Actually
+ equally to ``bypass``.
+
+ :type: str
+
+ .. attribute:: move_type
+
+ The type of movement desired, often one of the values above.
+
+ :type: str
+
+ .. attribute:: goal
+
+ The goal to move to.
+
+ :type: Pose
+
+ .. attribute:: focus
+
+ The focal point.
+
+ :type: Point
+
+ .. attribute:: initial_plan_time
+
+ The initial time at which the movement was planned.
+
+ :type: float
+
+ .. attribute:: blind
+
+ ???
+
+ :type: bool
+
+ .. attribute:: speed_factor
+
+ ???
+
+ :type: List[float]
+
+MoveResult
+~~~~~~~~~~
+.. attributetable:: navigator_path_planner.msg.MoveResult
+
+.. class:: navigator_path_planner.msg.MoveResult
+
+ A custom message representing the goal of an object's movement.
+
+ .. attribute:: failure_reason
+
+ The reason for the movement failing, if any.
+
+ :type: str
+
+Shooter
+^^^^^^^
+
+ShooterDoAction
+~~~~~~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.ShooterDoAction
+
+.. class:: navigator_msgs.msg.ShooterDoAction
+
+ A custom message representing the general movement of an entire system.
+
+ .. attribute:: action_goal
+
+ The goal for an action's movement.
+
+ :type: ShooterDoActionGoal
+
+ .. attribute:: action_result
+
+ The result of a move action's result.
+
+ :type: ShooterDoActionResult
+
+ .. attribute:: action_feedback
+
+ The feedback for an action movement.
+
+ :type: ShooterDoActionFeedback
+
+ShooterDoActionResult
+~~~~~~~~~~~~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.ShooterDoActionResult
+
+.. class:: navigator_msgs.msg.ShooterDoActionResult
+
+ A custom message representing the result of a system's movement.
+
+ .. attribute:: header
+
+ The header for the message.
+
+ :type: Header
+
+ .. attribute:: status
+
+ The status of the system in its movement.
+
+ :type: GoalStatus
+
+ .. attribute:: result
+
+ The result of the movement
+
+ :type: ShooterDoResult
+
+ShooterDoActionFeedback
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.ShooterDoActionFeedback
+
+.. class:: navigator_msgs.msg.ShooterDoActionFeedback
+
+ A custom message representing the feedback of a system's movement.
+
+ .. attribute:: header
+
+ The header for the message.
+
+ :type: Header
+
+ .. attribute:: status
+
+ The status of the system in its movement.
+
+ :type: GoalStatus
+
+ .. attribute:: feedback
+
+ The feedback of the movement.
+
+ :type: ShooterDoFeedback
+
+ShooterDoActionGoal
+~~~~~~~~~~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.ShooterDoActionGoal
+
+.. class:: navigator_msgs.msg.ShooterDoActionGoal
+
+ A custom message representing the goal of an object's action movement.
+
+ .. attribute:: header
+
+ The header for the message.
+
+ :type: Header
+
+ .. attribute:: goal_id
+
+ The ID of the goal.
+
+ :type: GoalID
+
+ .. attribute:: goal
+
+ The goal to move to.
+
+ :type: ShooterDoGoal
+
+ShooterDoFeedback
+~~~~~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.msg.ShooterDoFeedback
+
+.. class:: navigator_msgs.msg.ShooterDoFeedback
+
+ A custom message representing the feedback of a system's movement.
+
+ .. attribute:: time_remaining
+
+ The amount of time remaining.
+
+ :type: rospy.Duration
+
+ShooterDoGoal
+~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.msg.ShooterDoGoal
+
+.. class:: navigator_msgs.msg.ShooterDoGoal
+
+ A custom message representing the goal of an object's ShooterDoment. The class
+ has no public attributes.
+
+ShooterDoResult
+~~~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.msg.ShooterDoResult
+
+.. class:: navigator_msgs.msg.ShooterDoResult
+
+ A custom message representing the goal of an object's ShooterDoment.
+
+ .. attribute:: ALREADY_RUNNING
+
+ A constant string value to enumerate an error that the shooter is already running.
+ Constant value set to the name of the variable.
+
+ :type: str
+
+ .. attribute:: NOT_LOADED
+
+ A constant string value to enumerate an error that the shooter is not loaded.
+ Constant value set to the name of the variable.
+
+ :type: str
+
+ .. attribute:: ALREADY_LOADAED
+
+ A constant string value to enumerate an error that the shooter is already loaded.
+ Constant value set to the name of the variable.
+
+ :type: str
+
+ .. attribute:: MANUAL_CONTROL_USED
+
+ A constant string value to enumerate an error that the shooter is being controlled manually.
+ Constant value set to the name of the variable.
+
+ :type: str
+
+ .. attribute:: KILLED
+
+ A constant string value to enumerate an error that the shooter process was killed.
+ Constant value set to the name of the variable.
+
+ :type: str
+
+ .. attribute:: success
+
+ A constant string value to enumerate an error that the shooter process was successful.
+
+ :type: bool
+
+ .. attribute:: error
+
+ If success was not had, then what went wrong.
+
+ :type: str
diff --git a/docs/reference/alarms.rst b/docs/reference/alarms.rst
new file mode 100644
index 0000000..647d352
--- /dev/null
+++ b/docs/reference/alarms.rst
@@ -0,0 +1,154 @@
+:mod:`ros_alarms` - Stateful Alarm System
+-----------------------------------------
+
+.. automodule:: ros_alarms
+
+Python
+^^^^^^
+
+Various Python classes have been built around making the alarm system easier to
+interface with between nodes.
+
+For example, these classes can be used to immediately control alarms without
+the need to interface with topics or services:
+
+.. code-block:: python
+
+ >>> # Assume that the alarm_server node has been started
+ >>> from ros_alarms import Alarm, AlarmBroadcaster, AlarmListener
+ >>> broadcaster = AlarmBroadcaster("test-alarm")
+ >>> listener = AlarmListener("test-alarm")
+ >>> def callback(alarm: Alarm):
+ ... print(f"An alarm with the name {alarm.alarm_name} was called.")
+ >>> listener.add_callback(callback, call_when_raised = True)
+ >>> broadcaster.raise_alarm()
+ An alarm with the name test-alarm was called.
+
+Alarm
+~~~~~
+.. attributetable:: ros_alarms.Alarm
+
+.. autoclass:: ros_alarms.Alarm
+ :members:
+
+AlarmServer
+~~~~~~~~~~~
+.. attributetable:: ros_alarms.nodes.alarm_server.AlarmServer
+
+.. autoclass:: ros_alarms.nodes.alarm_server.AlarmServer
+ :members:
+
+AlarmBroadcaster
+~~~~~~~~~~~~~~~~
+.. attributetable:: ros_alarms.AlarmBroadcaster
+
+.. autoclass:: ros_alarms.AlarmBroadcaster
+ :members:
+
+AlarmListener
+~~~~~~~~~~~~~
+.. attributetable:: ros_alarms.AlarmListener
+
+.. autoclass:: ros_alarms.AlarmListener
+ :members:
+
+HeartbeatMonitor
+~~~~~~~~~~~~~~~~
+.. attributetable:: ros_alarms.HeartbeatMonitor
+
+.. autoclass:: ros_alarms.HeartbeatMonitor
+ :members:
+
+HandlerBase
+~~~~~~~~~~~
+.. attributetable:: ros_alarms.HandlerBase
+
+.. autoclass:: ros_alarms.HandlerBase
+ :members:
+
+
+C++
+^^^
+
+AlarmProxy
+~~~~~~~~~~
+.. cppattributetable:: ros_alarms::AlarmProxy
+
+.. doxygenstruct:: ros_alarms::AlarmProxy
+
+AlarmBroadcaster
+~~~~~~~~~~~~~~~~
+.. cppattributetable:: ros_alarms::AlarmBroadcaster
+
+.. doxygenclass:: ros_alarms::AlarmBroadcaster
+
+AlarmListener
+~~~~~~~~~~~~~
+.. cppattributetable:: ros_alarms::AlarmListener
+
+.. doxygenclass:: ros_alarms::AlarmListener
+
+ListenerCb
+~~~~~~~~~~
+.. cppattributetable:: ros_alarms::ListenerCb
+
+.. doxygenstruct:: ros_alarms::ListenerCb
+
+.. Causes sphinx-doc/sphinx#10152
+.. HeartbeatMonitor
+.. ~~~~~~~~~~~~~~~~
+.. .. cppattributetable:: ros_alarms::HeartbeatMonitor
+
+.. .. doxygenclass:: ros_alarms::HeartbeatMonitor
+
+Subjugator-specific
+^^^^^^^^^^^^^^^^^^^
+
+BusVoltage
+~~~~~~~~~~
+.. attributetable:: alarm_handlers.BusVoltage
+
+.. autoclass:: alarm_handlers.BusVoltage
+ :members:
+
+HeightOverBottom
+~~~~~~~~~~~~~~~~
+.. attributetable:: alarm_handlers.HeightOverBottom
+
+.. autoclass:: alarm_handlers.HeightOverBottom
+ :members:
+
+HwKill
+~~~~~~
+.. attributetable:: alarm_handlers.HwKill
+
+.. autoclass:: alarm_handlers.HwKill
+ :members:
+
+Kill
+~~~~
+.. attributetable:: alarm_handlers.Kill
+
+.. autoclass:: alarm_handlers.Kill
+ :members:
+
+NetworkLoss
+~~~~~~~~~~~
+.. attributetable:: alarm_handlers.NetworkLoss
+
+.. autoclass:: alarm_handlers.NetworkLoss
+ :members:
+
+OdomKill
+~~~~~~~~
+.. attributetable:: alarm_handlers.OdomKill
+
+.. autoclass:: alarm_handlers.OdomKill
+ :members:
+
+ThrusterOut
+~~~~~~~~~~~~
+.. attributetable:: alarm_handlers.ThrusterOut
+
+.. autoclass:: alarm_handlers.ThrusterOut
+ :members:
diff --git a/docs/reference/axros/api.rst b/docs/reference/axros/api.rst
new file mode 100644
index 0000000..9c9cabb
--- /dev/null
+++ b/docs/reference/axros/api.rst
@@ -0,0 +1,166 @@
+API Reference
+^^^^^^^^^^^^^
+
+Exception Hierarchy
+~~~~~~~~~~~~~~~~~~~
+.. exception_hierarchy::
+
+ - :exc:`~axros.AxrosException`
+ - :exc:`~axros.NotSetup`
+ - :exc:`~axros.AlreadySetup`
+ - :exc:`~axros.XMLRPCException`
+ - :exc:`~axros.ROSMasterError`
+ - :exc:`~axros.ROSMasterFailure`
+ - :exc:`~axros.ServiceError`
+ - :exc:`~axros.TooPastError`
+
+Exceptions
+~~~~~~~~~~
+.. attributetable:: axros.AxrosException
+
+.. autoclass:: axros.AxrosException
+ :members:
+
+.. attributetable:: axros.NotSetup
+
+.. autoclass:: axros.NotSetup
+ :members:
+
+.. attributetable:: axros.AlreadySetup
+
+.. autoclass:: axros.AlreadySetup
+ :members:
+
+.. attributetable:: axros.XMLRPCException
+
+.. autoclass:: axros.XMLRPCException
+ :members:
+
+.. attributetable:: axros.ROSMasterError
+
+.. autoclass:: axros.ROSMasterError
+ :members:
+
+.. attributetable:: axros.ROSMasterFailure
+
+.. autoclass:: axros.ROSMasterFailure
+ :members:
+
+.. attributetable:: axros.ServiceError
+
+.. autoclass:: axros.ServiceError
+ :members:
+
+.. attributetable:: axros.TooPastError
+
+.. autoclass:: axros.TooPastError
+ :members:
+
+Utility Functions
+~~~~~~~~~~~~~~~~~
+
+.. autofunction:: axros.wrap_timeout
+
+.. autofunction:: axros.wrap_time_notice
+
+.. autofunction:: axros.wall_sleep
+
+.. autoclass:: axros.XMLRPCLegalType
+
+NodeHandle
+~~~~~~~~~~
+.. attributetable:: axros.NodeHandle
+
+.. autoclass:: axros.NodeHandle
+ :members:
+
+Subscriber
+~~~~~~~~~~
+.. attributetable:: axros.Subscriber
+
+.. autoclass:: axros.Subscriber
+ :members:
+
+Publisher
+~~~~~~~~~
+.. attributetable:: axros.Publisher
+
+.. autoclass:: axros.Publisher
+ :members:
+
+Service
+~~~~~~~
+.. attributetable:: axros.Service
+
+.. autoclass:: axros.Service
+ :members:
+
+ServiceClient
+~~~~~~~~~~~~~
+.. attributetable:: axros.ServiceClient
+
+.. autoclass:: axros.ServiceClient
+ :members:
+
+AsyncServerProxy
+~~~~~~~~~~~~~~~~
+.. attributetable:: axros.AsyncServerProxy
+
+.. autoclass:: axros.AsyncServerProxy
+ :members:
+
+ROSMasterProxy
+~~~~~~~~~~~~~~
+.. attributetable:: axros.ROSMasterProxy
+
+.. autoclass:: axros.ROSMasterProxy
+ :members:
+
+Goal
+~~~~
+.. attributetable:: axros.Goal
+
+.. autoclass:: axros.Goal
+ :members:
+
+GoalManager
+~~~~~~~~~~~
+.. attributetable:: axros.GoalManager
+
+.. autoclass:: axros.GoalManager
+ :members:
+
+SimpleActionServer
+~~~~~~~~~~~~~~~~~~
+.. attributetable:: axros.SimpleActionServer
+
+.. autoclass:: axros.SimpleActionServer
+ :members:
+
+ActionClient
+~~~~~~~~~~~~
+.. attributetable:: axros.ActionClient
+
+.. autoclass:: axros.ActionClient
+ :members:
+
+Transform
+~~~~~~~~~~
+.. attributetable:: axros.Transform
+
+.. autoclass:: axros.Transform
+ :members:
+
+TransformBroadcaster
+~~~~~~~~~~~~~~~~~~~~
+.. attributetable:: axros.TransformBroadcaster
+
+.. autoclass:: axros.TransformBroadcaster
+ :members:
+
+TransformListener
+~~~~~~~~~~~~~~~~~
+.. attributetable:: axros.TransformListener
+
+.. autoclass:: axros.TransformListener
+ :members:
diff --git a/docs/reference/axros/errors.rst b/docs/reference/axros/errors.rst
new file mode 100644
index 0000000..53b8b88
--- /dev/null
+++ b/docs/reference/axros/errors.rst
@@ -0,0 +1,48 @@
+Errors and Known Issues
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Handling :class:`aiohttp.ClientConnectionError`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When using axros, you may encounter an instance of :class:`aiohttp.ClientConnectionError`
+when attempting to use the module. By the class' name, its understood that it is
+related to some connection error... but how do you actually fix it?
+
+Check the following things:
+
+* `roscore` is running and accessible
+* The correct ROS Master URI is given to the :class:`~axros.NodeHandle` or :class:`~axros.ROSMasterProxy`.
+
+If these appear correct, try restarting ROS (either by restarting `roscore` or `roslaunch`).
+It may be the case that a node stopped incorrectly or a service was improperly started,
+in which case ROS may believe a resource exists when it actually does not.
+
+Subscribing to parameter updates
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Using `rospy`, individual nodes can "subscribe" to particular parameters to receive
+updates on when these parameters are updated. This allows the nodes to quickly respond
+to changes made in the parameter server.
+
+However, this behavior has not been implemented in axros. This is because a more
+modern approach to this behavior includes using `Dynamic Reconfigure `_.
+Dynamic Reconfigure is more efficient than using the parameter subscriber feature
+previously mentioned, as dynamic reconfigure uses callbacks to indicate new changes,
+while nodes use a consistent polling feature to get updates on parameters.
+
+Subscribing to high-rate publishers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some publishers publish messages at very fast rates, which can add reliability
+and speed to a robotic system. However, axros may not be able to keep up with the
+high rate of incoming messages if the client code is constructed in particular
+ways.
+
+To ensure that the subscriber is able to read all incoming messages, ensure the following:
+
+1. Supply a callback to the subscriber that receives all incoming messages; do
+ not depend on using :meth:`axros.Subscriber.get_next_message`. The latter method
+ will cause messages to never be read if a callback is not supplied.
+2. When attempting to read all messages published by a publisher over a specific
+ period, use :meth:`axros.Subscriber.recently_read` to determine if more messages
+ still need to be read before the subscriber can be closed.
diff --git a/docs/reference/axros/examples.rst b/docs/reference/axros/examples.rst
new file mode 100644
index 0000000..94484b6
--- /dev/null
+++ b/docs/reference/axros/examples.rst
@@ -0,0 +1,93 @@
+Examples
+^^^^^^^^
+
+The following example starts a publisher and a subscriber which listens to the messages
+published by the publisher. After two seconds, it reports how many messages it was
+able to successfully receive.
+
+.. code-block:: python
+
+ import asyncio
+ from rosgraph_msgs.msg import Clock
+ from axros import NodeHandle, Publisher, Subscriber
+ import uvloop
+
+ async def pubsub(nh: NodeHandle, pub: Publisher, sub: Subscriber):
+ count = 0
+ try:
+ while True:
+ await asyncio.sleep(0)
+ msg = (Clock(nh.get_time()))
+ pub.publish(msg)
+ recv = await sub.get_next_message()
+ if (recv == msg):
+ count += 1
+ except:
+ print(f"Eventually, heard {count} messages.")
+ pass
+
+
+ async def main():
+ nh = await NodeHandle.from_argv("node", "", anonymous = True)
+ async with nh:
+ pub = nh.advertise('clock2', Clock, latching = True)
+ sub = nh.subscribe('clock2', Clock)
+ await asyncio.gather(pub.setup(), sub.setup())
+ pubsub_task = asyncio.create_task(pubsub(nh, pub, sub))
+ print("Everything is setup. Waiting two seconds.")
+ await asyncio.sleep(2)
+ pubsub_task.cancel()
+
+ if __name__ == "__main__":
+ uvloop.install()
+ asyncio.run(main())
+
+The node handle can be used for general purposes, such as parameters and sleeping:
+
+.. code-block:: python
+
+ >>> import os
+ >>> import axros
+ >>> nh = await NodeHandle("/test", "special_node", "localhost", os.environ["ROS_MASTER_URI"], {})
+ >>> nh.get_name()
+ '/test/special_node'
+ >>> await nh.set_param("special_param", True)
+ >>> await nh.get_param("special_param")
+ True
+ >>> await nh.delete_param("special_param")
+ >>> try:
+ ... await nh.get_param("special_param")
+ ... except axros.ROSMasterException:
+ ... print("This parameter does not exist!")
+ This parameter does not exist!
+ >>> await nh.sleep(2) # Sleeps for 2 seconds
+
+The node handle can also be used for publishing and subscribing to topics. Note
+that all Publishers and subscribers must be setup.
+
+.. code-block:: python
+
+ >>> import os
+ >>> import axros
+ >>> nh = await axros.NodeHandle("/test", "special_node", "localhost", os.environ["ROS_MASTER_URI"], {})
+ >>> from std_msgs.msg import Int32
+ >>> pub = nh.advertise("running_time", Int32)
+ >>> await pub.setup()
+ >>> async def publish():
+ ... try:
+ ... count = 0
+ ... while True:
+ ... pub.publish(Int32(count))
+ ... count += 1
+ ... await asyncio.sleep(1)
+ ... except asyncio.CancelledError as _:
+ ... # When task gets cancelled, stop publishing
+ ... pass
+ >>> task = asyncio.create_task(publish()) # Start publishing!
+ >>> sub = nh.subscribe("running_time", Int32)
+ >>> await sub.setup()
+ >>> while True:
+ ... print(await sub.get_next_message())
+ 4
+ 5
+ 6
diff --git a/docs/reference/axros/index.rst b/docs/reference/axros/index.rst
new file mode 100644
index 0000000..cd672e5
--- /dev/null
+++ b/docs/reference/axros/index.rst
@@ -0,0 +1,12 @@
+:mod:`axros` - Independent extensions for ROS
+---------------------------------------------
+
+.. automodule:: axros
+
+.. toctree::
+ :maxdepth: 1
+
+ resources
+ errors
+ examples
+ api
diff --git a/docs/reference/axros/resources.rst b/docs/reference/axros/resources.rst
new file mode 100644
index 0000000..2bf1eb2
--- /dev/null
+++ b/docs/reference/axros/resources.rst
@@ -0,0 +1,15 @@
+Managing Resources
+^^^^^^^^^^^^^^^^^^
+When using resources in axros, you must be mindful of how you start the resource,
+and how you clean the resource up. Many times, these actions are not done for you
+(to give you more control), and you must be mindful of when you plan to do them
+yourself. Doing these actions in the improper order or not doing them at all can result
+in resources becoming broken.
+
+For example, to start a publisher, you must first call the :meth:`Publisher.setup`
+after initializing the class. Then, you must either shut down the publisher using
+:meth:`Publisher.shutdown` or shut down the entire node handle using :meth:`NodeHandle.shutdown` - this
+will shutdown all publishers spawned by the node.
+
+Furthermore, attempting to shut down a resource more than once will result in an
+instance of :class:`RuntimeError` being raised.
diff --git a/docs/reference/bagging.rst b/docs/reference/bagging.rst
new file mode 100644
index 0000000..feb007d
--- /dev/null
+++ b/docs/reference/bagging.rst
@@ -0,0 +1,9 @@
+Online Bagger
+-------------
+
+.. currentmodule:: mil_tools
+
+.. attributetable:: nodes.online_bagger.OnlineBagger
+
+.. autoclass:: nodes.online_bagger.OnlineBagger
+ :members:
diff --git a/docs/reference/battery.rst b/docs/reference/battery.rst
new file mode 100644
index 0000000..05444a6
--- /dev/null
+++ b/docs/reference/battery.rst
@@ -0,0 +1,9 @@
+Battery Monitor
+---------------
+
+.. currentmodule:: navigator_battery_monitor
+
+.. attributetable:: nodes.navigator_battery_monitor.BatteryMonitor
+
+.. autoclass:: nodes.navigator_battery_monitor.BatteryMonitor
+ :members:
diff --git a/docs/reference/can.rst b/docs/reference/can.rst
new file mode 100644
index 0000000..f08e7d7
--- /dev/null
+++ b/docs/reference/can.rst
@@ -0,0 +1,210 @@
+:mod:`mil_usb_to_can` - USB to CAN Communication
+------------------------------------------------
+
+.. automodule:: mil_usb_to_can
+
+:mod:`mil_usb_to_can.sub8` - SubjuGator 8
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. automodule:: mil_usb_to_can.sub8
+
+Packet Format
+~~~~~~~~~~~~~
+In order to reliably communicate with the USB to CAN board, a consistent packet format
+must be defined.
+
+Below is the USBtoCAN Packet Format. This packet format wraps every message being
+sent over the serial connection to the USB to CAN board from ROS.
+
+.. list-table:: USBtoCAN Packet Format
+ :header-rows: 1
+
+ * - Name
+ - Length
+ - Description
+ * - Start flag (``0xC0``)
+ - 1 byte
+ - Flag indicating the start of a new board message
+ * - Payload
+ - 4-11 bytes
+ - Actual data being transmitted. Often created through application packets.
+ The two following tables show the payloads of command and receiving packets.
+ * - End flag (``0xC1``)
+ - 1 byte
+ - Flag indicating end of previous board message
+
+Below are the payload specifications for each type of transmission. Command packets
+are packets sent out by the computer to complete an action (sending or requesting
+information), whereas receiving packets are packets that listen to data coming from
+other devices.
+
+.. list-table:: Command Packet (:class:`.CommandPacket`)
+ :header-rows: 1
+
+ * - Name
+ - Length
+ - Description
+ * - Length
+ - 1 byte
+ - Byte indicating the length of the data being sent, or the length of the data
+ expected to be received, in bytes. Notably, bit 7 of this byte determines whether
+ the command packet is sending a command, or receiving data through a command.
+ If bit 7 is 1, then the command packet is receiving.
+ * - CAN ID
+ - 1 byte
+ - ID of the sender, or ID of who to request from
+ * - Data
+ - 1-8 bytes
+ - For sending command packets, the actual data being sent. For requesting command
+ packets, an empty binary string.
+
+.. list-table:: Receiving Packet (:class:`.ReceivePacket`)
+ :header-rows: 1
+
+ * - Name
+ - Length
+ - Description
+ * - Device ID
+ - 1 byte
+ - The CAN ID of the device to receive data from.
+ * - Payload length
+ - 1 byte
+ - The amount of data to listen to.
+ * - Data
+ - 1-8 bytes
+ - The data that was received.
+ * - Checksum
+ - 1 byte
+ - The checksum for the data.
+
+Checksums
+~~~~~~~~~
+All messages contain a checksum to help verify data integrity. However, receiving
+packets also have a special byte containing a slightly modified checksum formula.
+
+The checksum in all packets is found by adding up all bytes in the byte string,
+including the start/end flags, and then using modulo 16 on this result.
+
+Exceptions
+~~~~~~~~~~
+
+Exception Hierarchy
+"""""""""""""""""""
+.. currentmodule:: mil_usb_to_can.sub8
+
+.. exception_hierarchy::
+
+ - :exc:`Exception`
+ - :exc:`ApplicationPacketWrongIdentifierException`
+ - :exc:`USB2CANException`
+ - :exc:`ChecksumException`
+ - :exc:`PayloadTooLargeException`
+ - :exc:`InvalidFlagException`
+ - :exc:`InvalidStartFlagException`
+ - :exc:`InvalidEndFlagException`
+
+Exception List
+"""""""""""""""""""
+.. autoclass:: ApplicationPacketWrongIdentifierException
+ :members:
+
+.. autoclass:: USB2CANException
+ :members:
+
+.. autoclass:: ChecksumException
+ :members:
+
+.. autoclass:: PayloadTooLargeException
+ :members:
+
+.. autoclass:: InvalidFlagException
+ :members:
+
+.. autoclass:: InvalidStartFlagException
+ :members:
+
+.. autoclass:: InvalidEndFlagException
+ :members:
+
+ApplicationPacket
+~~~~~~~~~~~~~~~~~
+.. attributetable:: mil_usb_to_can.sub8.ApplicationPacket
+
+.. autoclass:: mil_usb_to_can.sub8.ApplicationPacket
+ :members:
+
+USBtoCANBoard
+~~~~~~~~~~~~~
+.. attributetable:: mil_usb_to_can.sub8.USBtoCANBoard
+
+.. autoclass:: mil_usb_to_can.sub8.USBtoCANBoard
+ :members:
+
+CANDeviceHandle
+~~~~~~~~~~~~~~~
+.. attributetable:: mil_usb_to_can.sub8.CANDeviceHandle
+
+.. autoclass:: mil_usb_to_can.sub8.CANDeviceHandle
+ :members:
+
+USBtoCANDriver
+~~~~~~~~~~~~~~
+.. attributetable:: mil_usb_to_can.sub8.USBtoCANDriver
+
+.. autoclass:: mil_usb_to_can.sub8.USBtoCANDriver
+ :members:
+
+SimulatedCANDevice
+~~~~~~~~~~~~~~~~~~
+.. attributetable:: mil_usb_to_can.sub8.SimulatedCANDevice
+
+.. autoclass:: mil_usb_to_can.sub8.SimulatedCANDevice
+ :members:
+
+SimulatedUSBtoCAN
+~~~~~~~~~~~~~~~~~
+.. attributetable:: mil_usb_to_can.sub8.SimulatedUSBtoCAN
+
+.. autoclass:: mil_usb_to_can.sub8.SimulatedUSBtoCAN
+ :members:
+
+Packet
+~~~~~~
+.. attributetable:: mil_usb_to_can.sub8.Packet
+
+.. autoclass:: mil_usb_to_can.sub8.Packet
+ :members:
+
+ReceivePacket
+~~~~~~~~~~~~~
+.. attributetable:: mil_usb_to_can.sub8.ReceivePacket
+
+.. autoclass:: mil_usb_to_can.sub8.ReceivePacket
+ :members:
+
+CommandPacket
+~~~~~~~~~~~~~
+.. attributetable:: mil_usb_to_can.sub8.CommandPacket
+
+.. autoclass:: mil_usb_to_can.sub8.CommandPacket
+ :members:
+
+:mod:`mil_usb_to_can.sub9` - SubjuGator 9
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. automodule:: mil_usb_to_can.sub9
+.. currentmodule:: mil_usb_to_can.sub9
+
+CANDeviceHandle
+~~~~~~~~~~~~~~~
+.. attributetable:: mil_usb_to_can.sub9.CANDeviceHandle
+
+.. autoclass:: mil_usb_to_can.sub9.CANDeviceHandle
+ :members:
+
+SimulatedCANDeviceHandle
+~~~~~~~~~~~~~~~~~~~~~~~~
+.. attributetable:: mil_usb_to_can.sub9.SimulatedCANDeviceHandle
+
+.. autoclass:: mil_usb_to_can.sub9.SimulatedCANDeviceHandle
+ :members:
diff --git a/docs/reference/electrical_protocol.rst b/docs/reference/electrical_protocol.rst
new file mode 100644
index 0000000..621af67
--- /dev/null
+++ b/docs/reference/electrical_protocol.rst
@@ -0,0 +1,174 @@
+:mod:`electrical_protocol` - Electrical-software communication standard
+-----------------------------------------------------------------------
+
+.. automodule:: electrical_protocol
+.. currentmodule:: electrical_protocol
+
+Packet Format
+~~~~~~~~~~~~~
+In order to reliably communicate with an electrical board, a consistent packet format
+must be defined.
+
+Below is the electrical protocol packet format. This packet format wraps every message being
+sent over the serial connection to the USB to CAN board from ROS.
+
+.. list-table:: Packet Format
+ :header-rows: 1
+
+ * - Name
+ - Length
+ - Description
+ * - Sync character 1 (``0x37``)
+ - 1 byte
+ - First sync character indicating the start of packets.
+ * - Sync character 2 (``0x01``)
+ - 1 byte
+ - Second sync character indicating the start of packets.
+ * - Class ID
+ - 1 byte
+ - Message class. Determines the family of messages the packet belongs to.
+ * - Subclass ID
+ - 1 byte
+ - Message subclass. In combination with class, determines specific qualities
+ of message.
+ * - Payload Length
+ - 2 bytes
+ - Length of payload.
+ * - Payload
+ - 0-65535 bytes
+ - Payload. Meaning of payload is determined by specific packet class/subclass.
+ * - Checksum A
+ - 1 byte
+ - First byte of Fletcher's checksum.
+ * - Checksum B
+ - 1 byte
+ - Second byte of Fletcher's checksum.
+
+Checksums
+~~~~~~~~~
+All messages contain a checksum to help verify data integrity. However, receiving
+packets also have a special byte containing a slightly modified checksum formula.
+
+The checksum in all packets is found by adding up all bytes in the byte string,
+including the start/end flags, and then using modulo 16 on this result. The
+library checksum is implemented like so:
+
+.. literalinclude:: ../../mil_common/drivers/electrical_protocol/electrical_protocol/packet.py
+ :pyobject: Packet._calculate_checksum
+
+Packet Listing
+~~~~~~~~~~~~~~
+Below is a listing of all available packets. The payload format is the format
+used by the :mod:`struct` module. For more information, see the Python documentation
+on the :ref:`list of format characters`, and their corresponding
+byte length.
+
++------------+--------------+----------------+-------------------------------------------------------------------------+
+| Message ID | Subclass ID | Payload Format | Class |
++============+==============+================+=========================================================================+
+| 0x00 | 0x00 | Empty | :class:`electrical_protocol.NackPacket` |
++ (Meta) +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x01 | Empty | :class:`electrical_protocol.AckPacket` |
++------------+--------------+----------------+-------------------------------------------------------------------------+
+| 0x01 | 0x00 | Empty | :class:`sub8_thrust_and_kill_board.HeartbeatPacket` |
++ (Sub8 +--------------+----------------+-------------------------------------------------------------------------+
+| Thrust/ | 0x01 | ``Bf`` | :class:`sub8_thrust_and_kill_board.ThrustSetPacket` |
++ Kill) +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x02 | ``B`` | :class:`sub8_thrust_and_kill_board.KillSetPacket` |
++ +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x03 | ``B`` | :class:`sub8_thrust_and_kill_board.KillReceivePacket` |
++------------+--------------+----------------+-------------------------------------------------------------------------+
+| 0x02 | 0x00 | Empty | :class:`sub9_thrust_and_kill_board.HeartbeatSetPacket` |
++ (Sub9 +--------------+----------------+-------------------------------------------------------------------------+
+| Thrust/ | 0x01 | Empty | :class:`sub9_thrust_and_kill_board.HeartbeatReceivePacket` |
++ Kill) +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x02 | ``Bf`` | :class:`sub9_thrust_and_kill_board.ThrustSetPacket` |
++ +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x03 | ``B`` | :class:`sub9_thrust_and_kill_board.KillSetPacket` |
++ +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x04 | ``B`` | :class:`sub9_thrust_and_kill_board.KillReceivePacket` |
++------------+--------------+----------------+-------------------------------------------------------------------------+
+| 0x03 | 0x00 | Empty | :class:`sub8_battery_monitor_board.BatteryPollRequestPacket` |
++ (Battery +--------------+----------------+-------------------------------------------------------------------------+
+| Monitor) | 0x01 | ``ffff`` | :class:`sub8_battery_monitor_board.BatteryPollResponsePacket` |
++------------+--------------+----------------+-------------------------------------------------------------------------+
+| 0x04 | 0x00 | ``BB`` | :class:`sub_actuator_board.ActuatorSetPacket` |
++ (Actuator +--------------+----------------+-------------------------------------------------------------------------+
+| Board) | 0x01 | Empty | :class:`sub_actuator_board.ActuatorPollRequestPacket` |
++ +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x02 | ``B`` | :class:`sub_actuator_board.ActuatorPollResponsePacket` |
++------------+--------------+----------------+-------------------------------------------------------------------------+
+| 0x05 | 0x00 | Empty | :class:`sub9_system_status_board.SetLedRequestPacket` |
+| (System | | | |
+| Status) | | | |
++------------+--------------+----------------+-------------------------------------------------------------------------+
+| 0x10 | 0x00 | ``?B`` | :class:`navigator_kill_light_board.KillSetPacket` |
+| (NaviGator +--------------+----------------+-------------------------------------------------------------------------+
+| Temporary | 0x01 | ``?B`` | :class:`navigator_kill_light_board.KillReceivePacket` |
+| Pico Kill +--------------+----------------+-------------------------------------------------------------------------+
+| Board) | 0x02 | | :class:`navigator_kill_light_board.SetMovementModePacket` |
++------------+--------------+----------------+-------------------------------------------------------------------------+
+| 0x11 | 0x00 | Empty | :class:`navigator_ball_launcher.ReleaseBallPacket` |
+| (NaviGator +--------------+----------------+-------------------------------------------------------------------------+
+| Ball | 0x01 | ``B`` | :class:`navigator_ball_launcher.SetSpinPacket` |
+| Launcher | | | |
+| Board) | | | |
++------------+--------------+----------------+-------------------------------------------------------------------------+
+| 0x20 | 0x00 | Empty | :class:`navigator_drone_comm.HeartbeatReceivePacket` |
+| (Drone) +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x01 | Empty | :class:`navigator_drone_comm.HeartbeatSetPacket` |
++ +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x02 | ``fff`` | :class:`navigator_drone_comm.GPSDronePacket` |
++ +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x03 | Empty | :class:`navigator_drone_comm.EStopPacket` |
++ +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x04 | ``20s`` | :class:`navigator_drone_comm.StartPacket` |
++ +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x05 | Empty | :class:`navigator_drone_comm.StopPacket` |
++ +--------------+----------------+-------------------------------------------------------------------------+
+| | 0x06 | ``ffc`` | :class:`navigator_drone_comm.TargetPacket` |
++------------+--------------+----------------+-------------------------------------------------------------------------+
+
+Exceptions
+~~~~~~~~~~
+
+Exception Hierarchy
+"""""""""""""""""""
+.. currentmodule:: electrical_protocol
+
+.. exception_hierarchy::
+
+ - :exc:`ChecksumException`
+
+Exception List
+"""""""""""""""""""
+.. autoclass:: electrical_protocol.ChecksumException
+ :members:
+
+ROSSerialDevice
+~~~~~~~~~~~~~~~
+.. attributetable:: electrical_protocol.ROSSerialDevice
+
+.. autoclass:: electrical_protocol.ROSSerialDevice
+ :members:
+
+Packet
+~~~~~~
+.. attributetable:: electrical_protocol.Packet
+
+.. autoclass:: electrical_protocol.Packet
+ :members:
+
+NackPacket
+~~~~~~~~~~
+.. attributetable:: electrical_protocol.NackPacket
+
+.. autoclass:: electrical_protocol.NackPacket
+ :members:
+
+AckPacket
+~~~~~~~~~
+.. attributetable:: electrical_protocol.AckPacket
+
+.. autoclass:: electrical_protocol.AckPacket
+ :members:
diff --git a/docs/reference/exceptions.rst b/docs/reference/exceptions.rst
new file mode 100644
index 0000000..0db3ee4
--- /dev/null
+++ b/docs/reference/exceptions.rst
@@ -0,0 +1,18 @@
+Exceptions
+----------
+
+.. currentmodule:: mil_tools
+
+.. attributetable:: ArgumentParserException
+
+.. autoclass:: ArgumentParserException
+ :members:
+
+ An error was encountered while parsing arguments. Commonly extended by
+ :class:`ThrowingArgumentParser`.
+
+ .. attribute:: message
+
+ The message associated with the error.
+
+ :rtype: :class:`str`
diff --git a/docs/reference/images.rst b/docs/reference/images.rst
new file mode 100644
index 0000000..1b24018
--- /dev/null
+++ b/docs/reference/images.rst
@@ -0,0 +1,47 @@
+Images
+------
+
+BagCrawler
+^^^^^^^^^^
+
+.. attributetable:: mil_ros_tools.BagCrawler
+
+.. autoclass:: mil_ros_tools.BagCrawler
+ :members:
+
+CvDebug
+^^^^^^^
+.. attributetable:: mil_tools.CvDebug
+
+.. autoclass:: mil_tools.CvDebug
+ :members:
+
+Image_Publisher
+^^^^^^^^^^^^^^^
+.. attributetable:: mil_tools.Image_Publisher
+
+.. autoclass:: mil_tools.Image_Publisher
+ :members:
+
+Image_Subscriber
+^^^^^^^^^^^^^^^^
+.. attributetable:: mil_tools.Image_Subscriber
+
+.. autoclass:: mil_tools.Image_Subscriber
+ :members:
+
+StereoImageSubscriber
+^^^^^^^^^^^^^^^^^^^^^
+
+.. attributetable:: mil_tools.StereoImageSubscriber
+
+.. autoclass:: mil_tools.StereoImageSubscriber
+ :members:
+
+Plotter
+^^^^^^^
+
+.. attributetable:: mil_tools.Plotter
+
+.. autoclass:: mil_tools.Plotter
+ :members:
diff --git a/docs/reference/index.rst b/docs/reference/index.rst
new file mode 100644
index 0000000..e9d8589
--- /dev/null
+++ b/docs/reference/index.rst
@@ -0,0 +1,35 @@
+Software Reference
+==================
+
+The following describes the software reference for many of the subsystems used
+by MIL. These subsystems relate to a variety of processes.
+
+.. toctree::
+ :maxdepth: 1
+
+ messages
+ services
+ actions
+ exceptions
+ mathematics
+ io
+ images
+ serial
+ msghandlers
+ axros/index
+ mission/index
+ rviz
+ pcodar
+ electrical_protocol
+ can
+ resources
+ rc
+ alarms
+ pathplanning
+ battery
+ passivesonar
+ vision
+ poi
+ pneumatic
+ sabertooth
+ bagging
diff --git a/docs/reference/io.rst b/docs/reference/io.rst
new file mode 100644
index 0000000..6a6b8f3
--- /dev/null
+++ b/docs/reference/io.rst
@@ -0,0 +1,36 @@
+User Input/Output
+-----------------
+.. currentmodule:: mil_tools
+
+Utility Functions
+^^^^^^^^^^^^^^^^^
+
+.. autofunction:: mil_tools.get_ch
+
+FPrintFactory
+^^^^^^^^^^^^^
+
+.. attributetable:: FprintFactory
+
+.. autoclass:: FprintFactory
+ :members:
+
+File Input/Output
+-----------------
+.. currentmodule:: mil_tools
+
+Utility Functions
+^^^^^^^^^^^^^^^^^
+
+.. autofunction:: mil_tools.download
+
+.. autofunction:: mil_tools.download_and_unzip
+
+Sanitization
+------------
+.. currentmodule:: mil_tools
+
+Utility Functions
+^^^^^^^^^^^^^^^^^
+
+.. autofunction:: mil_tools.slugify
diff --git a/docs/reference/mathematics.rst b/docs/reference/mathematics.rst
new file mode 100644
index 0000000..3d81c1d
--- /dev/null
+++ b/docs/reference/mathematics.rst
@@ -0,0 +1,20 @@
+Mathematics
+-------------------
+
+.. currentmodule:: mil_tools
+
+.. autofunction:: mil_tools.rotate_vect_by_quat
+
+.. autofunction:: mil_tools.skew_symmetric_cross
+
+.. autofunction:: mil_tools.deskew
+
+.. autofunction:: mil_tools.normalize
+
+.. autofunction:: mil_tools.compose_transformation
+
+.. autofunction:: mil_tools.make_rotation
+
+.. autofunction:: mil_tools.quat_to_rotvec
+
+.. autofunction:: mil_tools.euler_to_quat
diff --git a/docs/reference/messages.rst b/docs/reference/messages.rst
new file mode 100644
index 0000000..ca5c762
--- /dev/null
+++ b/docs/reference/messages.rst
@@ -0,0 +1,1706 @@
+Messages
+--------
+
+actionlib
+^^^^^^^^^
+
+GoalStatus
+~~~~~~~~~~
+
+.. attributetable:: actionlib_msgs.msg.GoalStatus
+
+.. class:: actionlib_msgs.msg.GoalStatus
+
+ Message type indicating the status of a goal in an actions server. Used by
+ the SimpleActionClient implemented by ROS and axros' layer over it.
+
+ The specific attributes of the message are also used in order to indicate
+ a specific type of status.
+
+ .. attribute:: PENDING
+
+ A constant of the message type used to indicate a pending goal. Truly
+ set to 0.
+
+ .. attribute:: ACTIVE
+
+ A constant of the message type used to indicate a active goal. Truly
+ set to 1.
+
+ .. attribute:: PREEMPTED
+
+ A constant of the message type used to indicate a preempted goal. Truly
+ set to 2.
+
+ .. attribute:: SUCCEEDED
+
+ A constant of the message type used to indicate a goal which succeeded.
+ Truly set to 2.
+
+Alarms
+^^^^^^
+
+Alarm
+~~~~~
+
+.. attributetable:: ros_alarms_msgs.msg.Alarm
+
+.. class:: ros_alarms_msgs.msg.Alarm
+
+ A message representing a ROS Alarm.
+
+ .. attribute:: alarm_name
+
+ The name of the alarm.
+
+ :type: str
+
+ .. attribute:: raised
+
+ Whether the alarm was raised.
+
+ :type: bool
+
+ .. attribute:: node_name
+
+ The node name associated with the alarm.
+
+ :type: str
+
+ .. attribute:: problem_description
+
+ The problem description associated with the alarm.
+
+ :type: str
+
+ .. attribute:: parameters
+
+ The JSON parameters associated with the alarm.
+
+ :type: str
+
+ .. attribute:: severity
+
+ The severity of the alarm.
+
+ :type: int
+
+Geometry Messages
+^^^^^^^^^^^^^^^^^
+
+Quaternion
+~~~~~~~~~~
+
+.. attributetable:: geometry_msgs.msg.Quaternion
+
+.. class:: geometry_msgs.msg.Quaternion
+
+ A message type representing a quaternion.
+
+ .. attribute:: w
+
+ The first element of the quaternion.
+
+ :rtype: float
+
+ .. attribute:: x
+
+ The second element of the quaternion.
+
+ :rtype: float
+
+ .. attribute:: y
+
+ The third element of the quaternion.
+
+ :rtype: float
+
+ .. attribute:: z
+
+ The fourth element of the quaternion.
+
+ :rtype: float
+
+Point
+~~~~~
+
+.. attributetable:: geometry_msgs.msg.Point
+
+.. class:: geometry_msgs.msg.Point
+
+ A ROS message type representing a single point.
+
+ .. attribute:: x
+
+ The x-value of the point.
+
+ :type: :class:`float`
+
+ .. attribute:: y
+
+ The y-value of the point.
+
+ :type: :class:`float`
+
+ .. attribute:: z
+
+ The z-value of the point.
+
+ :type: :class:`float`
+
+PointStamped
+~~~~~~~~~~~~
+
+.. attributetable:: geometry_msgs.msg.PointStamped
+
+.. class:: geometry_msgs.msg.PointStamped
+
+ A ROS message type representing a single PointStamped.
+
+ .. attribute:: header
+
+ The header associated with the point.
+
+ :type: :class:`Header`
+
+ .. attribute:: point
+
+ The position associated with the point
+
+ :type: :class:`Point`
+
+Vector3
+~~~~~~~
+
+.. attributetable:: geometry_msgs.msg.Vector3
+
+.. class:: geometry_msgs.msg.Vector3
+
+ A ROS message type representing a three-dimensional vector.
+
+ .. attribute:: x
+
+ The x-value of the vector.
+
+ :type: :class:`float`
+
+ .. attribute:: y
+
+ The y-value of the vector.
+
+ :type: :class:`float`
+
+ .. attribute:: z
+
+ The z-value of the vector.
+
+ :type: :class:`float`
+
+Pose
+~~~~
+
+.. attributetable:: geometry_msgs.msg.Pose
+
+.. class:: geometry_msgs.msg.Pose
+
+ A ROS message type representing an object's pose.
+
+ .. attribute:: position
+
+ The position of the pose.
+
+ :type: ~geometry_msgs.msg.Pose
+
+ .. attribute:: orientation
+
+ The orientation of the pose.
+
+ :type: ~geometry_msgs.msg.Quaternion
+
+Pose2D
+~~~~~~
+
+.. attributetable:: geometry_msgs.msg.Pose2D
+
+.. class:: geometry_msgs.msg.Pose2D
+
+ A ROS message type representing an object's pose in two dimensions.
+
+ .. attribute:: x
+
+ The x-value of the pose.
+
+ :type: float
+
+ .. attribute:: y
+
+ The y-value of the pose.
+
+ :type: float
+
+ .. attribute:: theta
+
+ The theta value of the pose.
+
+ :type: float
+
+PoseWithCovariance
+~~~~~~~~~~~~~~~~~~
+
+.. attributetable:: geometry_msgs.msg.PoseWithCovariance
+
+.. class:: geometry_msgs.msg.PoseWithCovariance
+
+ A ROS message type representing an object's pose, along with a covariance.
+
+ .. attribute:: pose
+
+ The object's pose.
+
+ :type: ~geometry_msgs.msg.Pose
+
+ .. attribute:: covariance
+
+ The object's covariance. Consists of a list of 36 values.
+
+ :type: List[float]
+
+Transform
+~~~~~~~~~
+
+.. attributetable:: geometry_msgs.msg.Transform
+
+.. class:: geometry_msgs.msg.Transform
+
+ A ROS message type representing an object's transform.
+
+ .. attribute:: translation
+
+ The translation of the transform.
+
+ :type: ~geometry_msgs.msg.Vector3
+
+ .. attribute:: rotation
+
+ The rotation of the transform.
+
+ :type: ~geometry_msgs.msg.Quaternion
+
+TransformStamped
+~~~~~~~~~~~~~~~~
+
+.. attributetable:: geometry_msgs.msg.TransformStamped
+
+.. class:: geometry_msgs.msg.TransformStamped
+
+ A stamped ROS message type representing an object's transform.
+
+ .. attribute:: header
+
+ The header of the message.
+
+ :type: ~std_msgs.msg.Header
+
+ .. attribute:: child_frame_id
+
+ The ID of the child frame.
+
+ :type: str
+
+ .. attribute:: transform
+
+ The transform in the message.
+
+ :type: ~geometry_msgs.msg.Transform
+
+Accel
+~~~~~
+
+.. attributetable:: geometry_msgs.msg.Accel
+
+.. class:: geometry_msgs.msg.Accel
+
+ A ROS message type representing an object's acceleration.
+
+ .. attribute:: linear
+
+ The linear acceleration of the twist.
+
+ :type: ~geometry_msgs.msg.Vector3
+
+ .. attribute:: angular
+
+ The angular acceleration of the twist.
+
+ :type: ~geometry_msgs.msg.Vector3
+
+Twist
+~~~~~
+
+.. attributetable:: geometry_msgs.msg.Twist
+
+.. class:: geometry_msgs.msg.Twist
+
+ A ROS message type representing an object's twist.
+
+ .. attribute:: linear
+
+ The linear direction of the twist.
+
+ :type: ~geometry_msgs.msg.Vector3
+
+ .. attribute:: angular
+
+ The angular direction of the twist.
+
+ :type: ~geometry_msgs.msg.Vector3
+
+TwistWithCovariance
+~~~~~~~~~~~~~~~~~~~
+
+.. attributetable:: geometry_msgs.msg.TwistWithCovariance
+
+.. class:: geometry_msgs.msg.TwistWithCovariance
+
+ A ROS message type representing an object's twist, along with a covariance.
+
+ .. attribute:: twist
+
+ The object's twist.
+
+ :type: ~geometry_msgs.msg.Twist
+
+ .. attribute:: covariance
+
+ The object's covariance. Consists of a list of 36 values.
+
+ :type: List[float]
+
+Polygon
+~~~~~~~
+
+.. attributetable:: geometry_msgs.msg.Polygon
+
+.. class:: geometry_msgs.msg.Polygon
+
+ A ROS message type representing a polygon.
+
+ .. attribute:: points
+
+ The points constructing the polygon.
+
+ :type: List[~geometry_msgs.msg.Point]
+
+Wrench
+~~~~~~
+
+.. attributetable:: geometry_msgs.msg.Wrench
+
+.. class:: geometry_msgs.msg.Wrench
+
+ A ROS message type representing the wrench of an object.
+
+ .. attribute:: force
+
+ The force associated with the object.
+
+ :type: ~geometry_msgs.msg.Vector3
+
+ .. attribute:: torque
+
+ The torque associated with the object.
+
+ :type: ~geometry_msgs.msg.Vector3
+
+WrenchStamped
+~~~~~~~~~~~~~
+
+.. attributetable:: geometry_msgs.msg.WrenchStamped
+
+.. class:: geometry_msgs.msg.WrenchStamped
+
+ A ROS message type representing the wrench of an object with an associated header.
+
+ .. attribute:: header
+
+ The header associated with the message.
+
+ :type: ~std_msgs.msg.Header
+
+ .. attribute:: wrench
+
+ The wrench associated with the object.
+
+ :type: ~geometry_msgs.msg.Wrench
+
+MIL Messages
+^^^^^^^^^^^^
+
+PoseTwist
+~~~~~~~~~
+
+.. attributetable:: mil_msgs.msg.PoseTwist
+
+.. class:: mil_msgs.msg.PoseTwist
+
+ A ROS message type representing an object's pose and twist.
+
+ .. attribute:: pose
+
+ The pose of the object.
+
+ :type: ~geometry_msgs.msg.Pose
+
+ .. attribute:: twist
+
+ The twist of the object.
+
+ :type: ~geometry_msgs.msg.Twist
+
+ .. attribute:: acceleration
+
+ The acceleration of the object.
+
+ :type: ~geometry_msgs.msg.Accel
+
+ObjectInImage
+~~~~~~~~~~~~~
+
+.. attributetable:: mil_msgs.msg.ObjectInImage
+
+.. class:: mil_msgs.msg.ObjectInImage
+
+ A ROS message type representing the position of an object in an image.
+
+ .. attribute:: name
+
+ The name of the object.
+
+ :type: str
+
+ .. attribute:: points
+
+ The center of the object in the image.
+
+ :type: ~mil_msgs.msg.Point2D
+
+ .. attribute:: confidence
+
+ The confidence of the object's position, ranging between 0 and 1.
+
+ :type: float
+
+ .. attribute:: attributes
+
+ ???
+
+ :type: str
+
+Point2D
+~~~~~~~
+
+.. attributetable:: mil_msgs.msg.Point2D
+
+.. class:: mil_msgs.msg.Point2D
+
+ A ROS message type representing an x and y position in a 2D space.
+
+ .. attribute:: x
+
+ The x-position.
+
+ :type: float
+
+ .. attribute:: y
+
+ The y-position.
+
+ :type: float
+
+Navigation Messages
+^^^^^^^^^^^^^^^^^^^
+
+Odometry
+~~~~~~~~
+
+.. attributetable:: nav_msgs.msg.Odometry
+
+.. class:: nav_msgs.msg.Odometry
+
+ A ROS message type representing an object's odometry.
+
+ .. attribute:: header
+
+ The message header.
+
+ :type: ~std_msgs.msg.Header
+
+ .. attribute:: child_frame_id
+
+ The child frame ID, used to determine the frame of the robot's twist.
+
+ :type: ~geometry_msgs.msg.Twist
+
+ .. attribute:: pose
+
+ The pose (along with covariance) determined within the frame of :attr:`~std_msgs.msg.Header.frame_id`.
+
+ :type: ~geometry_msgs.msg.PoseWithCovariance
+
+ .. attribute:: twist
+
+ The twist (along with covariance) determined within the frame of :attr:`~nav_msgs.msg.Odometry.child_frame_id`.
+
+ :type: ~geometry_msgs.msg.TwistWithCovariance
+
+Acceleration
+~~~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.Acceleration
+
+.. class:: navigator_msgs.msg.Acceleration
+
+ .. attribute:: linear
+
+ The linear component of the acceleration.
+
+ :type: Vector3
+
+ .. attribute:: angular
+
+ The angular component of the acceleration.
+
+ :type: Vector3
+
+KillStatus
+~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.KillStatus
+
+.. class:: navigator_msgs.msg.KillStatus
+
+ A custom message to represent information about a kill induced on the robot.
+
+ .. attribute:: overall
+
+ :type: bool
+
+ .. attribute:: pf
+
+ :type: bool
+
+ .. attribute:: pa
+
+ :type: bool
+
+ .. attribute:: sf
+
+ :type: bool
+
+ .. attribute:: sa
+
+ :type: bool
+
+ .. attribute:: remote
+
+ :type: bool
+
+ .. attribute:: computer
+
+ :type: bool
+
+ .. attribute:: remote_conn
+
+ :type: bool
+
+PerceptionObject
+~~~~~~~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.PerceptionObject
+
+.. class:: navigator_msgs.msg.PerceptionObject
+
+ A custom message definition to represent an object found by the perception
+ system.
+
+ .. attribute:: header
+
+ The message header.
+
+ :type: Header
+
+ .. attribute:: name
+
+ The name of the object.
+
+ :type: str
+
+ .. attribute:: DETECT_DELIVER_PLATFORM
+
+ The constant string field representing the platform to detect and deliver.
+ Actual string value is ``shooter``.
+
+ :type: str
+
+ .. attribute:: IDENTIFY_AND_DOCK
+
+ The constant string field representing the dock in the Identify and Dock mission.
+ Actual string value is ``dock``.
+
+ :type: str
+
+ .. attribute:: SCAN_THE_CODE
+
+ The constant string field representing the Scan the Code totem. Actual
+ string value is ``scan_the_code``.
+
+ :type: str
+
+ .. attribute:: TOTEM
+
+ The constant string field representing the totem in the Find Totems mission.
+ Actual string value is ``totem``.
+
+ :type: str
+
+ .. attribute:: START_GATE_BUOY
+
+ The constant string field representing the buoy of the start gate.
+ Actual string value is ``start_gate``.
+
+ :type: str
+
+ .. attribute:: BUOY
+
+ The constant string field representing a buoy.
+ Actual string value is ``buoy``.
+
+ :type: str
+
+ .. attribute:: UNKNOWN
+
+ The constant string field representing an unknown object.
+ Actual string value is ``unknown``.
+
+ :type: str
+
+ .. attribute:: ALL
+
+ The constant string field representing all objects found.
+ Actual string value is ``all``.
+
+ :type: str
+
+ .. attribute:: FAKE_SHOOTER
+
+ The constant string field representing a fake shooter.
+ Actual string value is ``Shooter``.
+
+ :type: str
+
+ .. attribute:: FAKE_IDENTIFY_AND_DOCK
+
+ The constant string field representing a fake dock in the Identify and Dock mission.
+ Actual string value is ``Dock``.
+
+ :type: str
+
+ .. attribute:: FAKE_SCAN_THE_CODE
+
+ The constant string field representing a fake Scan the Code totem in the
+ Scan the Code mission. Actual string value is ``Dock``.
+
+ :type: str
+
+ .. attribute:: GATE1
+
+ The constant string field representing the first gate.
+ Actual string value is ``Gate_1``.
+
+ :type: str
+
+ .. attribute:: GATE2
+
+ The constant string field representing the first gate.
+ Actual string value is ``Gate_2``.
+
+ :type: str
+
+ .. attribute:: GATE3
+
+ The constant string field representing the first gate.
+ Actual string value is ``Gate_3``.
+
+ :type: str
+
+ .. attribute:: BUOY_FIELD
+
+ The constant string field representing a field of buoys.
+ Actual string value is ``BuoyField``.
+
+ :type: str
+
+ .. attribute:: FIND_THE_BREAK
+
+ The constant string field representing ???.
+ Actual string value is ``FindBreak``.
+
+ :type: str
+
+ .. attribute:: CORAL_SURVEY
+
+ The constant string field representing ???.
+ Actual string value is ``CoralSurvey``.
+
+ :type: str
+
+ .. attribute:: ACOUSTIC_PINGER
+
+ The constant string field representing an acoustic pinger.
+ Actual string value is ``AcousticPinger``.
+
+ :type: str
+
+ .. attribute:: EMPTY_SPACE
+
+ The constant string field representing empty space.
+ Actual string value is ``EmptySpace``.
+
+ :type: str
+
+ .. attribute:: position
+
+ Estimated position of the object.
+
+ :type: Point
+
+ .. attribute:: id
+
+ The ID of the object.
+
+ :type: int
+
+ .. attribute:: confidence
+
+ The confidence of the object detection, from 0 to 255.
+
+ :type: int
+
+ .. attribute:: size
+
+ The size of the object in all dimensions.
+
+ :type: Vector3
+
+ .. attribute:: points
+
+ The points (in the ENU frame) that belong to the buoy.
+
+ :type: List[Point32]
+
+ .. attribute:: intensity
+
+ The intensity of each point in the ENU frame.
+
+ :type: List[int]
+
+ .. attribute:: pclInliers
+
+ The inliners for the PCL plane fitting algorithm.
+
+ :type: int
+
+ .. attribute:: normal
+
+ Unit vector for normal to one of the vertical planes of the object.
+
+ :type: Vector3
+
+ .. attribute:: color
+
+ Average color of the buoy.
+
+ :type: ColorRGBA
+
+PerceptionObjectArray
+~~~~~~~~~~~~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.PerceptionObjectArray
+
+.. class:: navigator_msgs.msg.PerceptionObjectArray
+
+ A custom message definition to represent an array of perception objects.
+
+ .. attribute:: objects
+
+ The objects in the array.
+
+ :type: List[PerceptionObject]
+
+Networking Messages
+^^^^^^^^^^^^^^^^^^^
+
+Host
+~~~~
+
+.. attributetable:: navigator_msgs.msg.Host
+
+.. class:: navigator_msgs.msg.Host
+
+ A custom message definition responsible for associating a hostname and IP
+ address with a status.
+
+ .. attribute:: hostname
+
+ The name of the host.
+
+ :type: str
+
+ .. attribute:: ip
+
+ The IP address of the host.
+
+ :type: str
+
+ .. attribute:: status
+
+ The status of the host.
+
+ :type: str
+
+Hosts
+~~~~~
+
+.. attributetable:: navigator_msgs.msg.Hosts
+
+.. class:: navigator_msgs.msg.Hosts
+
+ A custom message definition representing a group of hosts together.
+
+ .. attribute:: hostnames
+
+ A custom, constant string representing a group of hostnames. The string is
+ equal to:
+
+ mil-nav-wamv mil-nav-ubnt-wamv mil-nav-ubnt-shore mil-com-velodyne-vlp16 mil-com-sick-lms111
+
+ :type: str
+
+ .. attribute:: hosts
+
+ The hosts belonging to the group.
+
+ :type: List[~navigator_msgs.msg.Host]
+
+Passive Sonar Messages
+^^^^^^^^^^^^^^^^^^^^^^
+
+HydrophoneSamples
+~~~~~~~~~~~~~~~~~
+
+.. attributetable:: mil_passive_sonar.msg.HydrophoneSamples
+
+.. class:: mil_passive_sonar.msg.HydrophoneSamples
+
+ A custom message definition to represent data coming from the hydrophones.
+
+ .. attribute:: channels
+
+ The number of channels supported by the hydrophones.
+
+ :type: int
+
+ .. attribute:: samples
+
+ The number of samples on each channel.
+
+ :type: int
+
+ .. attribute:: sample_rate
+
+ The rate at which samples are recorded, per channel. Equal to the number
+ of samples per second.
+
+ :type: int
+
+ .. attribute:: data
+
+ The data recorded from the hydrophones. Each "word" in the data is a piece
+ of data from one hydrophone, such as ``H0 H1 H2 H3 H0 H1 ...``.
+
+ :type: List[int]
+
+HydrophoneSamplesStamped
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. attributetable:: mil_passive_sonar.msg.HydrophoneSamplesStamped
+
+.. class:: mil_passive_sonar.msg.HydrophoneSamplesStamped
+
+ A custom message definition to represent time-stamped data coming from the hydrophones.
+
+ .. attribute:: header
+
+ The message header.
+
+ :type: Header
+
+ .. attribute:: hydrophone_samples
+
+ The hydrophone samples received.
+
+ :type: HydrophoneSamples
+
+Ping
+~~~~
+
+.. attributetable:: mil_passive_sonar.msg.Ping
+
+.. class:: mil_passive_sonar.msg.Ping
+
+ A custom message definition to represent a ping from channels of data.
+
+ .. danger::
+
+ This class is deprecated, and has been replaced by
+ :class:`~mil_passive_sonar.msg.HydrophoneSamples` and
+ :class:`~mil_passive_sonar.msg.HydrophoneSamplesStamped`.
+ Support for this message type throughout the repository still exists,
+ although it may be removed in the future.
+
+ .. attribute:: header
+
+ The message header.
+
+ :type: Header
+
+ .. attribute:: channels
+
+ The number of channels supported by the hydrophones.
+
+ :type: int
+
+ .. attribute:: samples
+
+ The number of samples on each channel.
+
+ :type: int
+
+ .. attribute:: sample_rate
+
+ The rate at which samples are recorded, per channel. Equal to the number
+ of samples per second.
+
+ :type: int
+
+ .. attribute:: data
+
+ The data recorded from the hydrophones. Each "word" in the data is a piece
+ of data from one hydrophone, such as ``H0 H1 H2 H3 H0 H1 ...``.
+
+ :type: List[int]
+
+ProcessedPing
+~~~~~~~~~~~~~
+
+.. attributetable:: mil_passive_sonar.msg.ProcessedPing
+
+.. class:: mil_passive_sonar.msg.ProcessedPing
+
+ A custom message definition to represent a ping from channels of data.
+
+ .. attribute:: header
+
+ The message header.
+
+ :type: Header
+
+ .. attribute:: position
+
+ The position of the processed ping.
+
+ :type: Point
+
+ .. attribute:: freq
+
+ The frequency of the processed ping.
+
+ :type: float
+
+ .. attribute:: amplitude
+
+ The amplitude of the processed ping.
+
+ :type: float
+
+ .. attribute:: valid
+
+ Whether the processed ping is valid.
+
+ :type: bool
+
+Triggered
+~~~~~~~~~
+
+.. attributetable:: mil_passive_sonar.msg.Triggered
+
+.. class:: mil_passive_sonar.msg.Triggered
+
+ A custom message definition to represent ???.
+
+ .. attribute:: header
+
+ The message header.
+
+ :type: Header
+
+ .. attribute:: hydrophone_samples
+
+ ???
+
+ :type: HydrophoneSamples
+
+ .. attribute:: trigger_time
+
+ The time at which the ping was detected.
+
+ :type: float
+
+Standard Messages
+^^^^^^^^^^^^^^^^^
+
+Header
+~~~~~~
+
+.. attributetable:: std_msgs.msg.Header
+
+.. class:: std_msgs.msg.Header
+
+ A ROS message type representing the header of a message. Used throughout a
+ variety of messages.
+
+ .. attribute:: seq
+
+ The sequence ID of the header. A consecutively increasing ID.
+
+ :type: int
+
+ .. attribute:: time
+
+ The time of the message.
+
+ :type: genpy.rostime.Time
+
+ .. attribute:: frame_id
+
+ The frame that this object is associated with.
+
+ :type: str
+
+ColorRGBA
+~~~~~~~~~
+
+.. attributetable:: std_msgs.msg.ColorRGBA
+
+.. class:: std_msgs.msg.ColorRGBA
+
+ A ROS message type representing a color with RGB and an alpha channel.
+
+ .. attribute:: r
+
+ The red value of the color.
+
+ :type: float
+
+ .. attribute:: g
+
+ The green value of the color.
+
+ :type: float
+
+ .. attribute:: b
+
+ The blue value of the color.
+
+ :type: float
+
+ .. attribute:: a
+
+ The alpha value of the color.
+
+ :type: float
+
+Sensor Messages
+^^^^^^^^^^^^^^^
+
+Image
+~~~~~
+
+.. attributetable:: sensor_msgs.msg.Image
+
+.. class:: sensor_msgs.msg.Image
+
+ A ROS message to represent an image.
+
+ .. attribute:: header
+
+ The header associated with the message.
+
+ :type: Header
+
+ .. attribute:: height
+
+ The height of the image.
+
+ :type: int
+
+ .. attribute:: width
+
+ The width of the image.
+
+ :type: int
+
+ .. attribute:: encoding
+
+ The encoding of the image.
+
+ :type: str
+
+ .. attribute:: is_bigendian
+
+ Whether the image uses the big-endian format to store values.
+
+ :type: bool
+
+ .. attribute:: step
+
+ Full length of a row, in bytes.
+
+ :type: int
+
+ .. attribute:: data
+
+ Actual image data. The size of the list is equal to :attr:`.step` multiplied
+ by the number of rows.
+
+ :type: List[int]
+
+PointField
+~~~~~~~~~~
+
+.. attributetable:: sensor_msgs.msg.PointField
+
+.. class:: sensor_msgs.msg.PointField
+
+ A ROS message type to represent a field in a point cloud.
+
+ .. attribute:: INT8
+
+ Constant of the data type that can be used to represent the data type of a
+ value in the field. Set to ``1`` in the message definition.
+
+ :type: int
+
+ .. attribute:: UINT8
+
+ Constant of the data type that can be used to represent the data type of a
+ value in the field. Set to ``2`` in the message definition.
+
+ :type: int
+
+ .. attribute:: INT16
+
+ Constant of the data type that can be used to represent the data type of a
+ value in the field. Set to ``3`` in the message definition.
+
+ :type: int
+
+ .. attribute:: UINT16
+
+ Constant of the data type that can be used to represent the data type of a
+ value in the field. Set to ``4`` in the message definition.
+
+ :type: int
+
+ .. attribute:: INT32
+
+ Constant of the data type that can be used to represent the data type of a
+ value in the field. Set to ``5`` in the message definition.
+
+ :type: int
+
+ .. attribute:: UINT32
+
+ Constant of the data type that can be used to represent the data type of a
+ value in the field. Set to ``6`` in the message definition.
+
+ :type: int
+
+ .. attribute:: FLOAT32
+
+ Constant of the data type that can be used to represent the data type of a
+ value in the field. Set to ``7`` in the message definition.
+
+ :type: int
+
+ .. attribute:: FLOAT64
+
+ Constant of the data type that can be used to represent the data type of a
+ value in the field. Set to ``8`` in the message definition.
+
+ :type: int
+
+ .. attribute:: name
+
+ The name of the field.
+
+ :type: str
+
+ .. attribute:: offset
+
+ The offset from the start of the point struct.
+
+ :type: int
+
+ .. attribute:: datatype
+
+ The datatype, represented by using one of the attributes above.
+
+ :type: int
+
+ .. attribute:: count
+
+ The number of elements in the field.
+
+ :type: int
+
+PointCloud2
+~~~~~~~~~~~
+
+.. attributetable:: sensor_msgs.msg.PointCloud2
+
+.. class:: sensor_msgs.msg.PointCloud2
+
+ A ROS message type indicating a point cloud.
+
+ .. attribute:: header
+
+ The message header.
+
+ :type: Header
+
+ .. attribute:: height
+
+ The height of the point cloud. If the cloud is unordered, then ``1``.
+
+ :type: int
+
+ .. attribute:: width
+
+ The width of the point cloud. If the cloud is unordered, then this value
+ is set to the length of the point cloud.
+
+ :type: int
+
+ .. attribute:: fields
+
+ The fields in the point cloud.
+
+ :type: List[PointField]
+
+ .. attribute:: is_bigendian
+
+ Whether the field is big endian.
+
+ :type: bool
+
+ .. attribute:: point_step
+
+ The length of a point in bytes.
+
+ :type: int
+
+ .. attribute:: row_step
+
+ The length of a row in bytes.
+
+ :type: int
+
+ .. attribute:: data
+
+ The actual data inside the point cloud. The size of the array is :attr:`~sensor_msgs.msg.PointCloud2.row_step`
+ multiplied by :attr:`~sensor_msgs.msg.PointCloud2.height`.
+
+ :type: List[int]
+
+ .. attribute:: is_dense
+
+ ``True`` if there are no invalid points.
+
+ :type: bool
+
+Motor Feedback
+~~~~~~~~~~~~~~
+.. attributetable:: roboteq_msgs.msg.Feedback
+
+.. class:: roboteq_msgs.msg.Feedback
+
+ A third-party ROS message type for getting feedback from motor controllers.
+
+ .. attribute:: header
+
+ The header of the message.
+
+ :type: Header
+
+ .. attribute:: motor_current
+
+ Current flowing through the motors.
+
+ :type: float
+
+ .. attribute:: motor_power
+
+ Relative motor power, as a proportion of the full motor power.
+ Lives in a range from -1 to 1.
+
+ :type: float
+
+ .. attribute:: commanded_velocity
+
+ The velocity commanded of the motor. Output is in ``rad/s``.
+
+ :type: float
+
+ .. attribute:: measured_velocity
+
+ The true velocity of the motor. Output is in ``rad/s``.
+
+ :type: float
+
+ .. attribute:: measured_position
+
+ The position of the motor, in ``rad``. Wraps around -6/6M.
+
+ :type: float
+
+ .. attribute:: supply_voltage
+
+ The voltage supplied to the motor, in volts.
+
+ :type: float
+
+ .. attribute:: supply_current
+
+ The current supplied to the motor, in amps.
+
+ :type: float
+
+ .. attribute:: motor_temperature
+
+ The temperature of the motor, in Celsius.
+
+ :type: float
+
+ .. attribute:: channel_temperature
+
+ The temperature of the FETs, as reported by the controller. Units are in
+ Celsius.
+
+ :type: float
+
+Motor Status
+~~~~~~~~~~~~
+.. attributetable:: roboteq_msgs.msg.Status
+
+.. class:: roboteq_msgs.msg.Status
+
+ A third-party ROS message type for getting status from motor controllers.
+
+ .. attribute:: header
+
+ The header of the message.
+
+ :type: Header
+
+ .. attribute:: fault
+
+ A representation of any fault that occurred in the motor. Likely one of the
+ enumerated fault types of this class.
+
+ :type: int
+
+ .. attribute:: FAULT_OVERHEAT
+
+ Constant attribute used to represent that the motor experienced a fault
+ as a result of overheating.
+
+ :type: int
+ :value: 1
+
+ .. attribute:: FAULT_OVERVOLTAGE
+
+ Constant attribute used to represent that the motor experienced a fault
+ as a result of too much voltage.
+
+ :type: int
+ :value: 2
+
+ .. attribute:: FAULT_UNDERVOLTAGE
+
+ Constant attribute used to represent that the motor experienced a fault
+ as a result of too little voltage.
+
+ :type: int
+ :value: 4
+
+ .. attribute:: FAULT_SHORT_CIRCUIT
+
+ Constant attribute used to represent that the motor experienced a fault
+ as a result of a short circuit.
+
+ :type: int
+ :value: 8
+
+ .. attribute:: FAULT_EMERGENCY_STOP
+
+ Constant attribute used to represent that the motor experienced a fault
+ as a result of an emergency stop.
+
+ :type: int
+ :value: 16
+
+ .. attribute:: FAULT_SEPEX_EXCITATION_FAULT
+
+ Constant attribute used to represent that the motor experienced a fault
+ as a result of an excitation error.
+
+ :type: int
+ :value: 32
+
+ .. attribute:: FAULT_MOSFET_FAILURE
+
+ Constant attribute used to represent that the motor experienced a fault
+ as a result of a failure in the MOSFET system.
+
+ :type: int
+ :value: 64
+
+ .. attribute:: FAULT_STARTUP_CONFIG_FAULT
+
+ Constant attribute used to represent that the motor experienced a fault
+ as a result of a failure in the startup configuration.
+
+ :type: int
+ :value: 128
+
+ .. attribute:: status
+
+ The status of the motor. Likely set to a combination of the class' enumerated
+ types.
+
+ :type: int
+
+ .. attribute:: STATUS_SERIAL_MODE
+
+ Constant attribute used to represent that the motor is in serial mode.
+
+ :type: int
+ :value: 1
+
+ .. attribute:: STATUS_PULSE_MODE
+
+ Constant attribute used to represent that the motor is in pulse mode.
+
+ :type: int
+ :value: 2
+
+ .. attribute:: STATUS_ANALOG_MODE
+
+ Constant attribute used to represent that the motor is in analog mode.
+
+ :type: int
+ :value: 4
+
+ .. attribute:: STATUS_POWER_STAGE_OFF
+
+ Constant attribute used to represent that the power stage of the motor is
+ off.
+
+ :type: int
+ :value: 8
+
+ .. attribute:: STATUS_STALL_DETECTED
+
+ Constant attribute used to represent that a stall was detected.
+
+ :type: int
+ :value: 16
+
+ .. attribute:: STATUS_AT_LIMIT
+
+ Constant attribute used to represent that the motor is at its limit.
+
+ :type: int
+ :value: 32
+
+ .. attribute:: STATUS_MICROBASIC_SCRIPT_RUNNING
+
+ Constant attribute used to represent that the microbasic script is running.
+
+ :type: int
+ :value: 128
+
+ .. attribute:: ic_temperature
+
+ The temperature of the main logic chip, in Celsius.
+
+ :type: float
+
+ .. attribute:: internal_voltage
+
+ The internal voltage, in volts.
+
+ :type: float
+
+ .. attribute:: adc_voltage
+
+ The voltage of the analog-to-digital converter, in volts.
+
+ :type: float
+
+VRX Messages
+^^^^^^^^^^^^
+
+DockShape
+~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.DockShape
+
+.. class:: navigator_msgs.msg.DockShape
+
+ .. attribute:: Shape
+
+ The shape of the dock. Likely either :attr:`DockShape.CROSS`, :attr:`DockShape.CIRCLE`,
+ or :attr:`DockShape.TRIANGLE`.
+
+ :type: str
+
+ .. attribute:: CROSS
+
+ The dock holds the cross shape.
+
+ :type: str
+
+ .. attribute:: CIRCLE
+
+ The dock holds the circle shape.
+
+ :type: str
+
+ .. attribute:: TRIANGLE
+
+ The dock holds the triangle shape.
+
+ :type: str
+
+ .. attribute:: Color
+
+ The color of the dock. Likely either :attr:`DockShape.RED`, :attr:`DockShape.BLUE`,
+ or :attr:`DockShape.GREEN`.
+
+ :type: str
+
+ .. attribute:: RED
+
+ The dock shape is red.
+
+ :type: str
+
+ .. attribute:: BLUE
+
+ The dock shape is blue.
+
+ :type: str
+
+ .. attribute:: GREEN
+
+ The dock shape is green.
+
+ :type: str
+
+ .. attribute:: CenterX
+
+ The x-dimension of the center of the dock shape.
+
+ :type: int
+
+ .. attribute:: CenterY
+
+ The y-dimension of the center of the dock shape.
+
+ :type: int
+
+ .. attribute.. img_width
+
+ The width of the image showing the dock and its shape.
+
+ :type: int
+
+ .. attribute:: header
+
+ The message header.
+
+ :type: Header
+
+ .. attribute:: points
+
+ ???
+
+ :type: List[~geometry_msgs.msg.Point]
+
+ .. attribute:: color_confidence
+
+ The relative confidence that the color prediction is correct.
+
+ :type: float
+
+ .. attribute:: shape_confidence
+
+ The relative confidence that the shape prediction is correct.
+
+ :type: float
+
+DockShapes
+~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.DockShapes
+
+.. class:: navigator_msgs.msg.DockShapes
+
+ A custom message definition to represent the presence of multiple dock shapes
+ found by the vision system.
+
+ .. attribute:: list
+
+ The list of shapes found.
+
+ :type: List[DockShape]
+
+
+ScanTheCode
+~~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.msg.ScanTheCode
+
+.. class:: navigator_msgs.msg.ScanTheCode
+
+ A custom message definition to represent the color pattern show by a Scan The
+ Code totem.
+
+ .. attribute:: string_pattern
+
+ The pattern shown. ``R`` stands for red, ``B`` stands for blue, and ``G``
+ stands for green.
+
+ :type: str
diff --git a/docs/reference/mission/core.rst b/docs/reference/mission/core.rst
new file mode 100644
index 0000000..677179c
--- /dev/null
+++ b/docs/reference/mission/core.rst
@@ -0,0 +1,48 @@
+:mod:`mil_missions_core` - Base mission classes
+-----------------------------------------------
+
+.. automodule:: mil_missions_core
+
+BaseMission
+^^^^^^^^^^^
+.. attributetable:: mil_missions_core.BaseMission
+
+.. autoclass:: mil_missions_core.BaseMission
+ :members:
+
+ChainWithTimeout
+^^^^^^^^^^^^^^^^
+.. autofunction:: mil_missions_core.MakeChainWithTimeout
+
+Exceptions
+^^^^^^^^^^
+.. attributetable:: mil_missions_core.MissionException
+
+.. autoclass:: mil_missions_core.MissionException
+ :members:
+
+.. attributetable:: mil_missions_core.TimeoutException
+
+.. autoclass:: mil_missions_core.TimeoutException
+ :members:
+
+.. attributetable:: mil_missions_core.ParametersException
+
+.. autoclass:: mil_missions_core.ParametersException
+ :members:
+
+.. attributetable:: mil_missions_core.SubmissionException
+
+.. autoclass:: mil_missions_core.SubmissionException
+ :members:
+
+MissionClient
+^^^^^^^^^^^^^
+.. attributetable:: mil_missions_core.MissionClient
+
+.. autoclass:: mil_missions_core.MissionClient
+ :members:
+
+MakeWait
+^^^^^^^^
+.. autofunction:: mil_missions_core.MakeWait
diff --git a/docs/reference/mission/index.rst b/docs/reference/mission/index.rst
new file mode 100644
index 0000000..d56e4c9
--- /dev/null
+++ b/docs/reference/mission/index.rst
@@ -0,0 +1,13 @@
+:mod:`mil_missions` - Mission System
+------------------------------------
+
+The mission system is used to run "missions", or client modules used to orchestrate
+the desired end behavior of the robot. Missions are commonly implemented to orchestrate
+the behavior of a robot in preparation for a competition. Usually, mission code
+will not be used in other parts of the repository; rather, other modules are used
+by mission code.
+
+.. toctree::
+ :maxdepth: 1
+
+ core
diff --git a/docs/reference/msghandlers.rst b/docs/reference/msghandlers.rst
new file mode 100644
index 0000000..f17592c
--- /dev/null
+++ b/docs/reference/msghandlers.rst
@@ -0,0 +1,47 @@
+Message Handlers
+----------------
+.. currentmodule:: mil_tools
+
+.. autofunction:: pose_to_numpy
+
+.. autofunction:: twist_to_numpy
+
+.. autofunction:: posetwist_to_numpy
+
+.. autofunction:: odometry_to_numpy
+
+.. autofunction:: wrench_to_numpy
+
+.. autofunction:: numpy_to_point
+
+.. autofunction:: numpy_to_point2d
+
+.. autofunction:: numpy_to_quaternion
+
+.. autofunction:: numpy_to_twist
+
+.. autofunction:: numpy_to_wrench
+
+.. autofunction:: numpy_matrix_to_quaternion
+
+.. autofunction:: numpy_pair_to_pose
+
+.. autofunction:: numpy_quat_pair_to_pose
+
+.. autofunction:: numpy_to_points
+
+.. autofunction:: numpy_to_polygon
+
+.. autofunction:: numpy_to_vector3
+
+.. autofunction:: numpy_to_pose2D
+
+.. autofunction:: numpy_to_colorRGBA
+
+.. autofunction:: numpy_to_pointcloud2
+
+.. autofunction:: make_header
+
+.. autofunction:: make_wrench_stamped
+
+.. autofunction:: make_pose_stamped
diff --git a/docs/reference/passivesonar.rst b/docs/reference/passivesonar.rst
new file mode 100644
index 0000000..7cd64ab
--- /dev/null
+++ b/docs/reference/passivesonar.rst
@@ -0,0 +1,69 @@
+:mod:`mil_passive_sonar` - Passive Sonar
+----------------------------------------
+
+.. currentmodule:: mil_passive_sonar
+
+Utility Functions
+^^^^^^^^^^^^^^^^^
+
+.. autofunction:: mil_passive_sonar.algorithms.run
+
+.. autofunction:: mil_passive_sonar.algorithms.zero_mean
+
+.. autofunction:: mil_passive_sonar.algorithms.normalize
+
+.. autofunction:: mil_passive_sonar.algorithms.compute_freq
+
+.. autofunction:: mil_passive_sonar.algorithms.bin_to_freq
+
+.. autofunction:: mil_passive_sonar.algorithms.freq_to_bin
+
+.. autofunction:: mil_passive_sonar.algorithms.preprocess
+
+.. autofunction:: mil_passive_sonar.algorithms.bandpass
+
+.. autofunction:: mil_passive_sonar.algorithms.compute_deltas
+
+.. autofunction:: mil_passive_sonar.algorithms.make_template
+
+.. autofunction:: mil_passive_sonar.algorithms.match_template
+
+.. autofunction:: mil_passive_sonar.algorithms.calculate_error
+
+.. autofunction:: mil_passive_sonar.algorithms.find_minimum
+
+.. autofunction:: mil_passive_sonar.algorithms.compute_pos_4hyd
+
+TxHydrophonesClient
+^^^^^^^^^^^^^^^^^^^
+.. attributetable:: TxHydrophonesClient
+
+.. autoclass:: TxHydrophonesClient
+ :members:
+
+StreamedBandpass
+^^^^^^^^^^^^^^^^
+.. attributetable:: mil_passive_sonar.streamed_bandpass.StreamedBandpass
+
+.. autoclass:: mil_passive_sonar.streamed_bandpass.StreamedBandpass
+ :members:
+
+HydrophoneTrigger
+^^^^^^^^^^^^^^^^^
+.. attributetable:: mil_passive_sonar.scripts.triggering.HydrophoneTrigger
+
+.. autoclass:: mil_passive_sonar.scripts.triggering.HydrophoneTrigger
+ :members:
+
+PingLocator
+^^^^^^^^^^^
+.. attributetable:: mil_passive_sonar.scripts.ping_locator.PingLocator
+
+.. autoclass:: mil_passive_sonar.scripts.ping_locator.PingLocator
+ :members:
+
+SylphaseSonarToRosNode
+^^^^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: SylphaseSonarToRosNode
+
+.. doxygenclass:: SylphaseSonarToRosNode
diff --git a/docs/reference/pathplanning.rst b/docs/reference/pathplanning.rst
new file mode 100644
index 0000000..c004804
--- /dev/null
+++ b/docs/reference/pathplanning.rst
@@ -0,0 +1,41 @@
+:mod:`lqrrt` - Path Planning
+----------------------------
+
+Constraints
+^^^^^^^^^^^
+
+.. currentmodule:: lqrrt
+
+.. attributetable:: lqrrt.Constraints
+
+.. autoclass:: lqrrt.Constraints
+ :members:
+
+Planner
+^^^^^^^
+
+.. currentmodule:: lqrrt
+
+.. attributetable:: lqrrt.Planner
+
+.. autoclass:: lqrrt.Planner
+ :members:
+
+Tree
+^^^^
+
+.. currentmodule:: lqrrt
+
+.. attributetable:: lqrrt.Tree
+
+.. autoclass:: lqrrt.Tree
+ :members:
+
+Node
+^^^^
+.. currentmodule:: lqrrt
+
+.. attributetable:: navigator_path_planner.nodes.path_planner.LQRRT_Node
+
+.. autoclass:: navigator_path_planner.nodes.path_planner.LQRRT_Node
+ :members:
diff --git a/docs/reference/pcodar.rst b/docs/reference/pcodar.rst
new file mode 100644
index 0000000..9fedbf3
--- /dev/null
+++ b/docs/reference/pcodar.rst
@@ -0,0 +1,94 @@
+``pcodar`` - Point Cloud Object Detection
+===============================================================================
+
+The PCODAR system is responsible for coordinating LIDAR data into a database of
+usable objects associated with locations.
+
+Type Aliases
+------------
+.. doxygentypedef:: pcodar::Config
+
+.. doxygentypedef:: pcodar::point_t
+
+.. doxygentypedef:: pcodar::point_cloud
+
+.. doxygentypedef:: pcodar::point_cloud_ptr
+
+.. doxygentypedef:: pcodar::point_cloud_const_ptr
+
+.. doxygentypedef:: pcodar::KdTree
+
+.. doxygentypedef:: pcodar::KdTreePtr
+
+.. doxygentypedef:: pcodar::cluster_t
+
+.. doxygentypedef:: pcodar::clusters_t
+
+Classes
+-------
+
+InputCloudFilter
+^^^^^^^^^^^^^^^^
+.. cppattributetable:: pcodar::InputCloudFilter
+
+.. doxygenclass:: pcodar::InputCloudFilter
+
+MarkerManager
+^^^^^^^^^^^^^
+.. cppattributetable:: pcodar::MarkerManager
+
+.. doxygenclass:: pcodar::MarkerManager
+
+Associator
+^^^^^^^^^^
+.. cppattributetable:: pcodar::Associator
+
+.. doxygenclass:: pcodar::Associator
+
+ObjectDetector
+^^^^^^^^^^^^^^
+.. cppattributetable:: pcodar::ObjectDetector
+
+.. doxygenclass:: pcodar::ObjectDetector
+
+Object
+^^^^^^
+.. cppattributetable:: pcodar::Object
+
+.. doxygenclass:: pcodar::Object
+
+ObjectMap
+^^^^^^^^^
+.. cppattributetable:: pcodar::ObjectMap
+
+.. doxygenclass:: pcodar::ObjectMap
+
+OgridManager
+^^^^^^^^^^^^
+.. cppattributetable:: pcodar::OgridManager
+
+.. doxygenclass:: pcodar::OgridManager
+
+NodeBase
+^^^^^^^^
+.. cppattributetable:: pcodar::NodeBase
+
+.. doxygenclass:: pcodar::NodeBase
+
+Node
+^^^^
+.. cppattributetable:: pcodar::Node
+
+.. doxygenclass:: pcodar::Node
+
+PersistentCloudFilter
+^^^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: pcodar::PersistentCloudFilter
+
+.. doxygenclass:: pcodar::PersistentCloudFilter
+
+PointCloudCircularBuffer
+^^^^^^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: pcodar::PointCloudCircularBuffer
+
+.. doxygenclass:: pcodar::PointCloudCircularBuffer
diff --git a/docs/reference/pneumatic.rst b/docs/reference/pneumatic.rst
new file mode 100644
index 0000000..2d428c2
--- /dev/null
+++ b/docs/reference/pneumatic.rst
@@ -0,0 +1,37 @@
+:mod:`mil_pneumatic_actuator` - Pneumatic Actuator Board
+--------------------------------------------------------
+
+Exceptions
+^^^^^^^^^^
+.. autoclass:: mil_pneumatic_actuator.PnuematicActuatorDriverError
+ :members:
+
+.. autoclass:: mil_pneumatic_actuator.PnuematicActuatorDriverChecksumError
+ :members:
+
+.. autoclass:: mil_pneumatic_actuator.PnuematicActuatorDriverResponseError
+ :members:
+
+.. autoclass:: mil_pneumatic_actuator.PnuematicActuatorTimeoutError
+ :members:
+
+PneumaticActuatorDriver
+^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: mil_pneumatic_actuator.PnuematicActuatorDriver
+
+.. autoclass:: mil_pneumatic_actuator.PnuematicActuatorDriver
+ :members:
+
+Pneumatic Board Constants
+^^^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: mil_pneumatic_actuator.Constants
+
+.. autoclass:: mil_pneumatic_actuator.Constants
+ :members:
+
+SimulatedPnuematicActuatorBoard
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: mil_pneumatic_actuator.SimulatedPnuematicActuatorBoard
+
+.. autoclass:: mil_pneumatic_actuator.SimulatedPnuematicActuatorBoard
+ :members:
diff --git a/docs/reference/poi.rst b/docs/reference/poi.rst
new file mode 100644
index 0000000..38cd511
--- /dev/null
+++ b/docs/reference/poi.rst
@@ -0,0 +1,47 @@
+:mod:`mil_poi` - POI Handling
+-----------------------------
+
+.. automodule:: mil_poi
+
+Using with Rviz
+^^^^^^^^^^^^^^^
+To view and interactive with interactive marker POIs in Rviz, you will need to enable
+the "Interactive Markers" panel in Rviz. You will then need to set the update topic
+to be equal to the update topic published by the interactive marker server published
+by the POI server. This topic name will likely end in ``/update``.
+
+All POIs are represented as spheres in the interactive marker server; you can move
+these spheres around to change their location. Note that points are currently
+fixed to the x and y axes, meaning that you can not have floating or submerged points.
+
+Configuration Files
+^^^^^^^^^^^^^^^^^^^
+When the POI server is launched, it is provided with several ROS parameters to
+describe how the server should function. This includes POIs that are spawned by
+default upon server initialization.
+
+The default format of the POI configuration file is the following format:
+
+.. code-block:: yaml
+
+ ---
+ global_frame: enu # Name of the frame to derive POI locations from
+ initial_pois: # List of POIs that are spawned by default
+ # Name (key) and location (position & orientation) (value) of specific POIs
+ start_gate: [0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0]
+ # ... or just position only (quaternion of [0, 0, 0, 0] assumed)
+ position_only: [0, 0, 0]
+
+POIServer
+^^^^^^^^^
+.. attributetable:: mil_poi.POIServer
+
+.. autoclass:: mil_poi.POIServer
+ :members:
+
+AsyncPOIClient
+^^^^^^^^^^^^^^
+.. attributetable:: mil_poi.AsyncPOIClient
+
+.. autoclass:: mil_poi.AsyncPOIClient
+ :members:
diff --git a/docs/reference/rc.rst b/docs/reference/rc.rst
new file mode 100644
index 0000000..582fe58
--- /dev/null
+++ b/docs/reference/rc.rst
@@ -0,0 +1,7 @@
+:mod:`remote_control_lib` - Remote Control
+------------------------------------------
+
+.. attributetable:: remote_control_lib.RemoteControl
+
+.. autoclass:: remote_control_lib.RemoteControl
+ :members:
diff --git a/docs/reference/resources.rst b/docs/reference/resources.rst
new file mode 100644
index 0000000..3d15211
--- /dev/null
+++ b/docs/reference/resources.rst
@@ -0,0 +1,16 @@
+Resource Management
+-------------------
+
+Threads
+^^^^^^^
+
+.. autofunction:: mil_tools.thread_lock
+
+
+ROS Resources
+^^^^^^^^^^^^^
+.. autofunction:: mil_tools.wait_for_param
+
+.. autofunction:: mil_tools.wait_for_subscriber
+
+.. autofunction:: mil_tools.wait_for_service
diff --git a/docs/reference/rviz.rst b/docs/reference/rviz.rst
new file mode 100644
index 0000000..58ca259
--- /dev/null
+++ b/docs/reference/rviz.rst
@@ -0,0 +1,34 @@
+rviz
+----
+
+.. currentmodule:: mil_tools
+
+Utility Functions
+^^^^^^^^^^^^^^^^^
+
+.. autofunction:: draw_sphere
+
+.. autofunction:: draw_ray_3d
+
+.. autofunction:: make_ray
+
+VectorToMarker
+^^^^^^^^^^^^^^
+.. attributetable:: mil_ros_tools.vector_to_marker.VectorToMarker
+
+.. autoclass:: mil_ros_tools.vector_to_marker.VectorToMarker
+ :members:
+
+ClickedPointRecorder
+^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: nodes.clicked_point_recorder.ClickedPointRecorder
+
+.. autoclass:: nodes.clicked_point_recorder.ClickedPointRecorder
+ :members:
+
+NetworkBroadcaster
+^^^^^^^^^^^^^^^^^^
+.. attributetable:: nodes.network_broadcaster.NetworkBroadcaster
+
+.. autoclass:: nodes.network_broadcaster.NetworkBroadcaster
+ :members:
diff --git a/docs/reference/sabertooth.rst b/docs/reference/sabertooth.rst
new file mode 100644
index 0000000..d761c05
--- /dev/null
+++ b/docs/reference/sabertooth.rst
@@ -0,0 +1,16 @@
+:mod:`sabertooth2x12` - Sabertooth 2x12
+---------------------------------------
+
+Sabertooth2x12
+^^^^^^^^^^^^^^
+.. attributetable:: sabertooth2x12.Sabertooth2x12
+
+.. autoclass:: sabertooth2x12.Sabertooth2x12
+ :members:
+
+SimulatedSabertooth2x12
+^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: sabertooth2x12.SimulatedSabertooth2x12
+
+.. autoclass:: sabertooth2x12.SimulatedSabertooth2x12
+ :members:
diff --git a/docs/reference/serial.rst b/docs/reference/serial.rst
new file mode 100644
index 0000000..9682121
--- /dev/null
+++ b/docs/reference/serial.rst
@@ -0,0 +1,22 @@
+Serial
+------
+
+Utility Functions
+^^^^^^^^^^^^^^^^^
+
+.. autofunction:: mil_tools.hexify
+
+NoopSerial
+^^^^^^^^^^
+
+.. attributetable:: mil_tools.NoopSerial
+
+.. autoclass:: mil_tools.NoopSerial
+ :members:
+
+SimulatedSerial
+^^^^^^^^^^^^^^^
+.. attributetable:: mil_tools.SimulatedSerial
+
+.. autoclass:: mil_tools.SimulatedSerial
+ :members:
diff --git a/docs/reference/services.rst b/docs/reference/services.rst
new file mode 100644
index 0000000..272686e
--- /dev/null
+++ b/docs/reference/services.rst
@@ -0,0 +1,1139 @@
+Services
+--------
+
+Mission Systems
+^^^^^^^^^^^^^^^
+
+AcousticBeacon
+~~~~~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.srv.AcousticBeaconRequest
+
+.. class:: navigator_msgs.srv.AcousticBeaconRequest
+
+ The request class for the ``navigator_msgs/AcousticBeacon`` service. The class
+ contains no settable attributes.
+
+.. attributetable:: navigator_msgs.srv.AcousticBeaconResponse
+
+.. class:: navigator_msgs.srv.AcousticBeaconResponse
+
+ The response class for the ``navigator_msgs/AcousticBeacon`` service.
+
+ .. attribute:: beacon_position
+
+ The position of the acoustic beacon.
+
+ :type: Point
+
+ .. attribute:: setValue
+
+ Whether the position data of the beacon is reliable enough to be used.
+
+ :type: bool
+
+ChooseAnimal
+~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.ChooseAnimalRequest
+
+.. class:: navigator_msgs.srv.ChooseAnimalRequest
+
+ The request class for the ``navigator_msgs/ChooseAnimal`` service.
+
+ .. attribute:: target_animal
+
+ The target animal to circle around. Should be ``platyus``, ``crocodile``,
+ or ``turtle``.
+
+ :type: str
+
+ .. attribute:: circle_direction
+
+ The direction to circle in. Should be ``clockwise`` or ``anti-clockwise``.
+
+ :type: str
+
+.. attributetable:: navigator_msgs.srv.ChooseAnimalResponse
+
+.. class:: navigator_msgs.srv.ChooseAnimalResponse
+
+ The response class for the ``navigator_msgs/ChooseAnimal`` service.
+
+ .. attribute:: movement_complete
+
+ Whether the movement was completed.
+
+ :type: bool
+
+ColorRequest
+~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.ColorRequestRequest
+
+.. class:: navigator_msgs.srv.ColorRequestRequest
+
+ The request class for the ``navigator_msgs/ColorRequest`` service.
+
+ .. attribute:: color
+
+ The color used to find objects with.
+
+ :type: str
+
+.. attributetable:: navigator_msgs.srv.ColorRequestResponse
+
+.. class:: navigator_msgs.srv.ColorRequestResponse
+
+ The response class for the ``navigator_msgs/ColorRequest`` service.
+
+ .. attribute:: found
+
+ Whether objects were found.
+
+ :type: bool
+
+ .. attribute:: ids
+
+ The IDs of objects that were found.
+
+ :type: List[int]
+
+FindPinger
+~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.FindPingerRequest
+
+.. class:: navigator_msgs.srv.FindPingerRequest
+
+ The request class for the ``navigator_msgs/FindPinger`` service. The request
+ has no individual attributes.
+
+.. attributetable:: navigator_msgs.srv.FindPingerResponse
+
+.. class:: navigator_msgs.srv.FindPingerResponse
+
+ The response class for the ``navigator_msgs/FindPinger`` service.
+
+ .. attribute:: pinger_position
+
+ The position of the pinger.
+
+ :type: Point
+
+ .. attribute:: num_samples
+
+ ???
+
+ :type: int
+
+GetDockBays
+~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.GetDockBaysRequest
+
+.. class:: navigator_msgs.srv.GetDockBaysRequest
+
+ The request class for the ``navigator_msgs/GetDockBays`` service. The request
+ has no individual attributes.
+
+.. attributetable:: navigator_msgs.srv.GetDockBaysResponse
+
+.. class:: navigator_msgs.srv.GetDockBaysResponse
+
+ The response class for the ``navigator_msgs/GetDockBays`` service.
+
+ .. attribute:: bays
+
+ The positions of the three dock bays in the ENU frame. The first element is
+ the position of the left dock, the second element is the position of the center dock,
+ the third element is the position of the right dock.
+
+ :type: List[Point]
+
+ .. attribute:: normal
+
+ The normal vector pointing away from the plane of dock back.
+
+ :type: Vector3
+
+ .. attribute:: success
+
+ Whether the position of the docks could be found.
+
+ :type: bool
+
+ .. attribute:: error
+
+ If :attr:`~navigator_msgs.srv.GetDockBays.success` is ``False``,
+ then a message describing what went wrong.
+
+ :type: str
+
+GetDockShape
+~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.GetDockShapeRequest
+
+.. class:: navigator_msgs.srv.GetDockShapeRequest
+
+ The request class for the ``navigator_msgs/GetDockShape`` service.
+
+ .. attribute:: Shape
+
+ The shape to the get the associated dock of. Likely one of the associated shape
+ enumerations.
+
+ :type: str
+
+ .. attribute:: CROSS
+
+ Constant string attribute used to represent a cross shape on a dock. True value
+ is set to ``CROSS``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Shape` attribute.
+
+ :type: str
+
+ .. attribute:: TRIANGLE
+
+ Constant string attribute used to represent a triangle shape on a dock. True value
+ is set to ``TRIANGLE``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Shape` attribute.
+
+ :type: str
+
+ .. attribute:: CIRCLE
+
+ Constant string attribute used to represent a circle shape on a dock. True value
+ is set to ``CIRCLE``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Shape` attribute.
+
+ :type: str
+
+ .. attribute:: Color
+
+ The color to the get the associated dock of. Likely one of the associated color
+ enumerations.
+
+ :type: str
+
+ .. attribute:: RED
+
+ Constant string attribute used to represent a red shape on a dock. True value
+ is set to ``RED``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Color` attribute.
+
+ :type: str
+
+ .. attribute:: BLUE
+
+ Constant string attribute used to represent a triangle shape on a dock. True value
+ is set to ``BLUE``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Color` attribute.
+
+ :type: str
+
+ .. attribute:: GREEN
+
+ Constant string attribute used to represent a circle shape on a dock. True value
+ is set to ``GREEN``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Color` attribute.
+
+ :type: str
+
+ .. attribute:: ANY
+
+ Constant string attribute used to represent any value for a specific field - ie, a
+ dock with any shape or color representation. Actual value is ``ANY``.
+
+ :type: str
+
+.. attributetable:: navigator_msgs.srv.GetDockShapeResponse
+
+.. class:: navigator_msgs.srv.GetDockShapeResponse
+
+ The response class for the ``navigator_msgs/GetDockShape`` service.
+
+ .. attribute:: symbol
+
+ The associated shape and color of the returned dock.
+
+ :type: DockShape
+
+ .. attribute:: found
+
+ Whether a viable dock was found.
+
+ :type: bool
+
+ .. attribute:: error
+
+ If :attr:`~navigator_msgs.srv.GetDockShapeResponse.found` was false,
+ then a description of what went wrong. May be equal to one of this class' enumerations.
+
+ :type: str
+
+ .. attribute:: INVALID_REQUEST
+
+ An enumeration to describe a request that was invalid in some way. Actual
+ string value is ``INVALID_REQUEST``.
+
+ :type: str
+
+ .. attribute:: NODE_DISABLED
+
+ An enumeration to describe a request that was invalid in some way. Actual
+ string value is ``NODE_DISABLED``.
+
+ :type: str
+
+ .. attribute:: TOO_SMALL_SAMPLE
+
+ An enumeration to describe a request that was invalid in some way. Actual
+ string value is ``TOO_SMALL_SAMPLE``.
+
+ :type: str
+
+ .. attribute:: SHAPE_NOT_FOUND
+
+ An enumeration to describe a request that was invalid in some way. Actual
+ string value is ``SHAPE_NOT_FOUND``.
+
+ :type: str
+
+GetDockShapes
+~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.GetDockShapesRequest
+
+.. class:: navigator_msgs.srv.GetDockShapesRequest
+
+ The request class for the ``navigator_msgs/GetDockShapes`` service.
+
+ .. attribute:: Shape
+
+ The shape to the get the associated dock of. Likely one of the associated shape
+ enumerations.
+
+ :type: str
+
+ .. attribute:: CROSS
+
+ Constant string attribute used to represent a cross shape on a dock. True value
+ is set to ``CROSS``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Shape` attribute.
+
+ :type: str
+
+ .. attribute:: TRIANGLE
+
+ Constant string attribute used to represent a triangle shape on a dock. True value
+ is set to ``TRIANGLE``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Shape` attribute.
+
+ :type: str
+
+ .. attribute:: CIRCLE
+
+ Constant string attribute used to represent a circle shape on a dock. True value
+ is set to ``CIRCLE``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Shape` attribute.
+
+ :type: str
+
+ .. attribute:: Color
+
+ The color to the get the associated dock of. Likely one of the associated color
+ enumerations.
+
+ :type: str
+
+ .. attribute:: RED
+
+ Constant string attribute used to represent a red shape on a dock. True value
+ is set to ``RED``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Color` attribute.
+
+ :type: str
+
+ .. attribute:: BLUE
+
+ Constant string attribute used to represent a triangle shape on a dock. True value
+ is set to ``BLUE``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Color` attribute.
+
+ :type: str
+
+ .. attribute:: GREEN
+
+ Constant string attribute used to represent a circle shape on a dock. True value
+ is set to ``GREEN``.
+
+ Likely used in the :attr:`~navigator_msgs.srv.GetDockShapeRequest.Color` attribute.
+
+ :type: str
+
+ .. attribute:: ANY
+
+ Constant string attribute used to represent any value for a specific field - ie, a
+ dock with any shape or color representation. Actual value is ``ANY``.
+
+ :type: str
+
+.. attributetable:: navigator_msgs.srv.GetDockShapesResponse
+
+.. class:: navigator_msgs.srv.GetDockShapesResponse
+
+ The response class for the ``navigator_msgs/GetDockShapes`` service.
+
+ .. attribute:: shapes
+
+ The relevant dock shapes that were found.
+
+ :type: List[DockShape]
+
+ .. attribute:: found
+
+ If one or more suitable shapes was returned, then true.
+
+ :type: bool
+
+ .. attribute:: error
+
+ If :attr:`~navigator_msgs.srv.GetDockShapesResponse.found`
+ was false, then an explanation of why.
+
+ :type: str
+
+ .. attribute:: INVALID_REQUEST
+
+ An enumeration to describe a request that was invalid in some way. Actual
+ string value is ``INVALID_REQUEST``.
+
+ :type: str
+
+ .. attribute:: NODE_DISABLED
+
+ An enumeration to describe a request that was invalid in some way. Actual
+ string value is ``NODE_DISABLED``.
+
+ :type: str
+
+ .. attribute:: TOO_SMALL_SAMPLE
+
+ An enumeration to describe a request that was invalid in some way. Actual
+ string value is ``TOO_SMALL_SAMPLE``.
+
+ :type: str
+
+ .. attribute:: SHAPE_NOT_FOUND
+
+ An enumeration to describe a request that was invalid in some way. Actual
+ string value is ``SHAPE_NOT_FOUND``.
+
+ :type: str
+
+ShooterManual
+~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.ShooterManualRequest
+
+.. class:: navigator_msgs.srv.ShooterManualRequest
+
+ The request class for the ``navigator_msgs/ShooterManual`` service.
+
+ .. attribute:: feeder
+
+ ???
+
+ :type: float
+
+ .. attribute:: shooter
+
+ ???
+
+ :type: float
+
+.. attributetable:: navigator_msgs.srv.ShooterManualResponse
+
+.. class:: navigator_msgs.srv.ShooterManualResponse
+
+ The response class for the ``navigator_msgs/ShooterManual`` service.
+
+ .. attribute:: success
+
+ Whether the shooter operation was successful.
+
+ :type: bool
+
+StartGate
+~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.StartGateRequest
+
+.. class:: navigator_msgs.srv.StartGateRequest
+
+ The request class for the ``navigator_msgs/StartGate`` service. The request
+ class no public attributes.
+
+.. attributetable:: navigator_msgs.srv.StartGateResponse
+
+.. class:: navigator_msgs.srv.StartGateResponse
+
+ The response class for the ``navigator_msgs/StartGate`` service.
+
+ .. attribute:: target
+
+ The target of the mission's start gate.
+
+ :type: PoseStamped
+
+ .. attribute:: success
+
+ Whether the start gate operation was successful.
+
+ :type: bool
+
+Subsystems
+^^^^^^^^^^
+
+AlarmGet
+~~~~~~~~
+
+.. attributetable:: ros_alarms_msgs.srv.AlarmGetRequest
+
+.. class:: ros_alarms_msgs.srv.AlarmGetRequest
+
+ The request class for the ``ros_alarms/AlarmGet`` service.
+
+ .. attribute:: alarm_name
+
+ The name of the alarm to request data about.
+
+ :type: str
+
+.. attributetable:: ros_alarms_msgs.srv.AlarmGetResponse
+
+.. class:: ros_alarms_msgs.srv.AlarmGetResponse
+
+ The response class for the ``ros_alarms/AlarmGet`` service.
+
+ .. attribute:: header
+
+ The header for the response.
+
+ :type: Header
+
+ .. attribute:: alarm
+
+ The response data about the requested alarm.
+
+ :type: ~ros_alarms_msgs.msg.Alarm
+
+AlarmSet
+~~~~~~~~
+
+.. attributetable:: ros_alarms_msgs.srv.AlarmSetRequest
+
+.. class:: ros_alarms_msgs.srv.AlarmSetRequest
+
+ The request class for the ``ros_alarms/AlarmSet`` service.
+
+ .. attribute:: alarm
+
+ The alarm to set.
+
+ :type: ~ros_alarms_msgs.msg.Alarm
+
+.. attributetable:: ros_alarms_msgs.srv.AlarmSetResponse
+
+.. class:: ros_alarms_msgs.srv.AlarmSetResponse
+
+ The response class for the ``ros_alarms/AlarmSet`` service.
+
+ .. attribute:: succeed
+
+ Whether the request succeeded.
+
+ :type: bool
+
+CameraDBQuery
+~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.CameraDBQueryRequest
+
+.. class:: navigator_msgs.srv.CameraDBQueryRequest
+
+ The request class for the ``navigator_msgs/CameraDBQuery`` service.
+
+ .. attribute:: name
+
+ The name of the object to query.
+
+ :type: str
+
+ .. attribute:: id
+
+ The ID of the object to query.
+
+ :type: int
+
+.. attributetable:: navigator_msgs.srv.CameraDBQueryResponse
+
+.. class:: navigator_msgs.srv.CameraDBQueryResponse
+
+ The response class for the ``navigator_msgs/CameraDBQuery`` service.
+
+ .. attribute:: found
+
+ Whether the object is found.
+
+ :type: bool
+
+MoveToWaypoint
+~~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.MoveToWaypointRequest
+
+.. class:: navigator_msgs.srv.MoveToWaypointRequest
+
+ The request class for the ``navigator_msgs/MoveToWaypoint`` service.
+
+ .. attribute:: target_p
+
+ The target pose to head toward.
+
+ :type: Pose
+
+.. attributetable:: navigator_msgs.srv.MoveToWaypointResponse
+
+.. class:: navigator_msgs.srv.MoveToWaypointResponse
+
+ The response class for the ``navigator_msgs/MoveToWaypoint`` service.
+
+ .. attribute:: success
+
+ Whether the movement was successful.
+
+ :type: bool
+
+ObjectDBQuery
+~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.ObjectDBQueryRequest
+
+.. class:: navigator_msgs.srv.ObjectDBQueryRequest
+
+ The request class for the ``navigator_msgs/ObjectDBQuery`` service.
+
+ .. attribute:: name
+
+ The name of the object to find in the database.
+
+ :type: str
+
+ .. attribute:: cmd
+
+ The command to run in the database. The command should be formatted as
+ ``ID=YYY``, where ``ID`` is the property ID of the object to change, and
+ ``YYY`` is the value to set.
+
+ :type: str
+
+.. attributetable:: navigator_msgs.srv.ObjectDBQueryResponse
+
+.. class:: navigator_msgs.srv.ObjectDBQueryResponse
+
+ The response class for the ``navigator_msgs/ObjectDBQuery`` service.
+
+ .. attribute:: found
+
+ Whether the requested object was found.
+
+ :type: bool
+
+ .. attribute:: objects
+
+ A list of all objects found.
+
+ :type: List[PerceptionObject]
+
+SetFrequency
+~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.SetFrequencyRequest
+
+.. class:: navigator_msgs.srv.SetFrequencyRequest
+
+ The request class for the ``navigator_msgs/SetFrequency`` service.
+
+ .. attribute:: frequency
+
+ The frequency to set.
+
+ :type: int
+
+.. attributetable:: navigator_msgs.srv.SetFrequencyResponse
+
+.. class:: navigator_msgs.srv.SetFrequencyResponse
+
+ The response class for the ``navigator_msgs/SetFrequency`` service. The
+ class no public attributes.
+
+SetROI
+~~~~~~
+.. attributetable:: navigator_msgs.srv.SetROIRequest
+
+.. class:: navigator_msgs.srv.SetROIRequest
+
+ The request class for the ``navigator_msgs/SetROI`` service.
+
+ .. attribute:: roi
+
+ The region of interest to set.
+
+ :type: RegionOfInterest
+
+.. attributetable:: navigator_msgs.srv.SetROIResponse
+
+.. class:: navigator_msgs.srv.SetROIResponse
+
+ The response class for the ``navigator_msgs/SetROI`` service.
+
+ .. attribute:: success
+
+ Whether the set operation was successful.
+
+ :type: bool
+
+ .. attribute:: error
+
+ If the operation failed, then a description of what went wrong.
+
+ :type: str
+
+ .. attribute:: OUTSIDE_OF_FRAME
+
+ A string constant to represent that the region of interest is outside the
+ observable frame. Constant string actually equally to ``OUTSIDE_OF_FRAME``.
+
+ :type: str
+
+StereoShapeDetector
+~~~~~~~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.StereoShapeDetectorRequest
+
+.. class:: navigator_msgs.srv.StereoShapeDetectorRequest
+
+ The request class for the ``navigator_msgs/StereoShapeDetector`` service.
+
+ .. attribute:: detection_switch
+
+ ???
+
+ :type: bool
+
+ .. attribute:: shape
+
+ ???
+
+ :type: str
+
+ .. attribute:: processing_type
+
+ ???
+
+ :type: str
+
+ .. attribute:: num_points
+
+ The number of points relevant to the detector.
+
+ :type: int
+
+ .. attribute:: model_params
+
+ ???
+
+ :type: List[float]
+
+.. attributetable:: navigator_msgs.srv.StereoShapeDetectorResponse
+
+.. class:: navigator_msgs.srv.StereoShapeDetectorResponse
+
+ The response class for the ``navigator_msgs/StereoShapeDetector`` service.
+
+ .. attribute:: success
+
+ Whether the detector was successful in detecting!
+
+ :type: bool
+
+VisionRequest
+~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.VisionRequestRequest
+
+.. class:: navigator_msgs.srv.VisionRequestRequest
+
+ The request class for the ``navigator_msgs/VisionRequest`` service.
+
+ .. attribute:: target_name
+
+ The target to look for in the vision system.
+
+ :type: str
+
+.. attributetable:: navigator_msgs.srv.VisionRequestResponse
+
+.. class:: navigator_msgs.srv.VisionRequestResponse
+
+ The response class for the ``navigator_msgs/VisionRequest`` service.
+
+ .. attribute:: pose
+
+ Where the object is at, in the vision system.
+
+ :type: PoseStamped
+
+ .. attribute:: covariance_diagonal
+
+ The covariance in the vision target.
+
+ :type: Vector3
+
+ .. attribute:: found
+
+ Whether the vision object was found.
+
+ :type: bool
+
+Standard Messages
+^^^^^^^^^^^^^^^^^
+
+SetBool
+~~~~~~~
+
+.. attributetable:: std_srvs.srv.SetBoolRequest
+
+.. class:: std_srvs.srv.SetBoolRequest
+
+ The request type for the ``SetBool`` service. Requests for some boolean value
+ to be set.
+
+.. attributetable:: std_srvs.srv.SetBoolResponse
+
+.. class:: std_srvs.srv.SetBoolResponse
+
+ The response type for the ``SetBool`` service. Responds to the set boolean value
+ request.
+
+ .. attribute:: success
+
+ Whether the boolean value was successfully set.
+
+ :type: bool
+
+ .. attribute:: message
+
+ Any message included in the response.
+
+ :type: str
+
+Conversions
+^^^^^^^^^^^
+
+CameraToLidarTransform
+~~~~~~~~~~~~~~~~~~~~~~
+.. attributetable:: navigator_msgs.srv.CameraToLidarTransformRequest
+
+.. class:: navigator_msgs.srv.CameraToLidarTransformRequest
+
+ The request class for the ``navigator_msgs/CameraToLidarTransform`` service.
+
+ .. attribute:: header
+
+ The stamp the point was seen for tf.
+
+ :type: Header
+
+ .. attribute:: point
+
+ The x-dimension and y-dimension of the point in the camera. The z-dimension
+ is ignored.
+
+ :type: Point
+
+ .. attribute:: tolerance
+
+ The number of pixels the projected 3D Lidar point can be from the target point
+ to be included in the response.
+
+ :type: int
+
+.. attributetable:: navigator_msgs.srv.CameraToLidarTransformResponse
+
+.. class:: navigator_msgs.srv.CameraToLidarTransformResponse
+
+ The response class for the ``navigator_msgs/CameraToLidarTransform`` service.
+
+ .. attribute:: success
+
+ True if at least one point is found within LIDAR and transformed.
+
+ :type: bool
+
+ .. attribute:: transformed
+
+ If success is true, then the list of transformed points.
+
+ :type: List[Point]
+
+ .. attribute:: closest
+
+ 3D point that is closest to the target point when transformed and projected
+
+ :type: Point
+
+ .. attribute:: normal
+
+ The normal unit vector in the camera frame estimated from the transformed points.
+
+ :type: Vector3
+
+ .. attribute:: distance
+
+ The mean z-dimension of the transformed points.
+
+ :type: float
+
+ .. attribute:: error
+
+ If success is false, then what went wrong.
+
+ :type: str
+
+ .. attribute:: CLOUD_NOT_FOUND
+
+ The pointcloud was not found. Constant string actually equal to ``pointcloud
+ not found``.
+
+ :type: str
+
+ .. attribute:: NO_POINTS
+
+ No points were found. Constant string actually equal to ``no points``.
+
+ :type: str
+
+CoordinateConversion
+~~~~~~~~~~~~~~~~~~~~
+
+.. attributetable:: navigator_msgs.srv.CoordinateConversionRequest
+
+.. class:: navigator_msgs.srv.CoordinateConversionRequest
+
+ The request class for the ``navigator_msgs/CoordinateConversion`` service.
+
+ .. attribute:: LLA
+
+ The longitude, latitude, altitude coordinate frame. Constant string equal
+ to ``lla``.
+
+ :type: str
+
+ .. attribute:: ENU
+
+ The east, north, up frame. Constant string equal to ``enu``.
+
+ :type: str
+
+ .. attribute:: ECEF
+
+ The Earth-centered, Earth-fixed frame. Constant string equal to ``ecef``.
+
+ :type: str
+
+ .. attribute:: frame
+
+ The current frame of the relative objects.
+
+ :type: str
+
+ .. attribute:: to_frame
+
+ The frame of objects to convert objects to.
+
+ :type: str
+
+ .. attribute:: points
+
+ The points to convert between the different frames.
+
+ :type: List[Point]
+
+.. attributetable:: navigator_msgs.srv.CoordinateConversionResponse
+
+.. class:: navigator_msgs.srv.CoordinateConversionResponse
+
+ The response class for the ``navigator_msgs/CoordinateConversion`` service.
+
+ .. attribute:: converted
+
+ The list of converted points.
+
+ :type: List[Point]
+
+ .. attribute:: message
+
+ If an error occurred, the message of what went wrong.
+
+ :type: str
+
+KeyboardControl
+^^^^^^^^^^^^^^^
+.. attributetable:: navigator_msgs.srv.KeyboardControlRequest
+
+.. class:: navigator_msgs.srv.KeyboardControlRequest
+
+ The request class for the ``navigator_msgs/KeyboardControl`` service.
+
+ .. attribute:: uuid
+
+ A unique ID to represent the process (?).
+
+ :type: str
+
+ .. attribute:: keycode
+
+ The keycode that was pressed.
+
+ :type: int
+
+.. attributetable:: navigator_msgs.srv.KeyboardControlResponse
+
+.. class:: navigator_msgs.srv.KeyboardControlResponse
+
+ The response class for the ``navigator_msgs/KeyboardControl`` service.
+
+ .. attribute:: generated_uuid
+
+ A response unique ID that was generated in response to the request.
+
+ :type: str
+
+ .. attribute:: is_locked
+
+ Whether the client which sent the keycode has "locked control" of the keyboard
+ server, and is therefore blocking other keyboard input.
+
+ :type: bool
+
+POI Handling
+^^^^^^^^^^^^
+
+AddPOI
+~~~~~~
+.. attributetable:: mil_poi.srv.AddPOIRequest
+
+.. class:: mil_poi.srv.AddPOIRequest
+
+ The request class for the ``mil_poi/AddPOI`` service.
+
+ .. attribute:: name
+
+ The name of the POI to add.
+
+ :type: str
+
+ .. attribute:: position
+
+ The position of the new POI.
+
+ :type: PointStamped
+
+.. attributetable:: mil_poi.srv.AddPOIResponse
+
+.. class:: mil_poi.srv.AddPOIResponse
+
+ The response class for the ``mil_poi/AddPOI`` service.
+
+ .. attribute:: success
+
+ Whether the add operation was successful.
+
+ :type: bool
+
+ .. attribute:: message
+
+ The message associated with the success of the add operation.
+
+ :type: str
+
+MovePOI
+~~~~~~~
+.. attributetable:: mil_poi.srv.MovePOIRequest
+
+.. class:: mil_poi.srv.MovePOIRequest
+
+ The request class for the ``mil_poi/MovePOI`` service.
+
+ .. attribute:: name
+
+ The name of the POI to move.
+
+ :type: str
+
+ .. attribute:: position
+
+ The position of the new POI.
+
+ :type: PointStamped
+
+.. attributetable:: mil_poi.srv.MovePOIResponse
+
+.. class:: mil_poi.srv.MovePOIResponse
+
+ The response class for the ``mil_poi/MovePOI`` service.
+
+ .. attribute:: success
+
+ Whether the move operation was successful.
+
+ :type: bool
+
+ .. attribute:: message
+
+ The message associated with the success of the move operation.
+
+ :type: str
+
+DeletePOI
+~~~~~~~~~
+.. attributetable:: mil_poi.srv.DeletePOIRequest
+
+.. class:: mil_poi.srv.DeletePOIRequest
+
+ The request class for the ``mil_poi/DeletePOI`` service.
+
+ .. attribute:: name
+
+ The name of the POI to delete.
+
+ :type: str
+
+.. attributetable:: mil_poi.srv.DeletePOIResponse
+
+.. class:: mil_poi.srv.DeletePOIResponse
+
+ The response class for the ``mil_poi/DeletePOI`` service.
+
+ .. attribute:: success
+
+ Whether the delete operation was successful.
+
+ :type: bool
+
+ .. attribute:: message
+
+ The message associated with the success of the delete operation.
+
+ :type: str
diff --git a/docs/reference/vision.rst b/docs/reference/vision.rst
new file mode 100644
index 0000000..2e43a02
--- /dev/null
+++ b/docs/reference/vision.rst
@@ -0,0 +1,258 @@
+Computer Vision
+---------------
+
+Utility Functions
+^^^^^^^^^^^^^^^^^
+.. autofunction:: mil_vision_tools.auto_canny
+
+.. autofunction:: mil_vision_tools.contour_centroid
+
+.. autofunction:: mil_vision_tools.contour_mask
+
+.. autofunction:: mil_vision_tools.putText_ul
+
+.. autofunction:: mil_vision_tools.points_in_image
+
+.. autofunction:: mil_vision_tools.roi_enclosing_points
+
+.. autofunction:: mil_vision_tools.rect_from_roi
+
+.. autofunction:: mil_vision_tools.quaternion_from_rvec
+
+.. autofunction:: mil_vision_tools.create_object_msg
+
+.. TODO Figure out why this signature is causing issues with Sphinx/Breathe/Doxygen
+.. .. doxygenfunction:: mil_vision::pseudoInverse
+
+.. doxygenfunction:: mil_vision::larger_contour
+
+.. doxygenfunction:: mil_vision::smooth_histogram
+
+.. doxygenfunction:: mil_vision::generate_gaussian_kernel_1D
+
+.. doxygenfunction:: mil_vision::find_local_maxima
+
+.. doxygenfunction:: mil_vision::find_local_minima
+
+.. doxygenfunction:: mil_vision::select_hist_mode (std::vector< cv::Point > &histogram_modes, unsigned int target)
+
+.. doxygenfunction:: mil_vision::select_hist_mode (std::vector< cv::Point > &histogram_modes, int target)
+
+.. doxygenfunction:: mil_vision::range_from_param
+
+.. doxygenfunction:: mil_vision::inParamRange
+
+.. doxygenfunction:: mil_vision::rotateKernel
+
+.. doxygenfunction:: mil_vision::makeRotInvariant
+
+.. doxygenfunction:: mil_vision::getRadialSymmetryAngle
+
+C++ Type Aliases
+^^^^^^^^^^^^^^^^
+.. doxygentypedef:: mil_vision::PCD
+
+.. doxygentypedef:: mil_vision::PCDPtr
+
+.. doxygentypedef:: mil_vision::SPtrVector
+
+.. doxygentypedef:: mil_vision::UPtrVector
+
+Vision Utility Functions
+^^^^^^^^^^^^^^^^^^^^^^^^
+.. doxygenfunction:: mil_vision::kanatani_triangulation
+
+.. doxygenfunction:: mil_vision::statistical_image_segmentation
+
+.. doxygenfunction:: mil_vision::triangulate_Linear_LS
+
+.. doxygenfunction:: mil_vision::lindstrom_triangulation
+
+ContourClassifier
+^^^^^^^^^^^^^^^^^
+.. attributetable:: mil_vision_tools.ContourClassifier
+
+.. autoclass:: mil_vision_tools.ContourClassifier
+ :members:
+
+Threshold
+^^^^^^^^^
+.. attributetable:: mil_vision_tools.Threshold
+
+.. autoclass:: mil_vision_tools.Threshold
+ :members:
+
+ImageMux
+^^^^^^^^
+.. attributetable:: mil_vision_tools.ImageMux
+
+.. autoclass:: mil_vision_tools.ImageMux
+ :members:
+
+ImageSet
+^^^^^^^^
+.. attributetable:: mil_vision_tools.ImageSet
+
+.. autoclass:: mil_vision_tools.ImageSet
+ :members:
+
+ImageProc
+^^^^^^^^^
+.. attributetable:: mil_vision_tools.ImageProc
+
+.. autoclass:: mil_vision_tools.ImageProc
+ :members:
+
+TrackedObject
+^^^^^^^^^^^^^
+.. attributetable:: mil_vision_tools.TrackedObject
+
+.. autoclass:: mil_vision_tools.TrackedObject
+ :members:
+
+ObjectsTracker
+^^^^^^^^^^^^^^
+.. attributetable:: mil_vision_tools.ObjectsTracker
+
+.. autoclass:: mil_vision_tools.ObjectsTracker
+ :members:
+
+RectFinder
+^^^^^^^^^^
+.. attributetable:: mil_vision_tools.RectFinder
+
+.. autoclass:: mil_vision_tools.RectFinder
+ :members:
+
+VisionNode
+^^^^^^^^^^
+.. attributetable:: mil_vision_tools.VisionNode
+
+.. autoclass:: mil_vision_tools.VisionNode
+ :members:
+
+CameraLidarTransformer
+^^^^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: CameraLidarTransformer
+
+.. note::
+
+ Most of the methods/attributes for this class are private, which is why none appear.
+ To have these documented, either make these public or discuss the option of documenting
+ private C++ class members with a software lead.
+
+.. doxygenclass:: CameraLidarTransformer
+
+ClosedCurve
+^^^^^^^^^^^
+.. cppattributetable:: mil_vision::ClosedCurve
+
+.. doxygenclass:: mil_vision::ClosedCurve
+
+ActiveContour
+^^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::ActiveContour
+
+.. doxygenclass:: mil_vision::ActiveContour
+
+CameraObserver
+^^^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::CameraObserver
+
+.. doxygenclass:: mil_vision::CameraObserver
+
+ColorObservation
+^^^^^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::ColorObservation
+
+.. doxygenstruct:: mil_vision::ColorObservation
+
+UnoccludedPointsImg
+^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::UnoccludedPointsImg
+
+.. doxygenclass:: mil_vision::UnoccludedPointsImg
+
+PointColorStats
+^^^^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::PointColorStats
+
+.. doxygenstruct:: mil_vision::PointColorStats
+
+PcdColorizer
+^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::PcdColorizer
+
+.. doxygenclass:: mil_vision::PcdColorizer
+
+SingleCloudProcessor
+^^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::SingleCloudProcessor
+
+.. doxygenclass:: mil_vision::SingleCloudProcessor
+
+PixelType
+^^^^^^^^^
+.. doxygenenum:: mil_vision::PixelType
+
+CameraFrame
+^^^^^^^^^^^
+.. cppattributetable:: mil_vision::CameraFrame
+
+.. doxygenclass:: mil_vision::CameraFrame
+
+ImageWithCameraInfo
+^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::ImageWithCameraInfo
+
+.. doxygenstruct:: mil_vision::ImageWithCameraInfo
+
+FrameHistory
+^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::FrameHistory
+
+.. doxygenclass:: mil_vision::FrameHistory
+
+Range
+^^^^^
+.. cppattributetable:: mil_vision::Range
+
+.. doxygenstruct:: mil_vision::Range
+
+CameraFrameSequence
+^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::CameraFrameSequence
+
+.. doxygenclass:: mil_vision::CameraFrameSequence
+
+CameraModel
+^^^^^^^^^^^
+.. cppattributetable:: mil_vision::CameraModel
+
+.. doxygenclass:: mil_vision::CameraModel
+
+ROSCameraStream
+^^^^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::ROSCameraStream
+
+.. doxygenclass:: mil_vision::ROSCameraStream
+
+PcdSubPubAlgorithm
+^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: mil_vision::PcdSubPubAlgorithm
+
+.. doxygenclass:: mil_vision::PcdSubPubAlgorithm
+
+
+ImagePublisher
+^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: ImagePublisher
+
+.. doxygenclass:: ImagePublisher
+
+
+ImageSubscriber
+^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: ImageSubscriber
+
+.. doxygenclass:: ImageSubscriber
diff --git a/docs/software/adding_documentation.md b/docs/software/adding_documentation.md
new file mode 100644
index 0000000..d91bf76
--- /dev/null
+++ b/docs/software/adding_documentation.md
@@ -0,0 +1,104 @@
+# Updating Documentation
+So, you'd like to update this documentation? That's fantastic! Documentation will help
+countless numbers of MIL generations to understand what you've built. If you only build
+a system, but don't document it, future generations may not even know what to do with
+what you've built!
+
+## Setup for Members with ROS
+
+If you have ROS installed, that's great. You will be able to build source files
+from our source code. Make sure you have completed the getting started process
+to ensure you have all the needed dependencies.
+
+Remember to make your changes on an accessible branch:
+```bash
+$ git checkout -b
+```
+
+Feel free to be flexible with this; you may not need to make a new branch if you
+already have one that you'd like to add documentation to.
+
+## Setup for Members without ROS
+
+We want to make the MIL docs accessible to all members, including those who
+may not have ROS setup. Below are the steps you will need to take to get a _lite_
+setup working that allows you to contribute to the docs and preview your changes.
+
+1. Install git and clone the repository.
+ ```bash
+ $ git clone https://github.com/uf-mil/mil -j8 --recurse-submodules
+ ```
+2. Make your own branch off of `master`. This branch only will be used by you
+ (and any collaborators working with you), so feel free to play around with things.
+ ```bash
+ $ cd mil
+ $ git checkout -b
+ ```
+3. Install Python and the needed dependencies. This will vary based on your
+ operating system.
+ ```bash
+ $ pip3 install -r requirements.txt
+ ```
+4. Make changes to the files.
+5. To view your changes and contribute them, continue reading below.
+
+## Updating styling
+
+Most of the colors used on the documentation site are controlled through `custom.css`
+or `codeblocks.css`. To update the general layout of the site, edit the `custom.css`
+and re-build the documentation. If you haven't changed any actual content, you may
+need to build the documentation from scratch using the `-s` flag.
+
+To update the colors shown in code blocks, edit the `codeblocks.css` file. You can
+either edit this file directly, or generate a similar copy by using the `pygments`
+library. Navigate into the `uf_mil_pygments` Python package in the `docs/` folder,
+install the Python package (`pip install -e .`) and then create a CSS file using
+the Pygments Style class found in the package (`pygmentize -S mil -f html -a .highlight > mil.css`).
+
+## Making changes
+To make changes to the documentation, you only need to add/edit files under
+the `docs/` folder or docstrings existing in the source code. Once you edit these
+sources, you have changed the documentation, and this will be reflected in the
+HTML you build.
+
+To see the syntax used to make the documentation, check out the page on [syntax](/software/documentation_syntax.md).
+
+## Viewing changes
+It is important to generate the documentation website locally and view it in a
+web browser to verify your changes did what you wanted them to do and they are
+quick to read.
+
+For members who have ROS setup, you can build the documentation with the following
+commands:
+
+```bash
+$ mil
+$ ./scripts/build_docs
+```
+
+Members without ROS setup will need to build the documentation without the source
+files. Because you aren't building the reference files, you will get a few errors
+explaining that Sphinx can't find those files. This is expected. Errors related
+to files you've modified may be a result of your changes, however.
+
+```bash
+$ mil
+$ ./scripts/build_docs --no-source
+```
+
+At the bottom of each build output, a link is displayed where you can access
+the built documentation. Keep in mind that this link does not start with `https://`,
+but rather `file://`.
+
+After you've built the repository for the first time, the build contents are cached,
+meaning that subsequent changes the docs will only re-build the files you edited
+since you last built the docs. If this is not ideal behavior, you can completely
+re-build the docs by adding another flag:
+```bash
+$ mil
+$ ./scripts/build_docs --scratch
+```
+
+## Contributing changes
+Now that you have made and verified your changes, follow the [contributing guide](contributing)
+to add your changes to the repository.
diff --git a/docs/software/alarms.md b/docs/software/alarms.md
new file mode 100644
index 0000000..80fb514
--- /dev/null
+++ b/docs/software/alarms.md
@@ -0,0 +1,114 @@
+# Alarms in ROS
+
+In the realm of building dependable control systems, the importance of error detection
+and effective error-handling mechanisms cannot be overstated. Within this context,
+MIL presents a robust solution in the form of a live alarm system. This alarm system
+operates discreetly in the background of both the robot's mission and driver codebases,
+ready to be activated upon the emergence of errors. Notably, the alarm code doesn't
+solely serve to identify and address errors; it can also adeptly manage changes
+or updates that extend beyond error scenarios.
+
+## ROS Alarms: A Service-Oriented Architecture
+
+The architecture of ROS alarms distinguishes itself by employing a service-oriented
+model rather than the usual topic-based approach. In ROS, Services act as the
+conduits for interaction between nodes, functioning in a request-response manner.
+While ROS topics enable asynchronous data exchange, services facilitate nodes in
+seeking specific actions or information from other nodes, awaiting a subsequent
+response before proceeding. This method of waiting before proceeding is known as a
+synchronous data exchange. This proves especially valuable in tasks that require
+direct engagement, such as data retrieval or computations.
+
+## Alarm System Logic
+
+The alarm system's functionality is more intricate than that of a typical ROS
+service, which usually manages operations of base types (ints, strings, etc.).
+In this scenario, the alarm's service server is engineered to manage the tasks
+of updating, querying, and processing an alarm object. ROS alarms encompass two
+distinct types of clients: the alarm broadcaster and the alarm listener. The
+broadcaster initializes and triggers alarms in response to errors or changes,
+while the listener monitors the broadcaster's activity and activates designated
+a callback function when alarms are raised. The callback function should handle
+the error or change appropriately.
+
+To successfully leverage alarms, the initialization of both the broadcaster and
+listener is needed. The listener should be configured to execute a predefined
+callback function, addressing errors or changes detected by the broadcaster.
+Within your codebase, error detection and alarm-raising procedures should be
+integrated. If orchestrated correctly, the callback function will be automatically
+invoked, underscoring successful error mitigation.
+
+Note that there are several special properties that can be attached to your alarm.
+Here are a couple of examples:
+* When you raise an alarm you can assign a severity level to the alarm [0, 5].
+* You can attach multiple callback functions to the alarm.
+ * **This is where severity comes into play!** By specifying the required
+ severity level that is needed to execute the callback when initializing the
+ function, you can choose which callbacks are executed when the alarm is raised.
+ * You can also specify a range of severity levels that the alarm would need to
+ execute a given callback.
+
+Here is a line-by-line breakdown of an example alarm implementation:
+
+```python
+ab = AlarmBroadcaster("test_alarm")
+al = AlarmListener("test_alarm")
+ab.clear_alarm()
+rospy.sleep(0.1)
+```
+This is how you would initialize the alarm broadcaster and listener. Here
+make sure to clear any previous alarm data in the broadcaster.
+
+```python
+al.add_callback(cb1)
+```
+Make sure to establish the callback function that should be executed once
+the alarm is activated.
+
+```python
+ab.raise_alarm()
+rospy.sleep(0.1)
+assert al.is_raised()
+assert cb1_ran
+```
+When the alarm is sounded via the `raise_alarm()` function, the callback will be
+executed automatically.
+
+```python
+al.clear_callbacks()
+
+al.add_callback(cb1, severity_required=2)
+al.add_callback(cb2, call_when_raised=False)
+
+rospy.loginfo("Severity Range Test 1")
+ab.raise_alarm(severity=4)
+rospy.sleep(0.1)
+assert not cb1_ran
+assert cb2_ran
+cb2_ran = False
+
+rospy.loginfo("Severity Range Test 2")
+ab.raise_alarm(severity=1)
+rospy.sleep(0.1)
+assert cb1_ran
+assert not cb2_ran
+cb1_ran = False
+```
+Note that you can also attach some special properties to your alarm. For instance,
+you can attach multiple callback functions to the alarm. You can also configure
+whether the callback function should be automatically executed when the alarm is
+raised or whether it should be executed manually. Finally, you can assign a
+severity level to the alarm which can tell the alarm code which callback functions
+should be run.
+
+## Applications and Context
+
+The applications of ROS alarms span various contexts, with one notable application
+residing in the control of the submersible vehicle's thrust and killboard. The
+thrust and killboard, responsible for the sub's electronic operations, is
+integrally associated with ROS alarms. Upon the board's activation or deactivation
+(hard or soft kill), alarms are invoked to apprise users of these changes. The
+listener's callback function comes into play, ensuring that alarms are updated
+in alignment with the board's current state. This process triggered each time
+the board is deactivated, creates a system whereby users are continually informed
+about the board's status changes – essentially manifesting a dynamic live alarm system.
diff --git a/docs/software/apple_mseries_ubuntu_setup.md b/docs/software/apple_mseries_ubuntu_setup.md
new file mode 100644
index 0000000..596e277
--- /dev/null
+++ b/docs/software/apple_mseries_ubuntu_setup.md
@@ -0,0 +1,31 @@
+# Installing Ubuntu 18.04 on a Mac with an M-series processor (M1) (Depreciated)
+
+[//]: # ()
+[//]: # (Installing Ubuntu 18.04 on an M1 Mac can be challenging, as the device does not permit dual booting another operating system. Therefore, the recommended way to install Ubuntu 18.04 is to use a virtual machine.)
+
+[//]: # ()
+[//]: # (1. Download Ubuntu 18.04 Server for ARMv8. You can find this [here](https://cdimage.ubuntu.com/releases/18.04/release/).)
+
+[//]: # ()
+[//]: # (2. Install Parallels Desktop. You can use another VM software that can load an `.iso` file if you would like, but Parallels has been tested and is confirmed to work. If you use Parallels, you will need to make a Parallels account to use the software.)
+
+[//]: # ()
+[//]: # (3. Load the `.iso` file you downloaded earlier. You will see multiple localization prompts about which language to use, which keyboard layout to use, etc. Select US/English for the first two prompts, and then insert a USB drive into your computer. The contents of the USB drive should not matter.)
+
+[//]: # ()
+[//]: # (4. In the Parallels menu at the top of the window, allow Parallels access to the USB drive you inserted. Click the USB icon, and then click on the specific USB drive you inserted into your computer. It should now show a check mark next to the name.)
+
+[//]: # ()
+[//]: # (5. Continue proceeding through the Ubuntu Server installation process. There is no GUI, all steps are completed through the textual user interface. When partitioning your disk, you can use guided partitioning, which should partition all of the space Parallels allotted for that VM.)
+
+[//]: # ()
+[//]: # (6. The installation process will ask if you want to install any recommended software (such as software to make your computer into a DNS server). Do not select any options, press ``.)
+
+[//]: # ()
+[//]: # (7. The installation process should be complete. You should see a command line interface. Run `sudo apt-get update && sudo apt-get upgrade` to get the latest list of packages.)
+
+[//]: # ()
+[//]: # (8. Run `sudo tasksel`. Then, find `Ubuntu Desktop` and press ``. Then, press ``. Then, run `sudo reboot now`.)
+
+[//]: # ()
+[//]: # (9. You should now see a GUI interface. To sign in, use the username and password you setup before.)
diff --git a/docs/software/asyncio.md b/docs/software/asyncio.md
new file mode 100644
index 0000000..c246f05
--- /dev/null
+++ b/docs/software/asyncio.md
@@ -0,0 +1,218 @@
+# An Introduction to Asyncio
+
+`asyncio` is a standard Python library used to write concurrent code using asynchronous
+syntax. This library is similar to a predecessor library known as Twisted, which
+was used heavily in our repository for nearly a decade before it was removed from
+most files in our repository.
+
+:::{note}
+If you are planning to work with asynchronous code and have not already set up
+an IDE or editor with a language server, you are **highly recommended** to do so.
+It is very common to make mistakes in asynchronous programming (adding `await` somewhere
+it shouldn't be, using the wrong `asyncio` method, etc.) and having to run your
+program each time to figure out if you made any of these mistakes is not ideal.
+
+A type checker in your IDE can catch these mistakes immediately. Setting up a language
+server can take as little as 10 minutes, and is very worth it in the long run.
+:::
+
+## Migrating from Twisted to Asyncio
+
+In Twisted, coroutines were specified through the following syntax:
+
+```python
+from twisted.internet import defer
+from axros.util import cancellableInlineCallbacks
+
+class Example():
+ @defer.inlineCallbacks()
+ def example(self):
+ yield some_sleep_helper(2)
+ yield other_coroutine()
+ defer.returnValue("Done!")
+
+ # or
+ @cancellableInlineCallbacks
+ def other_example(self):
+ yield other_coroutine()
+```
+
+The second decorator, created by a former MIL member, was used to enhance `defer.inlineCallbacks`
+by allowing for the cancellation of nested coroutines. It's primary function was
+very similar to that of the standard `defer.inlineCallbacks` method.
+
+Now, we can use `asyncio` to achieve similar results:
+```python
+import asyncio
+
+class Example():
+ async def example(self):
+ await asyncio.sleep(2)
+ await other_coroutine()
+ return "Done!"
+
+ async def other_example(self):
+ await other_coroutine()
+```
+
+You'll notice some nice syntax improvements: the loss of a standard decorator to
+mark a method as being a coroutine, the use of special keywords made specifically
+for `async`, the ability to call `return` in a coroutine, and some helper functions
+provided by the standard `asyncio` library.
+
+## Coroutines, Tasks, and Futures
+There are three notable parts of `asyncio` you should be familiar with:
+* **Coroutines**: These are asynchronous functions. You can write these using
+ the `async def` syntax. Coroutines can be called with the `await` keyword to
+ start the execution of the coroutine.
+* **Futures**: A future is an object that is _immediately returned_ with the expectation
+ that it will have a populated value at a later date. You can `await` futures
+ to pause execution of the current method until the future has a result. In Python,
+ futures are reresented through the {class}`asyncio.Future` object.
+* **Tasks**: Tasks are high-level futures that are easier to work with in client
+ code. When writing high-level code (missions, for example), you should try to use
+ tasks, not futures. Tasks are represented in Python through the {class}`asyncio.Task`
+ class and are typically spawned through {func}`asyncio.create_task`.
+* **Awaitables**: This name refers to all three of the above, because all three of
+ the above can have the `await` keyword called on them.
+
+For some great examples of these three different classes, check out the Python
+documentation on {ref}`Coroutines `.
+
+## Help from `asyncio`
+The standard library `asyncio` will provide you a lot of help when working with
+awaitables. Let's take a look at some methods that you may want to use:
+
+* {func}`asyncio.sleep`: This coroutine pauses the parent coroutine for a specific
+ number of seconds. Useful!
+* {func}`asyncio.wait_for`: Sets a time limit for a coroutine: if the coroutine
+ does not finish within the time limit, then an exception is raised.
+* {func}`asyncio.wait`: Waits for a bunch of coroutines to finish in a certain manner.
+ This function can either wait for the first coroutine to finish, or it can
+ wait for all coroutines to finish.
+* {func}`asyncio.shield`: Prevents a coroutine from being cancelled.
+* {func}`asyncio.gather`: Run coroutines concurrently (ie, together). This can speed
+ up execution time by a great amount, but be weary of issues that may be caused
+ by running two coroutines at the same time (what if the other coroutine needs a resource
+ that can only be providd by the other coroutine?).
+* {func}`asyncio.create_task`: Creates a {class}`asyncio.Task` that begins the execution
+ of a coroutine all by itself. Similar to running a function in a thread. Note
+ that this method is not a coroutine, and therefore should not be called with
+ `await`.
+* {func}`asyncio.run`: Synchronous method that provides an entrypoint into an asynchronous
+ program. This should always be called if you need to call an asynchronous method
+ directly when starting a program. This should rarely be used if the program has
+ _already_ started.
+
+## Yielding Control
+When writing asynchronous functions, you need to be careful to avoid hogging the
+event loop. If you do this, you are going to prevent other coroutines from running
+at the same time.
+
+For example, this coroutine:
+```python
+async def uh_oh():
+ while True:
+ pass
+```
+would block all other coroutines on the event loop. This coroutine need to yield
+control.
+
+The simplest way to do this is to use {func}`asyncio.sleep`, even if the argument
+is zero. This coroutine will not end up blocking the event loop:
+```python
+import asyncio
+
+async def uh_oh():
+ while True:
+ asyncio.sleep(0) # Yield control to other coroutines!
+```
+
+## Typing `asyncio` Code
+As our repository becomes more and more typed, you may encounter a challenge where
+you need to type an asynchronous part of a program. How do you go about this?
+
+### Asynchronous Functions
+For most asynchronous functions, you can mark the return type as whatever
+the coroutine itself returns after being scheduled.
+
+```python
+import asyncio
+
+async def test(a: int, b: int) -> int:
+ await asyncio.sleep(2)
+ return a + b
+```
+
+However, if you want to type the actual asynchronous function itself, you will
+need to type the coroutine itself. You can either use {class}`collections.abc.Coroutine`
+or {class}`typing.Coroutine` for this. This type takes three generics. Usually,
+the first two can be {class}`typing.Any` - the third generic is the return type
+of the coroutine.
+
+```python
+import asyncio
+from collections.abc import Coroutine
+from typing import Any
+
+async def test(a: int, b: int) -> int:
+ await asyncio.sleep(2)
+ return a + b
+
+def gimme_a_test() -> Coroutine[Any, Any, int]:
+ return test(1, 2)
+```
+
+### Futures and Tasks
+Both {class}`asyncio.Future` and {class}`asyncio.Task` are generics, each taking
+one type: the result type of the future or task. While you are not required to type
+these classes as generics, its recommended for easier understanding later.
+
+```python
+import asyncio
+
+async def test() -> asyncio.Future[int]:
+ fut = asyncio.Future()
+ fut.set_result(3)
+ return fut
+```
+
+### {mod}`axros`
+{mod}`axros` now has a lot of great typing support for its asynchronous pieces.
+{class}`axros.Subscriber` and {class}`axros.Publisher` are generics which accept
+the message type that they are receiving and publishing.
+
+```python
+import asyncio
+from axros import NodeHandle
+from geometry_msgs.msg import Point, PointStamped
+
+async def main():
+ nh = NodeHandle.from_argv("my_special_node")
+ await nh.setup()
+ pub = nh.advertise("special_point", Point)
+ pub.publish(PointStamped()) # This is a type error
+ await nh.shutdown()
+
+asyncio.run(main())
+```
+
+## Using `uvloop`
+One extension that can be used on top of `asyncio` is an extension known as `uvloop`.
+When installed, this extension greatly speeds up the event loop itself, which helps
+the loop to move through coroutines faster. This can make your programs much more
+performant.
+
+Therefore, whenever you use {func}`asyncio.run`, you should also be using `uvloop.install`.
+```python
+import asyncio
+import uvloop
+
+uvloop.install()
+
+async def main():
+ ...
+
+if __name__ == "__main__":
+ asyncio.run(main())
+```
diff --git a/docs/software/bash_style.md b/docs/software/bash_style.md
new file mode 100644
index 0000000..7825914
--- /dev/null
+++ b/docs/software/bash_style.md
@@ -0,0 +1,13 @@
+# Bash Style Guide //TODO
+
+## Preamble
+All bash scripts should have the following lines at the top of the file:
+```
+#!/bin/bash
+set -euo pipefail
+```
+The first line allows the script to be executed from the terminal (e.g. `./my_script` rather than `bash my_script`) and the second line terminates the script if any command fails.
+
+Please also observe the following additional style rules:
+
+* Indent using 2 spaces
diff --git a/docs/software/calibrating_cams.md b/docs/software/calibrating_cams.md
new file mode 100644
index 0000000..376900f
--- /dev/null
+++ b/docs/software/calibrating_cams.md
@@ -0,0 +1,76 @@
+# Calibrating Cameras
+// TODO: Currently written by AI to quickly update to ROS2. Add more information later.
+
+When using a camera, calibration is required to ensure that we are able to receive images with no distortion. If we receive distorted images, it may be more difficult to reconstruct a 3D scene from the camera. Examples of camera distortion and a more detailed process on calibrating cameras can be found on the [OpenCV website](https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html).
+
+Camera calibration should only need to be performed once per camera model, as the distortion produced by one camera should generally be the same as another camera of the same model. However, if two cameras of the same model have different settings, then calibrating both cameras individually may be required.
+
+## Calibrating a New Camera
+
+Upon receiving a new camera, follow the instructions below to calibrate the camera for ROS 2:
+
+1. **Ensure Camera Detection:**
+ Confirm that your camera is connected and visible in ROS 2. You can check available topics by running:
+ ```bash
+ ros2 topic list
+ ```
+
+2. **Create a Launch File:**
+ Create a new ROS 2 launch file for the camera. For example, create a file named `camera_calibration.launch.py` with the following content:
+ ```python
+ from launch import LaunchDescription
+ from launch_ros.actions import Node
+ from ament_index_python.packages import get_package_share_directory
+ import os
+
+ def generate_launch_description():
+ config_file = os.path.join(
+ get_package_share_directory('your_camera_package'),
+ 'config',
+ 'camera_params.yaml'
+ )
+ return LaunchDescription([
+ Node(
+ package='usb_camera_driver',
+ executable='usb_camera_node',
+ name='camera',
+ output='screen',
+ parameters=[config_file],
+ remappings=[('/image_raw', '/camera/image_raw')]
+ )
+ ])
+ ```
+
+3. **Run the Camera Calibration Tool:**
+ Launch the ROS 2 camera calibration tool by running:
+ ```bash
+ ros2 run camera_calibration cameracalibrator --size 8x6 --square 0.024 --camera_name camera
+ ```
+ *Note: Modify `--size` (checkerboard dimensions) and `--square` (square size in meters) according to your calibration pattern.*
+
+4. **Calibrate:**
+ A GUI will appear. Move a sturdy checkerboard in front of the camera until the GUI accumulates enough samples. Then click "Calibrate" to generate the camera's parameters.
+
+5. **Save Calibration Parameters:**
+ Once calibration is successful, save the new calibration parameters to a YAML file. This file will be referenced by your launch file.
+
+6. **Update the Launch File:**
+ Modify your camera launch file to include the path to the new calibration YAML file so that the camera node uses the correct parameters.
+
+7. **Verify Calibration:**
+ Verify that calibration is successful by checking the **rectified image topic**:
+ ```bash
+ ros2 topic echo /camera/image_rect
+ ```
+ **Warning:** Only verify using the rectified image topic. The raw or color image topics may still display distortion.
+
+## Additional Resources
+
+For more details on camera calibration with ROS 2, refer to:
+- [OpenCV Calibration Tutorial](https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html)
+- ROS 2 documentation on [Camera Calibration](https://docs.ros.org/en/galactic/Tutorials/Camera-Calibrations.html) *(replace with the appropriate version if necessary)*
+
+:::{warning}
+Ensure that you use the updated ROS 2 commands (`ros2 run` instead of `rosrun`), Python launch files instead of XML, and `get_package_share_directory()` instead of `$(find ...)` in your configuration.
+:::
+```
\ No newline at end of file
diff --git a/docs/software/contributing.md b/docs/software/contributing.md
new file mode 100644
index 0000000..0b40304
--- /dev/null
+++ b/docs/software/contributing.md
@@ -0,0 +1,172 @@
+# Contributing Guide
+This guide describes how to make a change in the repository, and contribute this
+change back to the lab.
+
+## Sanity with Git
+This guide will show you how to make real, actual changes with Git. For many new
+members, that can be scary, and you may feel as though you might type in a wrong
+command and break everything! The good news is that this can't happen.
+
+Git works by giving you your own personalized copy of our source code. This copy
+can only be found on **your** computer! No one else has access to it. Therefore,
+you can't really hurt anyone else's progress. Even if you run some commands that
+mess up your copy, you can ask for a new one! How sweet is that?
+
+More so, we use branch protection, so you can't push code onto the robot without
+approval from a leader first. Therefore, don't feel pressured to always type the right
+command - you might screw up, and it's all okay!
+
+Now, back to the guide...
+
+## Setting up `pre-commit`
+If you have not already done so, it is highly recommended to set up `pre-commit`.
+While not required, this tool will help you debug any spelling mistakes, trailing
+whitespace, or formatting errors you have before your changes ever reach CI. If
+you don't use `pre-commit`, the chances of your changes failing in CI is somewhat
+high, as one spelling mistake could require you to modify your work once more.
+
+For information on setting up `pre-commit`, see the [page on developer tools](/software/devtools).
+
+## Find a project
+If you don't yet know what you want to work on, see our [issues list](https://github.com/uf-mil/mil/issues).
+We have a variety of projects to work on, and you can select a task in whatever
+project you'd like!
+
+## General contributing process
+For those unfamiliar with git, this will the general idea.
+1. Create a new branch off of the master branch (or branch off of another branch
+you want to fix).
+2. Make changes on that new branch.
+3. Add files that you will want to commit (You can think of a commit like a
+save file that you can go back to at any moment in time).
+4. Create a commit (This is actually creating the "save file").
+5. Push the commit to the remote branch.
+6. Create a pull request on GitHub that compares your branch to master branch.
+
+Check out [this cool link](https://rogerdudler.github.io/git-guide/) if you want
+another overview of Git!
+
+## Create a new branch
+Create a new branch for your changes `git checkout -b `. Be sure to
+pick a descriptive name (usually 2-4 words, joined by dashes will do). The specific
+name of the branch generally does not matter.
+
+## Viewing the status of files
+You can see all the changes that have been made with these commands:
+
+ $ git status # see the status of all files (what's changed, deleted, added, etc.)
+ $ git diff # see the changes you've made
+
+You may notice something called the "stage" and that files are either "staged" or
+"unstaged". The stage covers everything that will be committed when you commit.
+Usually, staged files are "ready" to be shown to someone else. Staged files shouldn't
+usually contain sensitive information, files unrelated to MIL, etc.
+
+It's sort of like if you have a folder with homework that's ready to turn in. You
+may finish your homework two days before it's due and put it in this folder, "staging"
+it. It's not officially turned in (that will happen when we commit), but it's ready to go!
+
+## Adding file to be staged for a commit
+You can add all these changes to be staged like this:
+
+ $ git add .
+
+Or if you have only certain files you want to add:
+
+ $ git add
+
+Be sure to only change the files you intend to and don't add any files that aren't needed.
+
+## Committing changes
+After a while, you'll want to make a **commit**. A commit is a point in time in the repository.
+It holds the status of every file in the repository at a particular time. This is
+super helpful - let's say you accidentally deleted an important file. You can go
+back to the previous commit, and grab the file again.
+
+You will need to provide a short description of your change when you commit it.
+
+ $ git commit -m "Description of what changed goes here"
+
+## Pushing your commit
+Now, you have made one or more commits, but unfortunately, these changes are still
+only available on your local copy. Let's change that, with pushing!
+
+Pushing commits allows everyone in MIL to see your work. This allows leaders to
+approve your work and other MILers to build on what you've built!
+
+:::{danger}
+Note that pushing your changes will make them available to everyone on the Internet.
+Therefore, never commit sensitive info containing personal info about you or someone
+else.
+:::
+
+Push your development branch to GitHub using:
+
+ $ git push origin
+
+This `push`es your changes to the `origin` (aka GitHub) relative to the branch
+`branchname` (the branch you made earlier).
+
+You may need to use the `-u` flag on your first `git push`. This allows git to register
+the branch you're pushing to as the one you always want to be pushing to.
+
+
+## Creating a pull request
+Now that your changes have been committed, it's time to submit them to be
+reviewed and then merged into the repository on GitHub.
+
+To create a new pull request, head over to the `Pull Requests` tab of our GitHub
+page and create a new pull request. Choose which branch to merge into `master` (or
+whatever other branch you're trying to merge your code into), and a dialog should appear.
+Add a title and body explaining what is changing. If you know what project your task
+is related to, you can also connect your PR to a project on the right-hand side of
+the interface.
+
+## Request and wait for review
+To ensure our code quality and robot safety, we require all code to be reviewed
+by at least one core developer before merging.
+
+When you first opened your PR, you may have noticed a spinning yellow circle on
+the page. This is our continuous integration. It's a friendly robot running your
+code to check for any possible errors. If your code contains no errors, then a green
+checkmark will appear, helping your reviewer to know that your changes are prime to accept.
+If it doesn't pass, you'll see a bright red X, indicating that you need to review your
+changes and fix something. See the next section below.
+
+If you have a friend in MIL or someone with a good knowledge of the things you
+changed, you can assign them as a reviewer on GitHub. If it has been a few days
+and no one has looked at your pull request, you can also bug people in slack.
+We strive for a 24-hour turn around for the first review.
+
+## Amend pull request
+Unless you are a true prodigy (or your reviewer is lazy), there will likely be
+some changes requested in your PR. After making the requested changes, you need
+to commit them and push them.
+
+* You should merge in upstream changes before making your changes. See the section below.
+* Look at the changes you made with `git status` and `git diff`.
+* Add the files you wish to keep to staging `git add ` (or all files with `git add .`).
+* Commit the changes with a descriptive message `git commit -m ""`.
+* Push your new commit to the same branch you submitted your PR from `git push origin `.
+
+Now it's time to wait for reviews again, this time hopefully you will be approved.
+
+## Merging in upstream changes
+If changes made by other developers are merged in before your pull request, you will have to update
+you pull request to include these changes. This can sometimes be a tedious process if changes
+were made to the same files you changed.
+
+* Fetch the latest changes from upstream (this caches them locally, not
+changing any of your code): `git fetch origin`.
+* Backup your current branch in case anything goes wrong during the rebase with `git checkout -b -backup`,
+and then go back to your original branch `git checkout `.
+* Rebase your changes to the latest master branch `git rebase -i origin/master`
+* This will open up your text editor with a list of the commits that will be
+added on top of master. Be sure to comment out (by adding `#` before the line)
+any commits that are not yours.
+* Save and close the text editor. Git will now attempt to rebase your changes
+on top of the master branch. If git detects a conflict, it will prompt you
+on how to manually fix them.
+* Once you have gone through the whole process and git says the rebase was
+successful, push your updated branch `git push origin -f `. Note
+the `-f` which you need as you have re-written history
diff --git a/docs/software/cpp_style.md b/docs/software/cpp_style.md
new file mode 100644
index 0000000..99a25c5
--- /dev/null
+++ b/docs/software/cpp_style.md
@@ -0,0 +1,512 @@
+# C++ Style Guide
+Welcome to the C++ style guide! This style guide briefly explains how we write
+our code to do crazy robot things, and how we'd like you to write yours, too!
+This style is used in our continuous integration process to make sure that all
+code submitted to our repository is somewhat organized and maintainable.
+
+Don't feel pressured to read this entire guide line-by-line and write down every
+little note. We have tools that help you follow this style without you knowing most
+of the style. However, this guide is meant to serve as the de-facto standard for
+our C++ style, so if you have a question as to why something is formatted, you
+can propose a change to this guide and the tools that help to enforce it.
+
+## Where it Started
+Most of this style guide comes from a combination of the [ROS style guide](http://wiki.ros.org/CppStyleGuide)
+and the [Google C++ style guide](https://google.github.io/styleguide/cppguide.html).
+These guides are extensive, and generally complement each other, as the ROS style
+guide is loosely based on the Google style guidelines. Additionally, some of the more
+philosophical aspects may be pulled from the [ISO C++ style guide](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines).
+
+## Enforcement
+While being able to have a style reference is important, how are these guidelines
+actually enforced? Generally, enforcement is done in two areas:
+
+* [Pre-commit](https://pre-commit.com) (before you push)
+* Continuous integration (when you open a pull request)
+
+Pre-commit is a new tool to MIL that will be pushed with the Noetic + Alabaster project.
+Pre-commit is a tool that executes a script right before you commit. This tool
+can run ``clang-format``, a tool dedicated to formatting and enforcing style on
+C++ style. Pre-commit will be expanded on more when the Noetic + Alabaster project
+is officially done.
+
+Continuous integration is the service that makes sure that new code added to the repository
+is ready to be added. Continuous integration runs a plethora of checks, including
+style checks on C++ code. This means that if your code does not comply with the C++
+style guidelines when you push, it may be denied, requiring you to go fix it.
+
+## Philosophy
+Before discussing the nuts and bolts of our desired C++ style, we'll offer a brief
+on our "code philosophy". These are guidelines that will generally not be checked
+by CI or automated systems. Rather, it's generally up to your friendly fellow MILers
+to try to encourage the following of these philosophies.
+
+In general, try to make your code **user-friendly**. This is super important, since
+all of us at MIL are humans, not computers! While computers run our code, they never
+innovate on it, they run whatever we tell them. It's up to us to work together
+to innovate new solutions in our programming so that these robots can do new things.
+
+### 1. Be expressive, not restrictive
+(Based on [ISO C++ style P1](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rp-direct))
+
+When writing code, try not to be cryptic or restrictive. Let's say you're writing
+code to find objects in an image, and you want to write a method that returns
+the position of the first image you find:
+
+```cpp
+std::vector SpecialObjectFinder::getLocationFirstImage();
+```
+
+What does that `std::vector` do? What does it represent? Let's try again.
+
+```cpp
+Position SpecialObjectFinder::getLocationFirstImage();
+```
+
+Oh - a position! In the first example, the `std::vector` was actually a vector
+of two ints representing an x-value and y-value in the camera image of the center of
+the object. That's hard to communicate without external documentation. However,
+using another class, `Position` communicates the functions' goal much clearer - it's
+meant to return a position. This class has x and y attributes.
+
+In this regard, attempt to create and abstract new data structures when you write
+code. If you're code is becoming complicated with exceptions and conditional statements
+all over the place, consider asking yourself if there's any way to slim down some of
+the functionality. Check out the ISO example above for an example involving finding
+an element in an iterator.
+
+Ask yourself how you express _your ideas_ write into the code!
+
+## Version
+All the code should target the C++11 standard. This is typically enforced in each
+package's `CMakeLists.txt` file.
+
+## Style Guide
+This section explains the actual style practices we encourage when writing C++
+code for MIL.
+
+### Naming
+_Source: [ROS C++ style 4](http://wiki.ros.org/CppStyleGuide#Naming),
+[Google Style Naming](https://google.github.io/styleguide/cppguide.html#Naming)_
+
+Below explains the process of naming various resources around the repository.
+
+#### Files
+When naming your files, use **underscores**, and attempt to be descriptive, but
+not lengthy. Consider if someone new to that package would be able to guess what's
+in that file without opening it, based on its name.
+
+For the extensions, use `.cpp` for a C++ file, and use `.h` for a header file.
+There's no reason to use `.cc` or `.cxx` or `.hpp` or any other extension.
+
+#### Classes/Types
+For classes and types, use title case. If the phrase contains an acronym, then feel
+free to only use upper letters for the acronym:
+
+```cpp
+class DrSchwartz;
+class GCPUImplementation;
+```
+
+#### Functions
+Functions should use camel case. This is like title case, but the first letter is not
+capitalized.
+
+```cpp
+void undoTransformation();
+ExampleClass constructFromMessage();
+```
+
+One exception to this rule is the naming guidelines for accessors and mutators.
+These can be named similarly to variables:
+```cpp
+class Car {
+public:
+ void set_speed(int speed); // Woah, a setter...
+ int get_speed(); // and a mutator!
+private:
+ int speed_;
+};
+```
+
+#### Variables
+Variables (including function arguments) should use snake case. For example:
+```cpp
+int thisIsNotGood; // No!
+int this_is_good; // Yes!
+
+void exampleFunction(bool argOne, std::string awesomePhrase); // No!
+void exampleFunction(bool arg_one, std::string awesome_phrase); // No!
+```
+
+Please remember to also be descriptive with your variable names. There's no need
+to be cryptic or needlessly short with your variable names.
+```cpp
+int x; // What is this supposed to represent?
+int rotations; // Oh, the number of rotations!
+
+bool wsy; // What is this??
+bool was_seen_yesterday; // Ah, that helps much more!
+```
+
+Furthermore:
+* Constants should use all capitals. For example, ``SPEED_OF_LIGHT``. This also
+ applies to the values of enumerators.
+* Member variables (of classes, not structs) should have a trailing underscore.
+ For example, ``internal_attribute_``.
+* Global variables should be prepended with ``g_``. For example, ``g_global_attribute``.
+
+#### Namespaces
+Namespaces should use underscores. Namespaces should never be named ``std``, and
+common namespace names (such as ``util``) should be avoided. Using these namespaces
+can create problems when using fully-qualified lookups in C++. ([What is that?](https://abseil.io/tips/130))
+
+```cpp
+namespace large_hadron_collider {
+ ...
+}
+```
+
+### Formatting
+_Source: [ROS C++ style: 6](http://wiki.ros.org/CppStyleGuide#Formatting),
+[Google Style: Formatting](https://google.github.io/styleguide/cppguide.html#Formatting)_
+
+#### Line Length
+Each of your lines should no more than 120 characters long. Generally, 80-100 characters
+is still acceptable, but if you can avoid it, please do.
+
+One may wonder, why does this matter? Generally, this helps users who have smaller
+screens and users who prefer to work with split screens. Additionally, very long lines
+can be confusing to readers of code who may see a very long line as two split lines.
+
+There are some exceptions to this rule:
+* A comment which contains a long string, such as a URL.
+* A string which can't be wrapped. For example, a string containing a long URL, or
+ a string where the newlines are significant, such as a help message.
+* An include statement.
+* A header guard.
+* A `using` declaration.
+
+If a tool (like `clang-format`) complains about the line length anyway, you will
+need to disable the tool on the lines where it is complaining.
+
+#### Indentation
+Always use spaces, and always use 2 spaces for indentation.
+
+#### Floating Points
+When using floating point numbers in C++, either use an integer to initialize the float,
+or use a radix point with numbers on both sides. If you want to use exponential notation
+with the number, use either an `e` or an `E`.
+
+```cpp
+float f = 1.f; // Nope: Use numbers on both sides of the radix point.
+long double ld = -.5L; // Same as above;
+float f = 1.0f; // Awesome!
+float f2 = 1; // This works great, too!
+long double ld = -0.5L; // Fantastic work!
+
+double huge = 1254e4; // Nope: Where's the radix point?
+double huge_again = 1254.0e4; // Nice!
+```
+
+#### Function Calls
+When using function calls, sometimes you may need to call a function with a ton of
+arguments, which can cause the call to become excessively long.
+
+If you need to break up the function call, you can align the rest of the arguments
+in the function call with the first argument. If you've already indented, then you
+can use a four space indent to align the arguments.
+
+```cpp
+bool result = funnyFunction(huge_argument_number_one_oh_my_this_is_long,
+ argument_two, argument_three);
+
+if (...) {
+ if (...) {
+ while (...) {
+ bool result = funnyFunction(huge_argument_number_one_oh_my_this_is_long,
+ argument_two, argument_three);
+ }
+ }
+}
+```
+
+Sometimes, the arguments of function calls might be complex. In this case, feel
+free to put one augmenter on one line by itself.
+```cpp
+bool result = weirdMathFunction(quat[1] + std::sqrt(quat[2]) & 8, // Crazy Scientist A's matrix determinant formula
+ argument_two, argument_three);
+```
+
+Sometimes, you may want specific arguments to exist on specific lines for readability.
+This is totally okay, too!
+```cpp
+int magic[][] = createMagicSquare(x1, x2, x3,
+ y1, y2, y3,
+ z1, z2, z3);
+```
+
+#### Braces
+When using braces for conditions or control logic, place the braces on a new line.
+In the case that the logic inside a control block is short (one line or less),
+then the braces can be excluded. An exception to this rule is `switch` statements, discussed
+below.
+
+```cpp
+if (example_term)
+{
+ ...
+}
+
+if (simple_test)
+ simpleCall();
+
+if (this_works_too)
+{
+ simpleCall();
+}
+
+while (condition_is_true) continue;
+```
+
+For cases where braces are excluded, there should be no other conditional statement
+other than the primary statement. For example, a conditional block using no braces
+should only use an `if` statement and should not have an `else if` or `else` clause.
+
+#### Conditionals
+Conditional blocks should always use spaces to break up key terms. For example,
+the `if` keyword and the expression inside the parentheses following the `if`
+keyword should be separated by a space. This likewise applies to `else if` and `else`.
+
+```cpp
+if (this_is_perfect) {
+ // Great job!
+ ...
+} else if (wow_you_did_it == again) {
+ ...
+}
+```
+
+#### Switches
+For `switch` blocks, braces are optional. Attempt to be consistent throughout a particular
+package.
+
+In the case of fallthrough (ie, the exclusion of `break` in a case statement),
+please add a comment indicating fallthrough. Some tutorials might suggest the use
+of the `[[fallthrough]]` attribute, but unfortunately, this is only allowed in C++17
+and further.
+
+```cpp
+switch (x) {
+ case 1:
+ ...
+ break;
+ case 2:
+ ...
+ break;
+}
+// or
+switch (x) {
+ case 1: {
+ ...
+ break;
+ }
+ case 2: {
+ ...
+ break;
+ }
+ default: {
+ ...
+ break;
+ }
+}
+```
+
+#### Loops
+Loops are similar to conditional statements. Braces can be avoided for very short
+loops, or they can be kept in.
+
+For loops with no bodies, either use a pair of empty braces or use the `continue`
+statement to indicate that the loop is continually running.
+```cpp
+for (int i = 0; i < 10; i++)
+ sum += i;
+
+while (tired) {
+ drinkCoffee();
+}
+
+while (spin_forever) continue;
+```
+
+#### Pointers and References
+When using pointers and references, place the * or & either before the space, or
+after the space. Keep this syntax the same throughout one file.
+
+In some cases, such as using pointers as a template parameter, you can remove the space
+entirely.
+
+Never declare more than one pointer on a single line, as this expression is often
+misread.
+
+```cpp
+int* x;
+p = &x;
+
+char *c;
+const int& p = &x;
+
+CharClass example;
+
+int * x; // No!
+const int & a; // Sad face.
+```
+
+#### Preprocessor Directives
+Preprocessor directives always start at the beginning of the line, full stop.
+This may appear to break up indentation - this is fine! The examination of preprocessor
+directives is important, and using significant indentation helps to show this.
+
+You can optionally use spaces after the `#` for nested preprocessor directives.
+
+```cpp
+if (test_condition) {
+ #if LETS_GO_CRAZY
+ startCrazyMode();
+ #endif
+ cleanup();
+}
+```
+
+#### Class Structure
+When structuring your class definition, use one space to indent the `public`, `protected`,
+and `private` keywords. Then, use the traditional two-space indent for all other
+needed members in the class.
+
+```cpp
+class ExampleClass : public BaseClass {
+ public:
+ ExampleClass();
+ ~ExampleClass() {}
+
+ protected: // Do not leave a blank line after these keywords
+ someFunction();
+
+ private:
+ int some_var_;
+ char special_char_;
+};
+```
+
+#### Namespaces
+Namespaces do not add an extra level of indentation.
+
+```cpp
+namespace cooking {
+class Pan {
+ public:
+ void pourCupcake(int row, int col);
+ Cupcake retrieveCupcake(int row, int col);
+
+ private:
+ Cupcake[][] cupcakes_;
+};
+}
+```
+
+#### Horizontal Whitespace
+General rules about horizontal whitespace:
+
+* Comments at the end of a line should be separated from the contents of the line
+ by two spaces.
+* Semicolons should generally not have spaces before them.
+* The colon in a class initializer list should generally have a space around it.
+* Keywords in control blocks (`if`, `for`, `while`, etc.) should have a space around them.
+* Semicolons inside a `for` statement generally have a space after them. (Ie, `for (int i = 0; i < 5; i += 2)`)
+* Colons in range-based for loops generally have spaces on both sides.
+* Assignment operators (`x = 0`, `x += 5`)generally have spaces on both sides.
+* Binary operators (`x + y`, `x || y`) traditionally have spaces, but these can be removed in select scenarios.
+* Unary operators (`!x`, `&x`) almost never have spaces between them and their subject.
+
+#### Vertical Whitespace and Blank Lines
+Vertical whitespace is helpful, **sometimes**. Vertical whitespace generally includes
+blank lines.
+
+Use blank lines to separate thoughts inside a particular scope (class definition,
+function, etc.).
+
+There is no need to start/end a function with a blank line. Adding a blank line
+before a comment can help with readability, as can using a blank line without any
+associated comment to split two different ideas.
+
+### C++ Features
+C++ comes with a lot of cool features, but these features can sometimes cause problems.
+We must be careful about which ones we intend to use.
+
+#### Preprocessor Macros
+Don't use them. Macros are likely going to cause us more trouble than they're worth
+because of their global scope and unfriendly use.
+
+#### Namespaces and `using`
+Namespaces are a great way to separate code. The `using` keyword allows one to use
+code from a separate namespace somewhere else. For example:
+
+```cpp
+using std::list;
+```
+
+When using `using` (did you smile at that? I hope so!), try to keep the statements specific.
+Don't try to use all of `std`, which could pollute a file's namespace. Instead,
+try to use specific things from `std`.
+
+#### Friends
+Everyone loves having friends, and C++ does, too. Use the `friend` keyword cautiously
+throughout your C++ code. Where it is used, please try to keep the friend to the same
+file so that a user does not have to go look in another file.
+
+It may also be desired to conduct unit tests through the `friend` keyword.
+
+#### Exceptions
+Use exceptions judiciously. Exceptions are great for representing true failures
+in a particular piece of code, and can allow for the abstraction of error handling methods.
+
+However, exceptions can also introduce weird behavior into a piece of code. Exceptions
+can cause functions to return before one thinks they will, and can cause issues if another
+function catches a particular error before another function.
+
+User input at runtime (this is rare when working with autonomous vehicles, yes) should
+never throw an exception. An exception represents a code failure, not the failure
+of one user to input a proper expression into a live piece of code.
+
+#### `const`
+Use `const` wherever it is appropriate. `const` can help the compiler ensure that
+some classes and methods are only mutating a few select values. Remember though
+that `const` can quickly become viral; ie, if you pass a `const` variable to a function,
+that function will need `const` in its prototype.
+
+#### Using `sizeof`
+When using `sizeof`, prefer the use of a variable as the argument, rather than the use
+of a class or type.
+
+### ROS Helpers
+#### Assertions
+When using assertions in a piece of C++ code, please use a function from the family
+of `ROS_ASSERT` functions.
+
+#### Printing
+When printing to the console, please use the `rosconsole` family of functions.
+
+#### Deprecation
+To mark a function as deprecated, add the `ROS_DEPRECATED` attribute to its signature.
+To mark a class as deprecated, mark all of its functions as deprecated.
+
+```cpp
+ROS_DEPRECATED int cardCount();
+
+class MyClass {
+ public:
+ ROS_DEPRECATED MyClass();
+
+ ROS_DEPRECATED void specialFunction();
+};
+```
diff --git a/docs/software/devtools.md b/docs/software/devtools.md
new file mode 100644
index 0000000..e37833d
--- /dev/null
+++ b/docs/software/devtools.md
@@ -0,0 +1,204 @@
+# Developer Tools
+
+If you're interested in sticking around in MIL for a while (as we hope you are!),
+we recommend installing some tools that will make your work a little easier.
+These tools serve to be like little assistants, politely cleaning up your code
+behind you and warning you about potential errors that may occur as you change
+existing code and contribute new code.
+
+Let's discuss how we can use some of these tools.
+
+## `pre-commit`
+
+One tool that most developers (if not all) should have installed is `pre-commit`.
+This command-line tool checks your code for linting errors, spell check errors,
+unneeded whitespace, and the formatting of your files. And, it does this
+automatically, without you even needing to ask! How awesome is that?
+
+`pre-commit` runs on a shared config file that all MIL members use.
+This config file specifies what the tool should check for, such as if you have
+extra whitespace at the end of the line. When you attempt to commit changes to
+the repo, the tool will block your commit if it finds any errors. Some of the
+hooks will automatically format the code into the proper way for you, while
+others will show you what part you need to change yourself.
+
+Furthermore, our CI checks use the same hooks specified in the config file. This
+means that if `pre-commit` does not pass on your local computer, it's not going
+to pass when you try to merge it into the robot's codebase. Therefore, it's
+highly recommended to install the tool to save yourself some time in the long run.
+
+### Installing
+
+To install `pre-commit`, use `pip`! We specify the version of `pre-commit` in
+a requirements file, which is why you reference it in the command below.
+
+```sh
+$ pip3 install -r requirements.txt
+```
+
+After doing this step, you should be able to run the `pre-commit` command. Now,
+we will install the hooks specified in our config file. This command will also
+install a git hook into your git configuration. This allows the tool to run right
+before you attempt to commit a piece of code.
+
+```sh
+$ pre-commit install
+```
+
+Now, try to run it against all of our files! It should show that all tests have
+passed. Some may have been skipped.
+
+```sh
+$ pre-commit run --all-files
+```
+
+If you have any trouble with this tool, feel free to check out
+[the pre-commit website](https://pre-commit.com).
+
+## Vim
+
+Another helpful developer tool is having a good Vim configuration, if that's the
+editor you choose to use (the most popular editor amongst MIL members).
+A good Vim configuration can provide helpful code suggestions and diagnostic
+features, helping you to catch errors write after you write a particular line
+of software.
+
+We'll see how we can set up a helpful Vim configuration below.
+
+### Introducing Vim
+
+What is Vim, anyway, and why do many MIL members use it? Vim is a code editor
+that runs inside your terminal. You may know of other editors such as VSCode
+or PyCharm or CLion, but these are GUI programs. You can click around them and
+press a bunch of buttons to do things.
+
+In Vim, there are no buttons, and usually, no clicking. You only use your keyboard
+to do everything you want (to move, to change settings, delete lines, etc.).
+How? A bunch of keyboard shortcuts, and a "Vim language" for coordinating movement!
+These settings make Vim super flexible, allowing you to bring the software generally
+anywhere.
+
+There are a lot of great Vim tutorials around the Web, so we won't discuss many
+of the keyboard shortcuts here. If you're interested in learning the Vim way,
+feel free to search for a book, game, or guide that walks you through the editor.
+Because many MIL software leaders use Vim or have used Vim before, we are here
+to help you out as well!
+
+### Installing Neovim
+
+A popular fork of the Vim project is a piece of software named Neovim. This
+project adds more functionality to Vim, allowing for more flexibility in
+extensions and modifications.
+
+You can install Neovim through:
+
+```sh
+$ sudo apt-get install neovim
+```
+
+### Installing a distribution
+
+One method for getting a nice Neovim setup going involves installing a particular
+distribution of the software. These distributions come with a pre-configured
+set of extensions and configuration files that make setting up a nice helpful
+Neovim configuration painless!
+
+Some popular Neovim distributions include:
+* [SpaceVim](https://github.com/SpaceVim/SpaceVim)
+* [LunarVim](https://github.com/LunarVim/LunarVim)
+* [spf13's Vim configuration](https://github.com/spf13/spf13-vim)
+* [NvChad](https://github.com/NvChad/NvChad)
+
+If you choose to set up one of these distributions, you don't need to read
+the rest of the tutorial, and you'll have nice features in your own Vim configuration!
+That's really cool, which makes this a great option! However, if you'd like to set up
+your own configuration, keep reading.
+
+### Writing a configuration
+
+You may be inclined to write your own configuration for Neovim! That's great.
+Chances are if you do this, you'll be able to learn a lot about Vim and Neovim
+in the process. However, it's also a lot. Because there's so much to it, we won't
+walk through the process here. However, here are some things you may want to set up:
+
+* Installing an extension manager ([vim-plug](https://github.com/junegunn/vim-plug) for example!)
+* Setting up a reasonable escape key (such as `jk`)
+* Setting up integrated LSP (Try checking out [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig)!)
+* Setting up diagnostics and formatters used in `pre-commit` with [null-ls.nvim](https://github.com/jose-elias-alvarez/null-ls.nvim)
+* Finding a beautiful colorscheme!
+* Setting up extensions to make your life easier (A lot of great ones can be found at [vimawesome](https://vimawesome.com/))
+
+## Tmux
+Tmux is a famous terminal multiplexer that allows for more flexibility over your
+terminal environment. Specifically, the program can enable you to pause terminal
+environments when your terminal session closes, switch between terminals quickly,
+and view multiple terminal panes at once. If you are going to work on the live robots,
+you should have the program installed, as it allows multiple members to share the
+same terminal environment on the robot at the same time.
+
+To learn more about Tmux in general, check out the [Tmux GitHub wiki](https://github.com/tmux/tmux/wiki).
+A quick reference sheet can be found at [https://tmuxcheatsheet.com](https://tmuxcheatsheet.com/).
+
+### Tmuxinator
+Managing Tmux sessions manually can be extremely time-consuming, so we use
+tmuxinator to provide a version controlled interface for our robots and
+simulators. Basic commands are:
+
+```sh
+$ tx list # show configs available to start
+$ tx start # start (or join if already started) a tmuxinator session
+$ tmux ls # Show active all tmux sessions ( not only ones started by tmuxinator )
+$ tx stop # stop a session that is running
+```
+
+The MIL configs for tmuxinator are hard linked from
+`$MIL_REPO/.tmuxinatorConfigs/.yaml` to `~/.config/tmuxinator/.yaml`.
+If you want to add personal tmuxinator configurations you, should add them in
+`.config/tmuxinator/`. If you want to add MIL-wide configs, place them in
+`$MIL_REPO/.tmuxinatorConfigs`.
+
+## Bash and Zsh
+
+Furthermore, our team's upgrade to ROS Noetic brought another feature: support
+for the Zsh shell. This shell is an alternative to the Bash shell (the default
+shell on Ubuntu). Zsh has some more features than Bash, which might interest
+you.
+
+Note that either shell works, and you should explore around to see if switching
+to the Zsh is more in-line with your preferences. We'll walk below setting up
+some helpful tools for both below. You should set up one or the other; not both.
+
+:::{note}
+Because of the flexibility of `bash`, all shell scripts should be written in
+`bash`, not `zsh` or `sh`. You can designate a script as being a bash script
+by using the `#! /bin/bash` shebang at the top of the file. The Z shell runs
+these scripts fine.
+:::
+
+### Bash
+
+By default, the main configuration file for the Bash shell is the `~/.bashrc`
+file. In here, you can set up plugins, set aliases, and run commands when your
+shell starts up. Pretty helpful!
+
+A recommended plugin for your Bash terminal is setting up `oh-my-bash`.
+[This plugin](https://github.com/ohmybash/oh-my-bash) allows you to add
+themes and plugins into your terminal using your configuration file. On the
+project README, you can see how to set up the plugin and begin configuring
+plugins and themes.
+
+### Zsh
+
+The alternative to the default Bash shell is the Z shell, commonly known as `zsh`.
+This shell is becoming more mainstream as time goes on due to its increased
+flexibility over the bash shell. The main configuration file for this shell is
+`~/.zshrc` - this is where you can put aliases and various configuration values,
+similar to bash's `~/.bashrc`.
+
+A common plugin for the Z shell is the [`oh-my-zsh` plugin](https://github.com/ohmyzsh/ohmyzsh).
+This project is one of the largest repositories on GitHub, and comes with a
+multitude of themes and extensions.
+
+You may also want to check out [Powerlevel10k](https://github.com/romkatv/powerlevel10k),
+which displays helpful information in your shell prompt, such as `git` info. It's
+definitely worth checking out.
diff --git a/docs/software/documentation_syntax.md b/docs/software/documentation_syntax.md
new file mode 100644
index 0000000..8c975fc
--- /dev/null
+++ b/docs/software/documentation_syntax.md
@@ -0,0 +1,199 @@
+# Documentation Syntax
+## ReStructured Text
+
+One of the most common formats you'll see used for documentation is ReStructured
+Text, or RST. These files usually end in `.rst`. Furthermore, all docstrings
+are automatically rendered using RST.
+
+To create and edit documentation, you don't need to know too much RST. For a nice
+introduction, check out [this primer](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html).
+
+If you're writing new documentation, feel free to write it in RST, or the alternate
+MyST, described below.
+
+## Markdown and MyST
+
+While RST is great (and used by default), its syntax can sometimes feel dated and
+old. Therefore, a replacement was developed: MyST. Similar in name, this alternate
+parser allows you to write documentation using Markdown rather than RST.
+
+To use MyST instead of RST, write documentation files in Markdown instead of RST!
+Using a `.md` extension should be enough to tell Sphinx which parser to use.
+
+Everything that's available through the RST syntax can be found in MyST - the syntax
+is a little different. For more information on MyST and how to use it, check out
+its [documentation](https://myst-parser.readthedocs.io/en/latest/index.html).
+
+## Admonitions
+
+Sometimes, you want to make things a little more evident. Admonitions are great
+for this purpose. Admonitions are the "Danger" or "Note" boxes that you see
+around the docs.
+
+They are compatible with both RST and MyST and support a variety of syntax:
+
+```rst
+.. danger::
+
+ It's dangerous to go alone! Take this admonition.
+```
+
+:::{danger}
+It's dangerous to go alone! Take this admonition.
+:::
+
+```md
+:::{warning}
+Oh my gosh! Be careful.
+:::
+```
+
+:::{warning}
+Oh my gosh! Be careful.
+:::
+
+## Docstrings vs. Explicit Documentation
+There are two main types of document in our repository: docstrings and explicit
+documentation.
+
+Docstrings are documentation **within** the code itself. These docstrings are then
+found by Sphinx and compiled into the repository reference documentation.
+
+Explicit documentation is documentation created by members by using files under
+the `docs/` folder. Explicit documentation is not connected to any code we use
+in particular, which makes it very flexible.
+
+## Docstrings
+Docstrings are a powerful method of documentation. The documentation is outlined
+in the code, allowing developers to grasp what classes and methods do as they're working
+on them. Plus, these docstrings get concatenated together to form the HTML reference
+docs. (Hint: These are what make up most of the [Software Reference page](/reference/index.rst)!)
+
+### Adding a docstring (Python)
+To add a new docstring to the reference documentation, add a docstring inside the code.
+
+Let's look at an example:
+
+```python
+def download_and_unzip(url, output_dir):
+ try:
+ html = download(url)
+ except:
+ raise IOError("Could not load file at {}".format(url))
+
+ fake_file = StringIO.StringIO(html)
+
+ zip_ = zipfile.ZipFile(fake_file, "r")
+ for file_path in zip_.namelist():
+ _, file_name = os.path.split(file_path)
+ file_like = zip_.open(file_path)
+
+ f = open(os.path.join(output_dir, file_name), "w")
+ f.write(file_like.read().decode('utf-8'))
+ f.close()
+```
+
+Can you tell what this method does? You could maybe look at some of the lines and
+guess as to what it's doing - but this isn't ideal. Without a docstring, this is
+how you (and all the other software MILers) have to understand this code! Let's
+fix that by adding a docstring.
+
+```python
+def download_and_unzip(url: str, output_dir: str) -> None:
+ """
+ Downloads a zip file at a particular URL and unzips it to a directory.
+
+ Args:
+ url (str): The URL to obtain the zip file from.
+ output_dir (str): The location of where to write the zip contents to.
+
+ Raises:
+ IOError: The file at the URL could not be found/loaded.
+ """
+ try:
+ html = download(url)
+ except:
+ raise IOError("Could not load file at {}".format(url))
+
+ fake_file = StringIO.StringIO(html)
+
+ zip_ = zipfile.ZipFile(fake_file, "r")
+ for file_path in zip_.namelist():
+ _, file_name = os.path.split(file_path)
+ file_like = zip_.open(file_path)
+
+ f = open(os.path.join(output_dir, file_name), "w")
+ f.write(file_like.read().decode('utf-8'))
+ f.close()
+```
+
+Wow! Look how much clearer that is. You know what the type of each argument is, and
+what it represents. You can see any errors that the function might raise, as well, along
+with what it returns (`None`). And, this is available in the code and on the doc's website!
+
+So, you're all good, right? Not yet! You need to make sure that the function's
+docstring will be shown on the reference page. In `reference.rst`, you need to
+add either an `.. autofunction:: ` or `.. autoclass:: ` directive. (Check out
+the document to see examples!)
+
+Then, when you build the docs, the docstring will be added to the docs. For more information
+on docstrings in Python, consult the [Python style guide](/software/python_style).
+
+### Adding a docstring (C++)
+To add new docstrings for C++ code, you should add the docstrings in the necessary
+header files.
+
+Find the appropriate function or class, and add a docstring comment before its
+declaration. You can use JavaDoc-like syntax to add annotations.
+
+For example:
+
+```cpp
+/**
+ * Waits for a connection to be established on the heartbeat listener. If no connection
+ * is established before the timeout has run out, then false is returned and the
+ * function exits.
+ *
+ * @param timeout The amount of time to wait before exiting the function and returning
+ * false.
+ *
+ * @return Whether a connection was established in time.
+ */
+bool waitForConnection(ros::Duration timeout = { -1.0 }) const; // waits forever by default
+```
+
+This docstring includes a general description of the function, along with what parameter
+it's poised to accept. Additionally, what the function returns is documented. Great!
+
+## Explicit Documentation
+
+### Creating the file
+Create the file in the `docs/` directory of the repository, and place the document
+under a folder which makes sense (ie, `mechanical/` for mechanical documentation).
+You can use either reStructuredText or Markdown for creating your documents, but if
+you are making an index or navigation-focused page, use reST.
+
+### Indexing the file
+For your newly added page to be found, it needs to be added to a table of contents. There is a root table of contents in `index.rst` and smaller table of contents within various subdirectories. Add your page to one or both of these, whichever you deem more appropriate. To do so, add the path to your page (without the extension) under the
+`.. toctree::` section of the `index.rst` file. For example, to add the "Meeting Schedule" page mentioned above, the `index.rst` will now look like
+
+```rst
+.. toctree::
+ :maxdepth: 1
+
+ my_article
+ Meeting Schedule
+```
+
+Sometimes, though, you don't want your document to be in a `toctree`. In this case,
+add it to a `:hidden:` TOC tree, like so:
+
+```rst
+.. toctree::
+ :hidden:
+
+ peek_a_boo
+```
+
+This TOC tree won't be rendered, but Sphinx will still allow you to build the docs
+because the document is in some TOC tree.
diff --git a/docs/software/extension_support.md b/docs/software/extension_support.md
new file mode 100644
index 0000000..22adbe3
--- /dev/null
+++ b/docs/software/extension_support.md
@@ -0,0 +1,31 @@
+# Extension Support
+Sometimes, you may need to work on a project which requires custom drivers or SDKs
+be installed on your computer. Below are some of these cases, and the installation scripts
+which can help to set up the extensions on your computer.
+
+## Proprietary Software
+MIL uses a few proprietary packages which cannot be distributed with the repo.
+You are able to compile the repo and run simulations without them, but
+they must be installed on the actual robots.
+
+**Install the BlueView Imaging Sonar SDK:**
+
+ $ ./scripts/install_bvtsdk # installs the BlueView Imaging Sonar SDK
+
+**Install the Pointgrey Flycapture SDK:**
+
+ $ ./scripts/install_flycap # installs the Pointgrey Flycapture SDK
+
+These scripts will prompt you for an encryption password. Ask a MIL leader for this.
+
+:::{warning}
+The BlueView Imaging Sonar SDK will only work on x64-compatible computers. ARM
+computers cannot currently install the software.
+:::
+
+## UDEV Rules
+If you plan on running certain MIL sensors from your local machine
+or are setting up the installation on a robot, you must give your user
+access to certain USB devices through UDEV.
+
+ $ ./scripts/install_udev_rules
diff --git a/docs/software/gazebo_guide.md b/docs/software/gazebo_guide.md
new file mode 100644
index 0000000..2cc048c
--- /dev/null
+++ b/docs/software/gazebo_guide.md
@@ -0,0 +1,329 @@
+
+# Gazebo Guide
+// TODO: Verify some differences with ROS2
+
+This is a guide on how to use Gazebo, including launching the sub and
+viewing it inside Gazebo, how Gazebo can be controlled and manipulated, how to
+use Gazebo to make world files, and where you can find more info on Gazebo.
+
+## Brief Introduction
+
+Gazebo is an open-source 3D dynamic simulator, that allows us to design, model,
+and test robots and their behavior in a virtual world. Similar to game engines
+like Unity, Gazebo takes in scripts and models and performs physics simulations
+on them. While it is similar, Gazebo offers physics simulations at a higher level
+of fidelity, a suite of sensors, and interfaces for both users and programs.
+
+There are many versions of Gazebo, but this guide was written for **Gazebo
+Classic 11** as this is the version of Gazebo currently being used at MIL.
+
+### Running Gazebo
+
+There are many ways run Gazebo.
+
+* Click the "Show Applications" button on Ubuntu (the apps button located in
+ the bottom left corner). Then search for the Gazebo Icon and press that icon
+ to open Gazebo.
+
+* You can press Alt + F2 (or Alt+Fn+F2) to bring up the "Run a Command" window.
+ Then type "gazebo" and press Enter to open Gazebo.
+
+* You can also open a terminal and type "gazebo" and it will open Gazebo.
+
+To launch Gazebo will all the necessary files for simulating Subjugator,
+follow these steps:
+
+1. Open a terminal window and execute the following command. This command uses
+ ROS to start all the relevant ROS nodes and to load the world file for
+ subjugator. This also starts a Gazebo Sever.
+
+ ```bash
+ ros2 launch subjugator_launch gazebo.launch.py --show-logs
+ ```
+
+ :::{note}
+ `--screen` forces all ROS node output to the screen. It is used for debugging.
+ :::
+
+1. Then in another terminal window run this command to start the Gazebo
+ graphical client, which connects to the Gazebo Sever.
+
+ ```bash
+ gazebogui
+ ```
+
+1. Then in another terminal window run this command and then press Shift-C to
+ unkill the sub to allow movement.
+
+ ```bash
+ amonitor kill
+ ```
+
+1. Execute the following command to start a specific mission, replacing
+ "StartGate2022" with the name of the desired mission:
+
+ ```bash
+ mission run StartGate2022
+ ```
+
+## How to use Gazebo
+
+### User Interface
+
+When you launch Gazebo you will be greeted by its user interface.
+
+
+
+The Gazebo interface consists of three main sections: The **Left Panel**, the
+**Scene**, and the **Right Panel**. By default the Right Panel is hidden. This
+is because we do not have anything selected. To show the right panel you can
+always Click and drag the bar on the right to open it.
+
+
+
+#### Left Panel
+
+The Left Panel has three tabs, each with different features. You can see
+these tabs at the top of the Left Panel. You can click on them to switch
+between them. The tabs are:
+
+##### World Tab
+
+The World Tab displays the models that are currently in the scene. Within this
+tab, you can view and modify various model parameters, like their pose (their
+position and rotation). Additionally, you can expand the GUI option to adjust
+the camera view angle by modifying the camera pose.
+
+##### Insert Tab
+
+The Insert Tab allows you to add new models (objects) to the Gazebo simulation.
+Here, you will find a list of file paths where your models are saved. To view
+the model list, click on the arrow located on the left side of each path to
+expand the folder. Select the desired model and click again in the scene to
+place it.
+
+##### Layers Tab
+
+The Layers tab organizes and displays different visualization groups within
+the simulation. Layers can contain one or more models, and enabling or disabling
+a layer will show or hide all the models within it. While not mandatory, layers
+can be helpful for organizing your simulation. Note that this tab may be empty
+if no layers are defined.
+
+To define a layer, you will need to edit a model's SDF file. To add an
+object's visuals to a layer you will need to add a ` ` tag for information
+and then a `` tag with the layer number under each `` tag. Below
+is an example:
+
+```xml
+
+
+ 0
+
+ ...
+
+```
+
+#### Scene
+
+The Scene is the main window where objects are animated, and you interact with
+the environment. Two toolbars are available:
+
+##### The Upper Toolbar
+
+The Upper Toolbar consists of various buttons that allow you to select, move,
+rotate, and scale objects. It also provides options to create simple shapes,
+as well as copy and paste objects.
+
+
+
+##### The Bottom Toolbar
+
+The Bottom Toolbar displays information about the simulation time and its
+relationship to real time. It helps you track the progress of your simulation.
+
+
+
+#### Right Panel
+
+The Right Panel is used to interact with the mobile parts (joints) of a
+selected model. It provides controls and settings specific to manipulating
+the joints of a model.
+
+#### Menus (File, Edit, Camera, View, Window, Help)
+
+Most Linux apps have menus. These menus are usually tabs (file, edit, ...) at
+the top left of an application. If you don't see it move your cursor to the
+top of the application window and the menus should appear. Below describes
+the features of each menu that Gazebo has.
+
+
+
+#### Mouse
+
+It is recommended that you use a mouse when using Gazebo. Below is a diagram
+showing all the mouse controls.
+
+
+
+However, if you want to use a trackpad you can. Below are the controls for
+the trackpad:
+
+
+
+## How to Create Models
+
+The structure for most models in Gazebo is that the model is a folder that
+contains a .config file, .SDF file(s), and .dae or .stl file(s). The config
+file contains meta information about the model. The .SDF file contains
+important simulation information like model definitions, the model's
+positioning, its physical properties, etc. The .dae or .stl files contain 3D
+mesh information. When creating a model it's recommended that you have all
+these components.
+
+### Model Editor
+
+You can use the **Model Editor** to create simple models all within Gazebo,
+but for more complex models you will want to create/write your own SDF files
+and .dae files.
+
+To enter the **Model Editor**, click on Edit in the menu bar and select Model Editor.
+
+The Model Editor Interface looks similar to the regular Gazebo UI with some
+slight changes. The left panel and the top toolbar have been changed to
+contain only buttons and features for editing and creating parts of a model.
+The bottom toolbar is now hidden as the simulation is paused.
+
+
+
+When entering the Model Editor all other models will turn white. This can make
+it hard to see the model you are currently working on if you have a lot of
+models in your scene. So it may be easier to open a blank Gazebo world and
+create the model using the Model Editor there. Then when you exit the Model
+Editor it will ask you to save the model. This will save the model as a folder
+on your computer. Then you can go back to the original world and insert
+this model, by going to the insert tab (note this is the regular insert tab,
+not the one in the model editor) and adding that model folder's file path.
+
+:::{note}
+When inserting a model, make sure that the file path you pick is the path to
+the parent directory. This directory contains the model folder you want to
+insert. Do not put the path to the model folder. Often this parent
+directory will contain all the models you want to use. The file hierarchy
+might look like this: where models is the parent directory and contains the
+models model1 and buoys.
+
+```
+ models/
+ ├── model_1/
+ │ ├── model.config
+ │ ├── model1.sdf
+ │ ├── model1.dae
+ │ └── ...
+ ├── buoys/
+ │ ├── model.config
+ │ ├── green.sdf
+ │ ├── red.sdf
+ │ └── ...
+```
+
+:::
+
+#### Insert Tab
+
+The Insert Tab allows you to add new parts, including links and models, to
+your model. You have two options for inserting shapes (links):
+
+* Simple Shapes: Click on the desired shape in the left panel and then click
+ again in the scene to place it.
+
+* Custom Shapes: You can add COLLADA (.dae), 3D Systems (.stl), Wavefront
+ (.obj), and W3C SVG (.svg) files as custom shapes. Create these shapes
+ using 3D modeling software like Blender.
+
+You can also insert other models into your model as nested models. These
+models can be obtained from the Gazebo Model Database
+(http://gazebosim.org/models/), which should be listed as one of your file
+paths under Model Databases. For example, if you need a depth sensor, you can
+add a depth sensor model from the database to your model.
+
+#### Model Tab
+
+The Model Tab displays the settings for the model you are creating. Here, you
+can change the model's name and modify its basic parameters. Additionally, you
+can add plugins to give your model functionality here as well.
+
+#### Placing Shapes
+
+Once you insert a shape, you can use the toolbar to move, rotate, and scale
+it. For finer control, you can double-click the shape or right-click and
+select "Open Link Inspector" to access the link inspector. In the link
+inspector, you can modify the shape's position, rotation, and scale to
+achieve the desired configuration. Make sure to adjust the scale in both the
+Visual and Collision tabs.
+
+#### Adding Joints
+
+To constrain the motion between shapes, you can add joints. Follow these steps:
+
+* Click on the joint icon in the toolbar (a line connecting two points).
+
+* In the Joint Creation Window, select the parent and child links (shapes)
+ of the joint.
+
+* Select the type of joint you need in the Joint Types section near the top
+ of the window.
+
+* Select the joint axis. Some joints do not have an axis.
+
+* Align the link (shape). Use the align links section to align the parent
+ and the child with each other.
+
+#### Adding a Plugin
+
+To control your model, you need to create a plugin. You can do this in the
+Model Tab by specifying the necessary details for the plugin.
+
+You can find more information on how to create your own custom plugins [here](https://classic.gazebosim.org/tutorials?tut=ros_gzplugins).
+
+#### Model Creation Workflow Example
+
+To illustrate the model creation process, let's consider creating a car model
+using Blender:
+
+* Create .dae files for the wheels, chassis, and other parts in Blender.
+
+* Insert these shapes into the Model Editor.
+
+* Use the toolbar and link inspector to position each shape precisely.
+
+* Add joints between the shapes to enable motion constraints.
+
+* Finally, create a plugin to control the model's behavior.
+
+### World File
+
+A World in Gazebo is used to describe the collection of robots and objects,
+and global parameters like the sky, ambient light, and physics properties.
+A World is the entire virtual environment that you have been
+working in. The World stores important information like where all the models
+are, their properties, and important global properties.
+
+You can save the World file by selecting File and Save World As.
+
+:::{note}
+When using roslaunch to start Gazebo, it is crucial to update the World file
+if you make any changes to the simulation environment. At MIL, there is a
+dedicated `worlds` folder where Gazebo World files are saved. When you update
+a World file, ensure that you replace the old file in this folder. Failing
+to do so will result in the continued use of the old World file when
+launching Gazebo using roslaunch.
+:::
+
+## More Info
+
+If you ever need more information on how any aspect of Gazebo works or how to
+use ROS with Gazebo you can check out the official Gazebo Documentation [here](https://classic.gazebosim.org/tutorials).
+Some of the images used in this guide are sourced from here and we are grateful
+to the creators for their exceptional work, which has been instrumental in
+writing this guide.
diff --git a/docs/software/getting_started.md b/docs/software/getting_started.md
new file mode 100644
index 0000000..55923ce
--- /dev/null
+++ b/docs/software/getting_started.md
@@ -0,0 +1,440 @@
+# Getting Started
+
+This page describes the recommended process of setting up a new Ubuntu system
+to work with the MIL repository and its dependencies. Ubuntu is an operating system
+(similar to OS X or Windows) that MIL (and other robotics labs) choose to use
+because of its familiarity with ROS.
+
+## System Requirements
+
+Autonomous robotics is computationally expensive, especially when running simulations.
+Your VM or computer should have at least 4GB, although it will run much faster with
+8GB of RAM or higher. You should have at least a dual-core system, but using
+more cores will allow compilation to run much faster.
+
+If you are using a virtual machine, you can change the amount of RAM and the
+number of CPU cores allotted to the virtual machine by visiting the settings
+of your VM software.
+
+## Setting Up Ubuntu
+
+### Choosing an Installation Method
+
+You will need to install **Ubuntu 20.04 LTS** (disk image downloads linked below),
+the main operating system supported by ROS and our tools. Our tools are not setup
+to work on other operating systems, including other Linux distributions, macOS,
+and Windows.
+
+To use Ubuntu in MIL, you have three options:
+
+1. **Dual-boot your computer.** Dual booting will allocate a piece of your computer's
+ storage to a new operating system, which will be installed on your computer directly.
+ This dual-booted solution will not run on top of your current operating system, but
+ will instead run by directly using your computer's resources.
+
+2. Use a **virtual machine**. A virtual machine uses your current operating system
+ to virtually host another operating system (in this case, Ubuntu). The experience is
+ typically not the best, but it does provide isolation and is **necessary for an M-series (ARM) Mac computer**
+
+3. **Windows Subsystem for Linux.**
+ WSL2 runs Ubuntu in a lightweight, highly integrated virtual machine.
+ While it doesn’t offer the full native speed of dual-booting, it delivers
+ much better performance and convenience than traditional virtual machines.
+ For most Windows users, WSL2 is a recommended option.
+
+For performance: Dual-boot > WSL > virtual machine
+For convenience: WSL > virtual machine > Dual-boot
+
+The following diagram should give you insight into which method is best for you, though it is only a recommendation.
+If you have installed Linux before or know of a technical issue with your computer, you may know that a different
+method is best for you.
+
+
+
+### Installing Ubuntu
+
+Here are the links to appropriate `.iso` (disk image) files. Note that you will
+need to choose the correct disk image based on your computer's architecture. You
+do not always need to download these files - they are only needed for some installation
+methods.
+
+| Architecture | URL |
+|-----------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| AMD64 (most Windows computers, Intel-based Mac computers) | [focal-desktop-amd64.iso](https://releases.ubuntu.com/focal/ubuntu-20.04.6-desktop-amd64.iso) |
+| ARM64 (Apple Silicon Mac computers) | 1. [ubuntu-20.04.5-live-server.arm64.iso](https://mil.ufl.edu/software/ubuntu-20.04.5-live-server-arm64.iso) 2. After setting up the server, run: `sudo apt update && sudo apt install ubuntu-desktop && sudo reboot now` |
+
+The following subsections cover various installation methods. Please choose the
+installation option that best meets your use case. If you're not sure what the
+best installation method is, please check the diagram above.
+
+After you have the operating system downloaded, you may need to configure it.
+This includes setting your preferred language and keyboard layout, along with
+your username and password. Set these settings up to your liking, but note that
+having a shorter username may save you some typing in the long run.
+
+#### Option 1: Using Windows Subsystem for Linux (WSL2)
+
+1. Open **PowerShell as Administrator** and run:
+ ```powershell
+ wsl --install
+ ```
+ This installs WSL with the default Ubuntu distribution. If you already have WSL installed but need version 2, run:
+ ```powershell
+ wsl --set-default-version 2
+ ```
+
+2. Restart your computer if prompted.
+Open **PowerShell** and list available distros:
+ ```powershell
+ wsl --list --online
+ ```
+Install Ubuntu (or another preferred distro):
+ ```powershell
+ wsl --install -d Ubuntu-22.04
+ ```
+ Replace `Ubuntu-22.04` with your preferred version from the list.
+Once installed, launch Ubuntu from the Start Menu or run:
+ ```powershell
+ wsl
+ ```
+
+1. **Update package lists** and install essential tools:
+ ```bash
+ sudo apt update && sudo apt upgrade -y
+ sudo apt install -y build-essential curl git
+ ```
+Ensure WSL2 is the default version for all new distributions:
+```powershell
+wsl --set-default-version 2
+```
+- You can access your Windows files inside WSL at:
+ ```bash
+ cd /mnt/c
+ ```
+- If running **GUI applications**:
+ - Windows 11 supports GUI apps natively via WSLg.
+ - Install GUI apps inside WSL and launch them normally.
+Run:
+```bash
+wsl --status
+```
+This should show that you are running **WSL version 2** and your chosen Ubuntu distro.
+
+#### Option 2: Dual-booting a Windows computer
+
+This includes installing Linux right alongside your host operating system, Windows, on a separate
+partition on your computer's hard drive. If you need access to a bootable USB drive
+containing Ubuntu Linux, feel free to stop by the lab.
+
+1. If your computer uses BitLocker (also known as advanced drive encryption), you
+ will need to disable this. To do this, you can usually search for "BitLocker"
+ or "drive encryption" in your Windows search bar. A control panel or Settings
+ application should open, at which point you can find the BitLocker setting
+ and disable it.
+
+2. If your computer uses Secure Boot, you will need to disable this. Secure Boot
+ is a security feature in Windows that prevents the loading of operating systems
+ other than Windows. While disabling Secure Boot will make your computer slightly
+ less secure, unless you are a secret spy, you should be okay.
+
+ To disable secure boot, you will need to enter your computer's UEFI settings.
+ To do this, trigger an advanced restart of Windows. This can be done by holding
+ shift before clicking restart. Then, click
+ **Troubleshoot > Advanced Options > UEFI Firmware Settings**. Proceed into the
+ security section of your BIOS settings, and disable Secure Boot.
+
+3. Now, let's partition your hard drive to allocate space for your new Ubuntu setup.
+ Open Disk Manager by typing in "Disk Manager" in the Windows search bar. Right-click
+ on your computer's drive, and click **Shrink Volume**. Shrink your disk by
+ **50000 MB**, or 50 GB.
+
+4. Now, insert the bootable USB drive into your computer, and once again, do an
+ advanced restart by holding Shift and clicking **Restart** in your main Windows
+ menu. In the advanced restart menu, click **Use a device**, and then choose
+ the bootable USB drive. If you don't see the USB drive, check to make sure that
+ the USB is fully inserted, and try pulling it out and plugging it back in.
+
+5. You should now see the Linux boot menu. Boot into **Install Ubuntu** or **Ubuntu**,
+ not "Try Ubuntu without installing." You can proceed with all default configuration
+ options in the Ubuntu setup page, as you've already partitioned your disk.
+
+6. Ubuntu will take some time to install. Once the installation process is complete,
+ you should be able to access the Terminal using the nine dots in the bottom left
+ corner to proceed with the rest of the installation.
+
+#### Option 2.5: Using a virtual machine on Windows (Using WSL is objectively better)
+
+#### Option 3: Using Parallels on macOS
+
+[Parallels Desktop](https://www.parallels.com/) is well-known as the best
+virtual machine manager for macOS. Installing new virtual machines is quick,
+performance is stellar, and the application comes bundled with a suite of tools
+to make sharing resources between the virtual machine and macOS painless. However,
+Parallels does cost $39.99/year for students.
+
+1. Purchase and download Parallels Desktop, linked above. If you use Homebrew,
+ you can install the Parallels with `brew install parallels --cask`.
+
+2. **Do not click "Install Ubuntu Linux" - this will install Ubuntu 22.04, not
+ Ubuntu 20.04!** Instead, download the appropriate `.iso` file linked above.
+ Macs using an M-series processor should install the ARM64 disk image, not the
+ AMD64.
+
+3. Choose "Install Windows or another OS from a DVD or image file." Select the `.iso`
+ file that you downloaded previously and start up your virtual machine.
+
+4. You can name your VM whatever you'd like (maybe something related to MIL?).
+ Click on "Configure..." and choose any options in the "Options" tab that you'd
+ like. In the "Hardware" tab, use the highest number of processors and highest
+ amount of memory recommended for your computer.
+
+5. Click "Continue" - this will launch the virtual machine and begin the installation
+ process.
+
+6. After some time, you should see the Linux boot menu. Boot into
+ **Install Ubuntu** or **Ubuntu**, not "Try Ubuntu without installing." You
+ can proceed with all default configuration options in the Ubuntu setup page,
+ as you've already partitioned your disk.
+
+7. Ubuntu will take some time to install. Once the installation process is complete,
+ you should be able to access the Terminal using the nine dots in the bottom left
+ corner to proceed with the rest of the installation.
+
+#### Option 4: Using UTM on macOS
+
+[UTM](https://mac.getutm.app/) is a popular open-source virtualization software
+for macOS. It is free, but will provide less performance and support between
+your host Mac and the VM.
+
+1. Download UTM, linked above. If you use Homebrew, you can install UTM with
+ `brew install utm --cask`.
+
+2. Download the appropriate `.iso` file for your computer, linked above. Macs using
+ an M-series processor should install the ARM64 disk image, not the AMD64.
+
+3. Click the "+" button to create a new virtual machine, and choose "Virtualize."
+ Next, choose "Linux."
+
+4. Under "Boot ISO Image", choose the disk image you downloaded earlier.
+
+5. Allocate half of your computer's memory to your VM. For example, if you have
+ a 16GB computer, then allocate 8GB to the VM. Allocate half of your computer's
+ CPU cores. For example, if you use a quad-core computer, then allocate two cores
+ to the VM. Enable hardware acceleration with OpenGL.
+
+6. Allocate 50GB of space to your VM. If you don't have too much space left on your
+ computer, you can allocate less, but do not go below 30GB. If you'd like to clean
+ up space on your computer, click the Apple logo in the top left corner of your
+ Mac, choose "About This Mac", head to "Storage", and then click "Manage."
+
+7. Click "Save." Before starting the VM, go into the control panel of the VM using
+ the options button in the top right. In "Display," enable "Retina Mode."
+
+8. Now, click the play button on your VM to turn the VM on!
+
+9. After some time, you should see the Linux boot menu. Boot into
+ **Install Ubuntu** or **Ubuntu**, not "Try Ubuntu without installing." You
+ can proceed with all default configuration options in the Ubuntu setup page,
+ as you've already partitioned your disk.
+
+10. Ubuntu will take some time to install. Once the installation process is complete,
+ you should be able to access the Terminal using the nine dots in the bottom left
+ corner to proceed with the rest of the installation.
+
+#### Option 5: Dual-boot a macOS computer
+
+While dual-booting macOS is not a common option of installation, for those with
+lots of space and recently built computers, it can still be a viable option. You
+may gain more performance from a dual-boot system versus a virtual machine.
+
+Dual-booting is only an option for members with an Intel-based Mac. M-series Macs
+are not able to dual-boot.
+
+1. To start, you'll need to partition your hard drive. Open Disk Utility and choose
+ "View > Show All Devices." Select the highest-level drive, and choose "Partition."
+
+2. Use the "+" button to create a new partition. Click "Add Partition." Name it
+ whatever you'd like (maybe something related to MIL or Ubuntu?), and set the
+ format to "MS-DOS (FAT32)." Allocate 50GB. If you don't have enough space to allocate
+ 50GB, 30GB should suffice, but don't go below 30GB. Click "Apply" to create
+ a partition.
+
+3. Insert the bootable USB drive into your computer and restart your computer. Upon
+ restart, hold the Option key until you see the boot options. Select the bootable
+ USB drive.
+
+4. After some time, you should see the Linux boot menu. Boot into
+ **Install Ubuntu** or **Ubuntu**, not "Try Ubuntu without installing." You
+ can proceed with all default configuration options in the Ubuntu setup page,
+ as you've already partitioned your disk.
+
+5. Ubuntu will take some time to install. Once the installation process is complete,
+ you should be able to access the Terminal using the nine dots in the bottom left
+ corner to proceed with the rest of the installation.
+
+#### Option 6: Use Distrobox on another Linux distribution
+
+If you're already using another Linux distribution regularly, you can use Distrobox
+to virtualize Ubuntu on this other distribution. This program is similar
+to Docker or a virtual machine software, but is more lightweight and less computationally
+heavy.
+
+1. Install Distrobox. The installation method will vary based on your host operating
+ system.
+
+2. Create a new Distrobox container using `distrobox create --name mil --image
+ ubuntu:focal --home ~/mil-home`.
+
+3. Enter the container using `distrobox enter --name mil`. You can proceed with
+ the MIL installation script from here.
+
+## Updating packages
+
+First, we will refresh the list of packages available for your computer. You
+will install packages on Ubuntu using the `apt` package manager. You may also
+see this written as `apt-get`; the two commands are very similar and usually
+achieve the same purpose.
+
+(To access the Terminal on Ubuntu, click the 9 dots in the bottom left corner
+and find the Terminal app. You can later install a different terminal emulator,
+if you'd like.)
+
+```bash
+$ sudo apt update
+$ sudo apt upgrade
+```
+
+:::{note}
+The `$` shown before the commands above indicates that those commands are meant
+to be run in your computer's shell. Do not type these dollar signs; only type
+what comes after them.
+
+You may also see `>>>` in code examples on pages you visit later. This indicates
+that those code examples are meant to be run in the Python REPL. Furthermore,
+`...` is used to represent a Python command that is meant to be indented before
+it's ran in the REPL.
+:::
+
+## Git setup
+
+To contribute changes, you will need to have [git](https://www.git-scm.com) installed.
+This program will be used to track and upload any changes that you make to the repository.
+
+```bash
+$ sudo apt install git
+```
+Additionally, if you are not signed in, running
+```
+gh auth login
+```
+and logging in through the browser will help verify your identity. You might
+also need to register your email and password again when prompted, or in:
+```bash
+$ ./scripts/store_git.sh
+```
+
+:::{note}
+In order to contribute code, you need to be in the [uf-mil GitHub organization](https://github.com/uf-mil).
+First create a GitHub account if you do not have one, then ask someone in MIL / on Slack
+to invite you.
+:::
+
+## Cloning the repository
+
+You need to clone (download) a copy of the repository onto your computer so you
+can make changes.
+
+First clone the upstream (MIL's fork) version of the repo. (catkin workspace is depreciated for ROS2 and causes issues)
+
+Then, clone the repository into your root directory (`--recurse-submodules` pulls the submodules,
+`-j8` is a downloads up to 8 submodules at a time).
+
+```bash
+$ git clone --recurse-submodules -j8 https://github.com/uf-mil/mil2.git
+```
+
+Navigate to the root of the repository now. If you have followed the
+instructions exactly, you can get there through:
+
+```bash
+$ cd ~/mil2
+```
+
+## Run the setup scripts
+
+If you are running Ubuntu, and prefer to run code directly on your "host"
+operating system without using Docker, you can run the following scripts from
+the root of the repository.
+
+If you're wondering what these scripts do, they install all the tools needed
+for you to work in MIL (``git``, ROS, Python dependencies, etc.). Feel free
+to open up the file in an editor if you're more curious.
+
+```bash
+$ ./scripts/install.sh
+$ exec bash # or exec zsh if you have set up zsh
+```
+
+Exit the terminal and enter it again.
+
+To build our tools, we use `colcon`.
+```$ colcon build --symlink-install```
+You can use an alias, to make calls quickly from wherever in the repository
+```bash
+alias cm="colcon build --symlink-install"
+```
+
+If something goes wrong, try the suggestions in [Getting Help](help). It's common
+for the build to fail if your system was unable to find enough resources to build
+the project. If you are using a VM, you may want to allocate more cores or RAM
+to the instance.
+
+## Viewing Simulation in ROS2
+// TODO: written by AI to update to ROS2
+
+Now that you've built the repository, check to make sure that the simulation works on your computer. In ROS2, we use **`ros2 launch`** instead of `roslaunch`.
+
+For this, you will need multiple terminal windows! To create a new window in the default terminal, use **`Ctrl + Shift + T`**.
+
+### **Step 1: Source Your ROS2 Environment**
+Before running any launch files, ensure your environment is set up:
+```bash
+source install/setup.bash
+```
+
+### **Step 2: Start the Simulation**
+In **window one**, launch Gazebo and the required subsystems:
+```bash
+ros2 launch subjugator_launch gazebo.launch.py
+```
+_(Ensure your launch file is a `.py` file, as ROS2 uses Python-based launch files instead of XML.)_
+
+### **Step 3: Open the Gazebo GUI**
+In **window two**, start the Gazebo client:
+```bash
+gazebo --verbose
+```
+_(Unlike ROS1, Gazebo GUI is started directly without a separate `gazebogui` command.)_
+
+If everything is working, you should see our robot in its own little world!
+
+---
+### **Additional Notes for ROS2**
+- **Use `ros2 topic list`** to verify active topics.
+- **Use `ros2 node list`** to confirm running nodes.
+- If any errors occur, check logs with:
+ ```bash
+ ros2 launch subjugator_launch gazebo.launch.py --show-logs
+ ```
+
+
+## Installing developer tools
+After you have verified that your Git setup is working appropriately, take a look
+at installing some developer tools on the [Developer Tools](/software/devtools) page.
+You are **highly recommended** to install `pre-commit`.
+
+## What's next?
+If the `cm` didn't fail on your computer, you're all good to go!
+Congratulations, and welcome to MIL!
+
+The next step is to get assigned a task and to dive in. You should have the setup to do so now!
\ No newline at end of file
diff --git a/docs/software/help.md b/docs/software/help.md
new file mode 100644
index 0000000..4e3f8c3
--- /dev/null
+++ b/docs/software/help.md
@@ -0,0 +1,90 @@
+# Getting Help
+Programming is difficult, and programming at the level needed for autonomous systems
+is even harder. Every developer write bugs, encounters confusing errors, and gets stuck
+in countless other ways. With time, you'll learn not how to write better code,
+but also how to effectively get help when you're stuck.
+
+You should always try to solve problems yourself using the internet, documentation,
+etc. before asking others. This not only shows respect for your peers' time (who likely
+also have their own problems) but will lead you to learn more. In other words,
+teach yourself to fish rather than asking for fish.
+
+## Check your sanity
+A great first move is to take a step back and think about what you're trying
+to do and if it makes sense.
+
+Ask yourself the following questions:
+
+* Are you running the latest code? Have you pulled from git lately (including
+submodules) and updated your system packages?
+ * Be sure to back up / commit any changes to a branch
+ * To reset to the latest code from GitHub run `git fetch origin` and then
+ `git checkout origin/master -B master`
+ * Be sure to initialize and update all submodules as well with `git submodule update --init --recursive`.
+* If the error says exactly how to fix it, have you tried that?
+* Is your system setup correctly as described in the [Getting Started Guide](/software/getting_started)?
+* Have you blindly copy-pasted/ran things from the internet? If so, do you know
+why? Do you know what it's doing?
+* Could you be trying to use something that is outdated / deprecated?
+* Have you tried rebooting your system or running it again?
+
+## Search these docs
+You may have noticed that these docs have a search bar. If you want
+to learn about a topic, try putting in some keywords related to your topic
+or finding a docs page in the table of contents. The search bar will also help
+you find related code to the problem you may be encountering, as it can search
+through the entire software reference.
+
+You may find the [Culture](/culture) page especially useful.
+
+## View the docs on related classes/methods
+Although you may be developing a new system/class/method (or not!), finding the
+documentation on classes/methods related to what you're building can be very helpful.
+
+For example, let's say you're working with the Passive Sonar system. Try finding some
+of the MIL-specific classes/methods you're working with (such as {class}`mil_passive_sonar.TxHydrophonesClient`)
+and then viewing the docs on those classes/methods in our reference docs.
+
+## Search the code with `grep`
+Perhaps the most useful command for a programmer is `grep`. Grep can search
+quickly through files for a particular pattern or string. `git grep` is an
+even faster way to search everything in a git repository (such as the MIL repo).
+
+For example, if you see an error `DVL: error on write`, you can run:
+
+ ~/catkin_ws/src/mil$ git grep "DVL: error on write"
+ SubjuGator/drivers/sub8_rdi_dvl/include/rdi_explorer_dvl/driver.hpp: \
+ ROS_ERROR_THROTTLE(0.5, "DVL: error on write: %s; dropping heartbeat", exc.what());
+
+And see the exact source file where this error comes from.
+
+Likewise, if you want to learn how to use a function, you can search the code
+for examples of it being used.
+
+## Search the internet
+If your problem is not MIL-specific (issue with Linux, ROS, C++, etc.),
+someone has most likely had the same problem and written about it on the internet.
+You'll be surprised how often you can fix your issue by Googling the error.
+
+## Search Slack
+Someone may have already asked a similar question on Slack. Try searching there.
+
+## Ask for Help
+If you made decent efforts to follow the above steps to figure things out on
+your own, now it is time to ask for help!
+
+In order for people to be able to understand your issue, please include:
+
+* Precisely what circumstances brought about the error (command, version of software, etc.)
+* What you are trying to do / achieve
+* What steps you have already taken to debug
+* The exact code in question (push it to a GitHub branch if it is your changes)
+
+### File an issue
+If you believe you have discovered an issue with something that should be working,
+it may be appropriate to file an issue [on GitHub](https://github.com/uf-mil/mil/issues).
+
+### Ask on slack / in-person
+If your issue regards code that you are developing or might be specific
+to your use case, come by office hours or ask around in the #software channel
+on slack.
diff --git a/docs/software/index.rst b/docs/software/index.rst
new file mode 100644
index 0000000..b72a99c
--- /dev/null
+++ b/docs/software/index.rst
@@ -0,0 +1,90 @@
+Software
+=====================
+Various documentation related to practices followed by the MIL Software team.
+
+Getting Started
+---------------
+Welcome to the software team, take a look at the following to get started!
+
+.. toctree::
+ :maxdepth: 1
+
+ Getting Started
+ ROS 2 Migration
+ devtools
+ Contributing Changes
+ help
+
+
+Technical Tools
+---------------
+Learn about some of the libraries and programs we use in MIL!
+
+.. toctree::
+ :maxdepth: 1
+
+ asyncio
+ rqt
+ rostest
+ gazebo_guide
+ Developing with Submodules
+
+
+Best Practices
+--------------
+Read below for the best practices for our team!
+
+.. toctree::
+ :maxdepth: 1
+
+ Bash Style Guide
+ C++ Style Guide
+ Python Style Guide
+
+
+MIL Tools
+---------
+Read about some of the tools used in MIL!
+
+.. toctree::
+ :maxdepth: 1
+
+ documentation_syntax
+ adding_documentation
+ alarms
+ preflight
+
+
+Hardware
+--------
+Check out some information about hardware used in MIL!
+
+.. toctree::
+ :maxdepth: 1
+
+ calibrating_cams
+ Installing NVIDIA Drivers for RTX 2080
+ zobelisk
+
+
+Miscellaneous
+-------------
+We couldn't find a good spot for this stuff lol
+
+.. toctree::
+ :maxdepth: 1
+
+ Resetting Ubuntu Administrative Password
+ Network with Vehicles and Simulation Servers <../infrastructure/network.md>
+ Optional Extensions
+ Helpful Scripts
+
+Archived
+--------
+Below are documentation pages that are no longer used.
+
+.. toctree::
+ :maxdepth: 1
+
+ Installing Ubuntu 18.04 on an M-series Apple computer
+ Migrating to ROS Noetic
diff --git a/docs/software/installation.png b/docs/software/installation.png
new file mode 100644
index 0000000..d984300
Binary files /dev/null and b/docs/software/installation.png differ
diff --git a/docs/software/noetic_migration.md b/docs/software/noetic_migration.md
new file mode 100644
index 0000000..14dc3e7
--- /dev/null
+++ b/docs/software/noetic_migration.md
@@ -0,0 +1,218 @@
+# Noetic Migration
+
+Welcome! Thanks for helping with the migration to ROS Noetic. This guide will attempt to walk you through some of the tools we will use and some of the steps we will take to achieve ROS Noetic compatibility.
+
+## Overview
+
+**So, what even is the problem here? What is "ROS Melodic" and "ROS Noetic", and why do we need to migrate between them?**
+
+First, ROS is the Robot Operating System, which controls how our robots perform. Released in 2018, ROS Melodic is the version our code currently operates on. ROS Noetic was released in 2020 and is the next major version of ROS after ROS Melodic.
+
+Like most software, ROS Noetic fixes a lot of bugs and adds helpful features that can be used when programming our robots. Therefore, many systems are migrating over to ROS Noetic, including the VRX competition, one of the main competitions we compete in. To ensure compatibility with ROS Noetic in the future, we want to start migrating earlier rather than later so that we aren't left behind and can use the latest-and-greatest features on our robots!
+
+So the migration between ROS Melodic is easy-peasy, right? A few setup scripts here, a touch of code editing there? Well, not exactly. There are a few major components of our systems that must be updated to work with ROS Noetic. This includes:
+
+* Updating all **Python 2** to be compatible with **Python 3**
+* Updating ROS packages to use a different version of CMake
+* Verifying dependency compatibility with ROS Noetic
+* Updating some dependencies, such as OpenCV and PCL
+* *[Other various changes...](http://wiki.ros.org/noetic/Migration)*
+
+We will work through these changes piece by piece to make sure our systems are up to date.
+
+Let's start with the first major step...
+
+## Migrating Python 2 to Python 3
+
+Python is one of the most common languages found in our codebase. However, the code was written in Python 2, and it now needs to be converted to Python 3, which has a very different syntax style.
+
+Before you start, take a **quick look** over [this porting guide](https://portingguide.readthedocs.io/en/latest/index.html). Start at the `Syntax Changes` section and skim through the end. You don't need to memorize this information, but skimming through the pages will give you a good idea for what changes need to be made.
+
+Then, you can choose a package to convert to Python 3. To do so, go to the GitHub repository and choose and issue with the `2to3` label. Once you've chosen a package to migrate, you can go through a series of steps with each package:
+
+### Step One: Running scripts against the existing code
+
+First, run some helper scripts against the code that already exists in the package. There are some great tools that can help you with this:
+
+* `python-modernize`: A command-line utility that is able to show what code needs to be migrated to Python 3. The utility will show what lines could cause issues if run with Python 3. Remember that a lot of Python is compatible with both versions 2 and 3, only some of it is not. Also note that not everything it flags is an issue, but more on this later.
+* `black`: Another command-line utility useful for making Python look pretty and sweet! It formats the code in such a way that the meaning is preserved but the code is easier to read!
+
+A good practice is to run `black` (and `python-modernize` if you find that it helps
+you) before you begin the process of migration. Then, re-run the command(s) again
+before you commit.
+
+### Step Two: Migrating the code
+
+Great, the code is now pretty! :D
+
+If you ran `python-modernize`, it will have suggested some changes to you, indicated
+by `+` and `-` signs. It may look something like this:
+
+```diff
+RefactoringTool: Refactored old.py
+--- old.py (original)
++++ old.py (refactored)
+@@ -1 +1,2 @@
+-print 'this is an example'
++from __future__ import print_function
++print('this is an example')
+RefactoringTool: Files that need to be modified:
+```
+
+This is showing that it's suggesting the removal of the `print 'this is an example'` line,
+the addition of `from __future__ import print_function`, and the addition of
+`print('this is an example')`.
+
+Let's break this down:
+1. `python-modernize` frequently likes to suggest adding `from __future__ import X`.
+The good news is that most of the time, this isn't needed at all. The only exception
+is `from __future__ import annotations`, which you may need to add if it suggests adding it.
+2. It's suggesting the replacement of `print '...'` with `print('...')`, which is
+an awesome idea! You may have noticed this is a required change in the Python 2 to 3
+Porting Guide above.
+
+Great! So now we know what to fix in our file. Here's some more tips about `python-modernize`:
+1. It always starts with a long list of "fixers" telling you what it looked for
+in the file. This is okay; you need to ignore the list.
+2. Some changes ask you to use `import six.XXX`. Never do this! This is covered more below.
+3. After migrating `print '...'` to `print('...')`, you may notice that `python-modernize`
+wants you to now write `print(('...'))`! Don't do this - only one set of parentheses
+is needed.
+4. Usually, a method beginning with `iter` can have the `iter` prefix removed. For example,
+`for k, v in dict.iteritems()` can be migrated to `for k, v in dict.items()`.
+
+Additionally, change the [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) of the file if that was not a suggested fix by `python-modernize`. You likely only need to replace the `python` with `python3`!
+
+#### Handling `import six.XXX` suggestions
+`six` is a Python 2 to 3 library used to help in the transition between the two
+languages by providing some helper functions and methods that work in both languages.
+
+When the program asks you to import something from `six`, it's asking you to prop
+up our code on these crutches. But, we are MIL, and we don't need any crutches!
+Instead of using `six`, try fixing the root problem. For example:
+
+```diff
+RefactoringTool: Refactored old.py
+--- old.py (original)
++++ old.py (refactored)
+@@ -1 +1,2 @@
+-test = range(2)
++from six.moves import range
++test = list(range(2))
+RefactoringTool: Files that need to be modified:
+RefactoringTool: old.py
+```
+
+It's asking us to import `range` from `six.moves`. It's telling us that our `range`
+function is messed up, and that we need to do something about it. You'll also notice
+that it wants us to wrap the `range` in a `list`.
+
+The porting guide linked above can come in real handy here. It explains that in Python 2,
+`range` always produced a `list`, while in Python 3, it produces a `range` object.
+Because we want the same functionality as we had in Python 2, we'll need to manually
+convert the `range` object to a `list`. Once that's done:
+
+```diff
+RefactoringTool: Refactored old.py
+--- old.py (original)
++++ old.py (refactored)
+@@ -1 +1,2 @@
++from six.moves import range
+ test = list(range(2))
+RefactoringTool: Files that need to be modified:
+RefactoringTool: old.py
+```
+
+Now the suggestion of wrapping `range` in a `list` is gone, but it's still
+asking us to `import range`. We can ignore this, because we know that we fixed
+the root problem. Great job!
+
+### Step Three: Documenting the code (optional!)
+
+An optional step in the migration process is documenting the code as you convert it.
+Documenting the code helps future members understand the code they are reading.
+
+Documentation comes in many forms! One form is by typing the code, a feature of
+Python that Python 3 supports. To type the code, add the types that the method
+accepts as parameters and what types it returns.
+
+Another form is by adding docstrings throughout the code, which help to explain
+what methods do and how they work. These docstrings can be added through a
+multi-line comment under the method signature. The docstring should include the
+type and an explanation for each argument and what the method returns.
+
+For example, the following code block can be annotated with types and docstrings:
+
+```python
+# From https://stackoverflow.com/a/11832677
+def postal_valid(s):
+ no_spaces = s.replace(" ","")
+ if len(no_spaces ) > 6: return false
+ for i in range(6):
+ if i%2:
+ if not no_spaces[i].isdigit():return False
+ else:
+ if not no_spaces[i].isalpha():return False
+
+ return no_spaces.upper() #True
+```
+to
+```python
+# From https://stackoverflow.com/a/11832677
+def postal_valid(s: str) -> bool:
+ """
+ Returns whether a postal code is valid.
+
+ Args:
+ s (str): The postal code, represented as a string.
+
+ Returns:
+ bool: Whether the code is valid.
+ """
+ no_spaces = s.replace(" ","")
+ if len(no_spaces ) > 6: return false
+ for i in range(6):
+ if i%2:
+ if not no_spaces[i].isdigit():return False
+ else:
+ if not no_spaces[i].isalpha():return False
+
+ return no_spaces.upper() #True
+```
+
+Now that you've added new documentation, let's see it built:
+```sh
+$ mil
+$ ./scripts/build_docs
+```
+
+That last command should build the documentation on your computer and provide you
+with a link - clicking that link should open up an HTML page where you can see
+your beautiful new documentation! How exciting!
+
+When a new member sees the method in the first code block, how are they supposed
+to know what it does? This is what the docstring and typing annotations help with!
+Now, another member can instantly see the types of parameters the method accepts,
+what it returns, and what it is supposed to do.
+
+Again, this is totally optional. But, if you complete this step, you will have
+the opportunity to learn much more about the codebase and how each module works!
+
+### Step Four: Check and verify
+
+Great! By now, the code should be ready to be run in Python 3. For a last step check,
+run `python-modernize` again and verify that any warnings that appear do not need
+to be fixed. Finally, run `black` again.
+
+## Updating CMake minimum version
+
+The CMake minimum version in each package needs to be updated to version `3.0.3`.
+This has already been completed for all packages and should not need to be completed again.
+
+## Testing the changes
+
+After making some changes to a package, you may have the desire to test the changes that you've made. But wait! You can't.
+
+Many of the packages in our codebase rely on each other like an interlocking Jenga tower. If one block is removed, the tower will frequently fall. Therefore, if you attempt to simulate your changes after making some changes, the simulation may fail.
+
+Therefore, make the best changes that you can; changes that you feel confident in. Once all packages have been updated for ROS Noetic, then we can test to see how our all the packages perform. If things are still broken at this point, then we can make further commits to fix what's broken.
diff --git a/docs/software/preflight.md b/docs/software/preflight.md
new file mode 100644
index 0000000..a2a088f
--- /dev/null
+++ b/docs/software/preflight.md
@@ -0,0 +1,2 @@
+```{include} ../../mil_common/utils/mil_tools/scripts/mil-preflight/preflight.md
+```
diff --git a/docs/software/python_style.md b/docs/software/python_style.md
new file mode 100644
index 0000000..0e69f78
--- /dev/null
+++ b/docs/software/python_style.md
@@ -0,0 +1,474 @@
+# Python Style Guide
+Welcome to the Python style guide for MIL. This guide is meant to be a relaxed, easy-to-follow guide with some tips on how to make your Python look snazzy! It's based on the [ROS style guide](http://wiki.ros.org/PyStyleGuide) and the [Google Python style guide](https://google.github.io/styleguide/pyguide.html).
+
+Don't feel pressured to know or understand every rule, and totally feel free to skim over the guide at first. This guide can provide some helpful information before you begin to write your Python, but it also serves as an excellent place to determine how to use a particular Python feature in your code.
+
+Additionally, this guide is not meant to be permanent! If you have a suggestion, feel free to bring it up and change the guide! Have fun!
+
+## The Power to Change Things
+
+Before we dive into the Python, a brief word about our code and your ability to change things.
+
+These guidelines are not a hard rule. These guidelines are not permanent, nor should they be. These guidelines were not created by anyone smarter than you.
+
+Therefore, you always have the power to change them. Likewise, if you see code that breaks these guidelines, feel free to change it. If you have suggestions for the guidelines, you should suggest them.
+
+Your innovation and willingness to break and bend the rules that currently exists is what can keep our code powerful, clean, and beautiful.
+
+## Features
+This section explains how to use several of Python's features to your advantage.
+
+### Naming
+**Naming** describes how variables, methods, classes, etc. are named.
+
+#### General
+Here is a brief table explaining the general pattern of naming:
+
+
+
+
+ Type
+ Public
+ Internal
+
+
+
+ Packages
+ lower_with_under
+
+
+
+
+ Modules
+ lower_with_under
+ _lower_with_under
+
+
+
+ Classes
+ CapWords
+ _CapWords
+
+
+
+ Exceptions
+ CapWords
+
+
+
+
+ Functions
+ lower_with_under()
+ _lower_with_under()
+
+
+
+ Global/Class Constants
+ CAPS_WITH_UNDER
+ _CAPS_WITH_UNDER
+
+
+
+ Global/Class Variables
+ lower_with_under
+ _lower_with_under
+
+
+
+ Instance Variables
+ lower_with_under
+ _lower_with_under
(protected)
+
+
+
+ Method Names
+ lower_with_under()
+ _lower_with_under()
(protected)
+
+
+
+ Function/Method Parameters
+ lower_with_under
+
+
+
+
+ Local Variables
+ lower_with_under
+
+
+
+
+
+#### Names to Avoid
+There are some names we want to avoid! These may be names that are claimed by Python, names that aren't helpful to other readers of your code, or names that are confusing.
+
+Do not use:
+
+* Single character names, except:
+ * In iterators (ex, `for i in range(100):`)
+ * `e` as an exception handler
+ * `f` as a file object
+* `__double_underscore_names__`, because these are reserved by Python!
+* Names that needlessly include a type
+* Names that are offensive
+* Names that are meaningless (such as `cool_constant` or `fun_variable`)
+
+#### Mathematical Names
+Sometimes, we will use our code to implement common mathematics or algorithms. In this case, we may want to use short variable names. Here are some things to consider that:
+
+* Short mathematical names should be generally understood. For example, using `pi` to represent Pi and `v` to represent velocity is generally understood and acceptable. However, using `vd` to represent *velocity x distance* would not be acceptable, as this is not a clear, accepted term.
+* If possible and it makes sense, try using a more descriptive name.
+* Add a short line comment after the first use of the variable if it could help future readers. You may also desire to include units here as well.
+
+#### File Naming
+Files should end with `.py` and should not use dashes (`-`), but rather underscores (`_`). If you do not want the `.py` ending on the Python file and would prefer the file to take the role of an executable, consider making a symbolic link or a shell script wrapper that runs the Python file. (This can be as short as `exec "$0.py" "$@"`!)
+
+### Imports
+Imports are a powerful feature of Python. Here is a quick guide for using imports in Python:
+
+```python
+# Entire modules use
+# import x
+import datetime
+
+# Specific modules from parent modules use
+# from x import y
+from dateutil import parser
+
+# Long module names should also use "as" keyword
+from example.package import super_long_subpackage_name as super_long
+
+# Common packages can also use "as"
+import numpy as np
+
+# For relative imports use .
+# For example:
+# Assume this file is in /folder/subfolder where mod2 also lives
+# Bad:
+import mod2
+
+# Good
+from folder.subfolder import mod2
+```
+
+### Exceptions and `assert`
+
+Exceptions are a handy feature of Python that helps mitigate code that is breaking. `assert` is a helpful keyword in Python that allows one to test whether an internal statement is true, and is often used to test for internal correctness!
+
+When attempting to catch exceptions:
+
+* Do not catch `Exception`. Attempting to catch `Exception` will catch every exception thrown, which could indirectly catch exceptions that the program was not meant to catch. Instead, catch for a specific exception that will be raised. There is one case in which catching `Exception` is acceptable, however:
+ * Attempting to catch all exceptions in attempt to mitigate exceptions blocking some code from running. For example, in order to handle exceptions quietly rather than ending a thread which runs a specific process.
+* Keep `try` blocks to a minimum. As `try` blocks grow in size, the probability of *some exception* being raised increases, which may hide the true reasons behind some exceptions. Instead, attempt to keep logic outside of `try` blocks and instead only use `try` to catch code that could directly throw the exception you are trying to catch.
+* Feel free to generate your own exception classes which inherit from built-in exception types. However, in many cases, it makes more sense to only use standard exceptions. For example, there is no need to create a new exception class for catching improper types passed into a method - instead, use `TypeError`.
+
+When using `assert`:
+
+* Keep its use internal. For example, don't use `assert` to validate human input into a method. Instead, use it to verify to check types or the output of a helper method.
+
+### Iterators
+
+Iterators provide a powerful way to loop through your code!
+
+* When using list comprehensions, each part of the comprehension (`A for B in C`) should fit on one line. If the list comprehension has more than one `for`, then use a traditional iterator.
+* Attempt to use default iterators when possible:
+```python
+# Yay!
+for key in dict:
+ ...
+
+for k, v in dict.items():
+ ...
+
+# Noooo :(
+for key in dict.keys():
+ ...
+
+for k, v in dict.iteritems():
+ ...
+```
+
+### Yielding
+
+Sometimes, it may be desired to have your method **yield** values rather than **return** them. Yielding in Python is a powerful feature which delays your method's execution until you need it.
+
+To have a method yield rather than return, use the `yield` keyword in the method and mark the method docstring with `Yields:`.
+
+### Lambda Functions
+
+Lambda functions are mini-functions. They are expressed like so: `lambda x, y: x + y`.
+
+If you use lambda functions:
+* Keep them to one line. If they are longer than 80 characters, use a nested function.
+* Use them sparingly. Using complex, important operations in a lambda functions makes the code harder to debug and harder for other members to understand.
+
+### Conditional Expressions
+
+Conditional expressions are short expressions which use the `if` and `else` keywords. Conditional expressions are powerful tools which can be understood by new editors of the code.
+
+Remember to keep the result, `if`, and `else` sections of the expression to only one line. For example:
+```python
+# Good
+a = (b if c else d)
+really_long = (evaluating_function(parameter)
+ if really_long_variable_name
+ else other_really_long_var_name
+ )
+
+# Bad
+super_long = (evaluating_function(parameter)
+ if (really_long_variable_name_one
+ and this_iz_cool_func(cats))
+ else 0
+ )
+```
+
+### Properties
+
+Properties are a powerful feature of Python which allow traditional class methods to be hidden as attributes. Sneaky! This adds the benefit of masking getters and setters as traditional properties, but can accidentally mask complexion in the code that should not be hidden.
+
+Properties should:
+* Not be used for very short operations (such as returning a value)
+* Not be used when the method invokes a lot of operations. The calling user may not understand this and accidentally invoke a lot of operations that block other processes.
+* Always be marked with the `@property` decorator.
+
+### Implicit True/False
+
+Python can evaluate a wide variety of statements to `True` and `False`. For example:
+```python
+a = []
+if not a:
+ # If a has no elements
+ do_something()
+
+b = ""
+if b:
+ # If len(b) > 1
+ do_something()
+```
+
+In those statements, `True` and `False` were never explicitly used. However, they were implicitly used.
+
+Attempt to use these statements when possible, as they help to make our code look more crafted and cute. However, keep some things in mind:
+* When using this type of statement to check the size of a Numpy array, use `if (not) array.size` instead of `if array`.
+
+### Decorators
+
+**D**ecorator = **D**dangerous! Sorta. Decorators are powerful for changing the behavior of methods, which can be helpful when operations in the method itself do not suffice.
+
+However, decorators are confusing for new readers of the code, new users to Python, hard to recover from in the case of a raised error, and hard to debug. In the case that a decorator breaks a wrapped function, a MIL member may assume that the function which was operated on by the decorator was at fault, when this may not always be the case.
+
+Therefore, when using decorators, keep in mind:
+* Please test decorators extensively.
+* Every decorator should be extensively documented.
+* Please use decorators judiciously.
+
+### Line Length
+
+Please keep lines to 80 characters or fewer. This can be seen in vim by using the option `colorcolumn=80`. If you have long strings, then use parentheses to implicitly connect multiple strings together:
+```python
+dr_seuss = ("Say! I like green eggs and ham!"
+ "I like them! I do, Sam-I-Am!")
+```
+
+There are some exceptions:
+* URLs in comments. Don't split these up.
+
+### Blank Line Separators
+Please do not use backslashes to shorten lines. There is generally no need for them,
+and they are confusing and hard to format.
+
+Use blank lines to separate different parts of your module. Use two lines to separate top-level elements of any file (whether they are classes or methods) and one line to separate other distinct elements of the file.
+
+### Whitespace
+
+Whitespace (not to be confused with greenspace, redspace, or rainbowspace!) can be incorrectly used in files to give the appearance of weird formatting.
+
+When using whitespace:
+* Do not use whitespace in front of a comma or colon.
+* Always surround comparison operators (`==`, `!=`, `<`) with a whitespace character.
+* Do not put a whitespace character before an index slice (such as `x [1]`) or function call (such as `fun (20)`).
+* Do not include whitespace inside brackets including parentheses, brackets, or braces. For example, use `(x + 1)`, not `( x + 1 )` or `{'schwartz': True}`, not `{ 'schwartz': True }`.
+* In function calls, do not use whitespace when passing a default parameter, unless a type annotation is present. For example, do not use `test(a, b: float=0.0)`, instead use `test(a, b: float = 0.0)`.
+
+### String Formatting
+
+Many times you will want to format strings in a certain way: to add variables into the string, to make the string look pretty, or to use the string in a certain context, such as an enumerated iterator (`for i, v in enumerate(list): print(i + v)`).
+
+In general: use f-strings! f-strings are a unique type of string and can be made by prepending the first single/double quote of a string with `f`. This string allows you to add in expressions into the string by using a pair of curly braces:
+```python
+ultimate_answer = 42
+print(f"The ultimate answer is {ultimate_answer}.")
+
+print(f"The ultimate answer is not {ultimate_answer // 2}!")
+```
+
+When formatting a string that will be printed for logging/debugging, attempt to use a common starting term such that the string can be found with a search tool, such as `grep` or the terminal's search functionality. Additionally, make clear what sections of the logged method are interpolated or calculated.
+```python
+# Please no!
+import random
+rand = random.random()
+print(f"The {rand} number is less than 1.")
+
+# Now, you can search for "This number is less than one" and find all matching instances!
+print(f"This number is less than one: {rand}")
+```
+
+### TODO Comments
+
+TODO comments are a great way to mark a piece of code as not currently finished. To use TODO comments, create a comment that starts with `TODO`, has your name, and what still needs to be done.
+```python
+# TODO (Dr. Schwartz) - Finish method to add c in final sum
+def sum(a: int, b: int, c: int):
+ return a + b
+```
+
+### Getters and Setters
+
+Getters and setters serve as dedicated methods for getting and setting a property of a class. These are similar to `@property` methods, but these are explicit methods which are not hidden as properties.
+
+Getters and setters should only be used when changing a single property causes significant overhead or recalculation of other properties. Otherwise, set the property as public or use a small `@property` method.
+
+Getters and setters should be named in a way that demonstrates which property is being set. For example, `get_weather()` and `set_weather()`.
+
+### Function Length
+
+A function should roughly be **30 lines**. This is not a hard rule, but is a general rule to keep in mind when writing and reading functions. If you see a function longer than this, feel free to break it up if it makes sense.
+
+## Typing
+**Please, whenever possible, add type annotations to your code.** Typing is a powerful feature of Python that helps others read and understand your code.
+
+Type annotations take on the following format:
+```python
+def sum(a: int, b: int) -> int:
+ return a + b
+```
+
+The `int` keyword after the `a` and `b` parameters of the method signals that the method accepts two integers. The `-> int` at the end of the function signature signals that the method then returns an `int`.
+
+Other common built-in type annotations you might see include `float`, `dict`, `bool`, or `None`. Sometimes, though type annotations can be a little more complex. How do you write the type of parameter that is optional? Or how you do you write the type annotation of a method that can return a `List` or a `dict`? Or how about a method that returns another method?? (Method inception!)
+
+This is where the built-in `typing` module comes in. This handy module contains all sorts of classes to represent types throughout your code. Let's have a look.
+
+```python
+from typing import List, Union, Optional, Callable
+
+def crazy_func(a: int, b: Union[List[float], dict], c: Optional[dict] = None) -> Callable:
+ # Do some crazy stuff
+ return d
+```
+
+What the heck is that method even saying?
+1. First, `a` accepts type `int`.
+2. Second, `b` accepts either (this is what the `Union` class represents) a list of `float`s or a `dict`.
+3. `c` *can* accept a `dict`, but it doesn't have to - supplying this parameter is `Optional`.
+4. The function returns another method, known to `typing` as a `Callable`.
+
+Note that if your type annotations are overly long, it may be a good idea to split up your method into a series of shorter methods.
+
+## Docstrings
+
+Docstrings stand for doctor strings, strings that can only be created by medical professionals. Kidding! Docstrings stand for strings that document particular aspects of one's code. Docstrings can be used to document modules, methods, and classes!
+
+### General Docstrings
+
+For all docstrings, use narrative text. It doesn't have to be your best literary work, but please make descriptions in your docstrings readable.
+
+### Modules
+
+Each module should have a docstring placed in its `__init__.py` file, at the top of the file. This docstring should explain what the module does. First, a one-line sentence should be added to explain briefly what the module does. Then, below this sentence, evaluate more on what the module does. Then, below the longer description, add one or two brief examples of the module's use case.
+
+```python
+# calculator/__init__.py
+"""
+Provides several calculation methods to add, subtract, multiply, and divide
+integers.
+
+Each calculation method is structured into a separate method. Some methods can
+also accept any amount of arguments, while others only accept two arguments.
+Some methods also support different methods of calculation or provide
+optimizations to speed up performance.
+
+Example 1:
+
+ calc = Calculator()
+ calc.add(4, 3) # 7
+
+ calc.subtract_many(4, 3, 5) # 4 - 3 - 5 = -4
+"""
+```
+
+### Classes
+
+Every class should also have a docstring. Begin the docstring by briefly elaborating on the purpose of the class before explaining more below, in a similar fashion to the module docstring. Then, add any public attributes provided by the class that are useful to the caller.
+
+```python
+# calculator/history.py
+class CalculatorHistory:
+ """
+ Stores the history of completed operations on the calculator.
+
+ Beyond storing the operations completed, the class also provides methods
+ for completing statistics on the operations completed. Individual entries
+ can be viewed or deleted from the history.
+
+ Attributes:
+ history_length (int): The number of entries in the current history.
+ oldest_entry (datetime.datetime): The time that the oldest entry in the
+ history was executed.
+ """
+ def __init__(self):
+ ...
+```
+
+### Methods
+
+Like modules and classes, methods should also have docstrings! Begin method docstrings with a brief explanation, followed by a longer, more detailed explanation if needed. Then, add the following three sections of the docstring:
+
+1. `Args:` - The arguments accepted by the function. List each argument name, its type annotation, and what it is in English. If multiple positional arguments (such as `*args`) or multiple keyword arguments (such as `**kwargs`) are accepted by the method, write these in the docstring as well.
+2. `Returns:` - The type annotation of the method's returned value, as well as an explanation of what is returned in English.
+3. `Raises:` - Any exceptions that are raised by the method. List the type of exception raised and what condition will cause the exception to be raised (in English).
+
+```python
+# calculator/history.py
+class CalculatorHistory:
+ ...
+
+ def retrieve_entries(self,
+ history_file: str,
+ *entries_indexes: int,
+ /,
+ return_only_since: Optional[datetime.datetime] = None
+ ) -> List[HistoryEntry]:
+ """
+ Retrieves a series of entries in the calculator history.
+
+ Used to obtain a set of individual entries. For a general range of
+ entries, use retrieve_range() instead.
+
+ Args:
+ history_file (str): The name of the history file to retrieve the
+ entries from.
+ *entries_indexes (int): A list of indexes to retrieve entries at.
+ return_only_since (Optional[datetime.datetime]): If specified,
+ then only return entries from a particular point. Keyword-only parameter.
+
+ Returns:
+ List[HistoryEntry]: A list of the history entries that match
+ the specified indices.
+
+ Raises:
+ IndexError: The desired index does not exist in the history
+ record.
+ """
+```
+
+## Linting & CI
+We are currently in the process of setting up linting and CI for our Python systems.
+
+## Other Tools
+Other tools that can make working with Python easier in our codebase include
+code completion and checking systems. You can install these in popular editors
+such as VSCode or Vim.
diff --git a/docs/software/resetubuntupass.md b/docs/software/resetubuntupass.md
new file mode 100644
index 0000000..f436fc9
--- /dev/null
+++ b/docs/software/resetubuntupass.md
@@ -0,0 +1,32 @@
+Ubuntu Password Reset Guide
+===========================
+Follow the steps for resetting your Ubuntu Password:
+
+1. Boot up your device / VM.
+
+2. Go into the boot menu by either holding down ```SHIFT``` or pressing ```ESC``` depending on your device; This will get you into the ****GRUB menu****.
+
+ 
+
+3. Navigate to the 2nd option from the top (Top most Recovery Boot Option) and then hit ```ENTER```; This will get you to the ****Recovery Menu****.
+
+ 
+
+4. Now, the root prompt shows up like: ```root@ubuntu:~#```.
+
+5. Remount the filesystem using: ``` mount -o remount,rw / ```.
+
+6. Next, you need to know your username. You can do this by using: ``` ls /home ```.
+
+7. To change the password, use: ``` passwd userName ```, replacing userName with your username.
+
+
+8. Type in ```exit``` and hit ```ENTER``` to go back to the Recovery Menu and then select ****resume**** to boot into Ubuntu.
+
+
+
+
+
+
+
+_Images taken from stackoverflow_
diff --git a/docs/software/ros2.md b/docs/software/ros2.md
new file mode 100644
index 0000000..c484b3b
--- /dev/null
+++ b/docs/software/ros2.md
@@ -0,0 +1,111 @@
+// TODO: Migrate Getting Started to ROS2, or vice versa
+
+# Migrating to ROS 2
+
+It's time -- we're migrating to ROS 2, the next major version of ROS! Here, we'll document the process of setting up your computer to develop for ROS2, the migration process, and any other relevant information.
+
+## System Requirements
+
+Autonomous robotics is computationally expensive, especially when running simulations.
+Your VM or computer should have at least 4GB, although it will run much faster with
+8GB of RAM or higher. You should have at least a dual-core system, but using
+more cores will allow compilation to run much faster.
+
+If you are using a virtual machine, you can change the amount of RAM and the
+number of CPU cores allotted to the virtual machine by visiting the settings
+of your VM software.
+
+## Setting Up Ubuntu
+
+### Choosing an Installation Method
+
+You will need to install **Ubuntu 24.04 LTS** (disk image downloads linked below),
+the main operating system supported by ROS and our tools. Our tools are not setup
+to work on other operating systems, including other Linux distributions, macOS,
+and Windows.
+
+To use Ubuntu in MIL, you have two options:
+
+1. Use a **virtual machine**. A virtual machine uses your current operating system
+to virtually host another operating system (in this case, Ubuntu). This could
+cause your Ubuntu environment to run slow (in some cases, it might be unusable)
+and may cause you to experience issues with certain programs.
+
+2. **Dual-boot your computer.** Dual booting will allocate a piece of your computer's
+storage to a new operating system, which will be installed on your computer directly.
+This dual-booted solution will not run on top of your current operating system, but
+will instead run by directly using your computer's resources.
+
+Dual-booting your computer is highly recommended over using a virtual machine,
+as it allows your Ubuntu setup to tap directly into your computer's resources.
+However, it's totally your choice.
+
+:::{warning}
+If you **have an M-series (ARM) Mac computer**, you will need to use a
+virtual machine as these systems are not able to have two operating systems installed
+at once. Intel-based Macs may also experience some issues with dual-booting Ubuntu.
+:::
+
+The following diagram should give you insight into which method is best for you.
+Note that the diagram is only a recommendation. If you have installed Linux before,
+or know of a technical issue with your computer, you may know that a different
+method is best for you.
+
+
+
+### Installing Ubuntu
+
+Here are the links to appropriate `.iso` (disk image) files. Note that you will
+need to choose the correct disk image based on your computer's architecture. You
+do not always need to download these files - they are only needed for some installation
+methods.
+
+| Architecture | URL |
+|-----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| AMD64 (most Windows computers, Intel-based Mac computers) | [ubuntu-24.04.1-desktop-amd64.iso](https://releases.ubuntu.com/noble/ubuntu-24.04.1-desktop-amd64.iso) |
+| ARM64 (Apple Silicon Mac computers) | 1. Ubuntu releases (faster): [noble-desktop-arm64.iso](https://cdimage.ubuntu.com/noble/daily-live/current/noble-desktop-arm64.iso) 2. MIL mirror (slower): [noble-desktop-arm64.iso](https://mil.ufl.edu/software/noble-desktop-arm64.iso) |
+
+For specific installation methods, please choose one of the methods from the [getting started page](/software/getting_started), and substitute the Ubuntu 24.04 iso for the Ubuntu 20.04 iso file where needed.
+
+### Cloning our repository
+
+Unlike ROS 1, our repository will no longer live in `~/catkin_ws/src/`. Now, it's new home will be your home directory!
+
+```bash
+$ sudo apt update
+$ sudo apt upgrade
+$ sudo apt install git
+$ git clone -j8 https://github.com/uf-mil/mil2
+```
+
+### Installing ROS 2
+
+Our installation script has been ported over to ROS 2, so it should be a simple installation:
+
+```bash
+$ cd mil2
+$ ./scripts/install.sh
+```
+
+### Installing `pre-commit`
+
+Don't forget to install `pre-commit` to check your changes before committing!
+
+```bash
+$ pip3 install -U pre-commit
+$ pre-commit install
+$ pre-commit run --all-files # should show no errors!
+yamllint.................................................................Passed
+black....................................................................Passed
+... etc.
+```
+
+## Learning about ROS 2
+
+While ROS 2 has many parallels to ROS 1, it will be worth your time to
+review a little bit about the changes from ROS 1. These pages are good
+reads before working with ROS 2:
+
+* [ROS docs on "Migrating from ROS 1"](https://docs.ros.org/en/jazzy/How-To-Guides/Migrating-from-ROS1.html)
+* [Using `colcon` to build packages](https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries/Colcon-Tutorial.html)
+* [Image: ROS 1 vs ROS 2 architecture](https://www.researchgate.net/profile/Takuya-Azumi/publication/309128426/figure/fig1/AS:416910068994049@1476410514667/ROS1-ROS2-architecture-for-DDS-approach-to-ROS-We-clarify-the-performance-of-the-data.png)
diff --git a/docs/software/rostest.md b/docs/software/rostest.md
new file mode 100644
index 0000000..ff00b68
--- /dev/null
+++ b/docs/software/rostest.md
@@ -0,0 +1,172 @@
+# Writing Unit Tests with `rostest`
+
+An important part of developing software for autonomous systems is testing. Testing
+is integral to ensuring that software works in a variety of environments under
+a variety of conditions; without tests, it's common to write mistakes in software
+that can lead to the failure of systems.
+
+ROS, the middleware powering our robots, provides great interfaces to writing
+unit tests for C++ and Python programs, using `gtest` and `unittest` as the testing
+libraries, respectively.
+
+## Why write tests?
+
+Why is it even important to write tests for our software? Why is it important to
+write tests for software that already _seems_ to work?
+
+Here's a great answer, from the [ROS wiki page on Unit Testing](http://wiki.ros.org/Quality/Tutorials/UnitTesting):
+> 1. **You can make incremental updates to your code more quickly.** We have hundreds of packages with many interdependencies, so it's hard to anticipate the problems a small change might cause. If your change passes the unit tests, you can be confident that you haven't introduced problems — or at least the problems aren't your fault.
+> 1. **You can refactor your code with greater confidence.** Passing the unit tests verifies that you haven't introduced any bugs while refactoring. This gives you this wonderful freedom from change fear! You can actually make things good quality!
+> 1. **It leads to better designed code.** Unit tests force you to write your code so that it can be more easily tested. This often means keeping your underlying functions and framework separate, which is one of our design goals with ROS code.
+> 1. **They prevent recurring bugs (bug regressions).** It's a good practice to write a unit test for every bug you fix. In fact, write the unit test before you fix the bug. This will help you to precisely, or even deterministically, reproduce the bug, and much precisely understand what the problem is. As a result, you will also create a better patch, which you can then test with your regression test to verify that the bug is fixed. That way the bug won't accidentally get reintroduced if the code gets modified later on. Also, whoever should accept your patch in a pull request, they will be much easier to convince that the problem is solved, and the contribution is of high quality.
+> 1. **They let you blame other people (contract-based development).** A unit test is documentation that your code meets its expected contract. If your contribution passes the tests written by others, you can claim that you did your job right. If someone else's code fails tests, you can reject it as being not of sufficient quality.
+> 1. **Other people can work on your code more easily (an automatic form of documentation).** It's hard to figure out whether you've broken someone else's code when you make a change. The unit tests are a tool for other developers to validate their changes. Automatic tests document your coding decisions, and communicate to other developers automatically about their violation. Thus tests become documentation for your code — a documentation that does not need to be read for the most time, and when it does need to be inspected the test system will precisely indicate what to read (which tests fail). By writing automatic tests you make other contributors faster. This improves the entire ROS project.
+> 1. **It is much easier to become a contributor to ROS if we have automated unit tests.** It is very difficult for new external developers to contribute to your components. When they make changes to code, they are often doing it in the blind, driven by a lot of guesswork. By providing a harness of automated tests, you help them in the task. They get immediate feedback for their changes. It becomes easier to contribute to a project, and new contributors to join more easily. Also, their first contributions are of higher quality, which decreases the workload on maintainers. A win-win!
+> 1. **Automatic tests simplify maintainer-ship.** Especially for mature packages, which change more slowly, and mostly need to be updated to new dependencies, an automatic test suite helps to very quickly establish whether the package still works. This makes it much easier to decide whether the package is still supported or not.
+> 1. **Automatic tests amplifying Value of Continuous Integration.** Regression tests, along with normal scenario-based requirements tests contribute to overall body of automated tests for your component. This increases effectiveness of the build system and of continuous integration (CI). Your component is better tested against evolution of other APIs that it depends on (CI servers will tell you better and more precisely what problems develop in your code).
+
+## Good testing practices
+
+While testing at all is awesome, having especially extensive unit tests can be
+very helpful in catching errors quickly. Unit tests can be improved by incorporating
+more of these principles.
+
+### Fuzzy and mutation testing
+
+One practice for writing strong unit tests includes the use of mutation and/or
+fuzzy testing. In this testing practice, you purposefully "break" the program with
+the hope that the tests catch the error successfully. You can do this manually,
+or with the help of tools.
+
+To manually fizz code, begin by thinking what could easily break your code. For example,
+if you use a string as an argument to a function or class' constructor, what if you
+supply a string that's 20,000 lines long? Does the class completely crash unexpectedly,
+or does it fail in an expected way? What if you use an empty string, or if you
+use a number instead of a string?
+
+Furthermore, you can use tools to help you catch errors that should be added. `mutmut`
+is a Python tool that implements a mutation testing framework. You can run the tool
+over a specific package and its tests to identify areas that are not covered by tests.
+
+```bash
+$ mutmut run --runner "rostest package_name package_test.test" \
+ --paths-to-mutate src \
+ --tests-dir test # Run mutation tester
+$ mutmut html # Create an HTML file showing what happened during testing
+$ xdg-open html/index.html # Browse the HTML file to determine what needs to be improved
+```
+
+## Python unit tests with {mod}`unittest`
+
+To write unit tests in python, you should use {mod}`unittest`. The structure of a unit
+test looks like this:
+
+```python
+import unittest
+import rostest
+from calculator_package import Calculator
+
+class NumTest(unittest.TestCase):
+ def setUp(self):
+ self.calculator = Calculator()
+
+ def test_add(self):
+ self.assertEqual(self.calculator.add(1, 2), 3)
+ self.assertEqual(self.calculator.add(-1, 0), -1)
+
+ def test_sub(self):
+ self.assertEqual(self.calculator.subtract(1, 2), -1)
+ self.assertEqual(self.calculator.subtract(10, 7), 3)
+
+ def tearDown(self):
+ self.calculator.cleanup()
+
+if __name__ == "__main__":
+ rostest.rosrun("calculator_package", "test_basic_operations", NumTest)
+ unittest.main()
+```
+
+In the example, there are several important pieces:
+1. {meth}`~.unittest.TestCase.setUp()` and {meth}`~.unittest.TestCase.tearDown()`
+ are called before and after each test, respectively. These methods can be used
+ to set up and clean up resources, as needed.
+1. Each test is a method that begins with `test_`. Methods that do not begin with
+ `test_` will not register as tests.
+1. You can use `assertX` methods to assert that the results of operations are
+ expected. Example method names include {meth}`~.unittest.TestCase.assertEqual`,
+ {meth}`~.unittest.TestCase.assertTrue`, and {meth}`~.unittest.TestCase.assertIn`.
+
+You can also write unit tests for asynchronous operations. Check out our example
+from our {mod}`axros` module:
+
+```python
+import axros
+import unittest
+import rostest
+
+class BasicNodeHandleTest(unittest.IsolatedAsyncioTestCase):
+ """
+ Tests basic nodehandle functionality.
+ """
+
+ nh: axros.NodeHandle
+
+ async def asyncSetUp(self):
+ self.nh = axros.NodeHandle.from_argv("basic", always_default_name = True)
+ await self.nh.setup()
+
+ async def test_name(self):
+ self.assertEqual(self.nh.get_name(), "/basic")
+
+ async def asyncTearDown(self):
+ await self.nh.shutdown()
+
+if __name__ == "__main__":
+ rostest.rosrun("axros", "test_basic_nodehandle", BasicNodeHandleTest)
+ unittest.main()
+```
+
+## Integrating tests with ROS
+
+After writing tests with `unittest` or `gtest`, you need to actually integrate
+them with ROS. This allows them to be tested in our continuous integration systems.
+
+To begin, make a `test/` directory in the package where the test lies. In this test
+folder, write a `.test` file in XML. This test file is actually a launch
+file, so you have a lot of flexibility in what launches when the test is executed.
+However, the most important tag is the `` tag. This specifies what tests
+are actually ran and analyzed for their output.
+
+Below is an example test file named `axros.test`. This test file launches one test
+file named `test_basic_nodehandle.py`. At its core, this is all you need to run
+tests from a test file. You can optionally also launch nodes, set parameters, and
+use conditionals, as you can with any launch file.
+
+```xml
+
+
+
+```
+
+You can see that the `` tag allows us to specify the name of the test, the package
+where the test can be found, and most importantly its `type`, or the name of the
+executable that runs the test. We can also add a time limit to the test to ensure
+that it doesn't run forever.
+
+The next step is to add recognition of this test file into your package's `CMakeLists.txt`
+file. You can do so by adding a few lines to this file:
+
+```cmake
+if(CATKIN_ENABLE_TESTING)
+ find_package(rostest REQUIRED)
+ add_rostest(test/axros.test)
+endif()
+```
+
+The argument to the `add_rostest` function is the name of your package's test file.
+
+Now, you should be able to see your tests when you compile:
+```
+$ catkin_make # Run catkin_make to compile everything
+$ catkin_make run_tests # Now, run all tests! In the output, you should see your test being ran.
+```
diff --git a/docs/software/rqt.md b/docs/software/rqt.md
new file mode 100644
index 0000000..258c435
--- /dev/null
+++ b/docs/software/rqt.md
@@ -0,0 +1,437 @@
+# Implementing GUI Based Tools Using `rqt`
+
+## Introduction
+
+RQT (ROS Qt-based GUI Framework) is a powerful tool that provides a graphical
+user interface for ROS (Robot Operating System) applications. It allows users
+to monitor ROS topics, interact with nodes, visualize data, and more. This
+document serves as a user guide for understanding and effectively using RQT.
+
+### Benefits of RQT
+
+- **Graphical Interface**: RQT provides a user-friendly graphical interface,
+ making it easier to visualize data, monitor topics, and interact with nodes.
+ This is especially helpful for users who prefer a GUI based approach over
+ the command line.
+
+- **Centralized Tool**: RQT serves as a centralized tool for various ROS tasks,
+ including visualization, configuration, and debugging. This reduces the need
+ to switch between multiple terminals and tools, streamlining the development
+ process.
+
+- **Extensibility**: RQT's plugin architecture allows users to create custom
+ plugins to tailor the tool to their specific application needs. This
+ extensibility significantly enhances RQT's capabilities and to various
+ robotic systems.
+
+- **Integration with ROS**: RQT is tightly integrated with ROS, ensuring
+ seamless interaction with ROS nodes, topics, and services. This integration
+ simplifies the process of debugging and analyzing data in real-time.
+
+## Installation
+
+Before using RQT, make sure you have ROS installed on your system. If ROS is
+not yet installed, follow the official ROS installation guide for your
+operating system. Once ROS is installed, you can install RQT using the package
+manager:
+
+```bash
+sudo apt-get install ros-noetic-rqt
+```
+
+## Getting Started
+
+### Launching RQT
+
+To launch RQT, open a terminal and run the following command:
+
+```bash
+rqt
+```
+
+This command will launch the RQT Graphical User Interface, displaying a
+default layout with available plugins.
+
+## Monitoring Information with RQT
+
+RQT provides various plugins to monitor information published on specific ROS
+topics. The most common plugin for this purpose is the Plot plugin.
+
+### Subscribing to Specific Topics
+
+1. Open RQT using the command mentioned in the previous section.
+1. Click on the "Plugins" menu in the top toolbar and select "Topics" >
+ "Message Publisher."
+1. A new "Message Publisher" tab will appear. Click on the "+" button to
+ subscribe to a specific topic.
+1. Choose the desired topic from the list and click "OK."
+1. Now, you can monitor the information published on the selected topic in
+ real-time.
+
+### Displaying Data with Plot Plugin
+
+1. Open RQT using the command mentioned earlier.
+1. Click on the "Plugins" menu in the top toolbar and select
+ "Visualization" > "Plot."
+1. A new "Plot" tab will appear. Click on the "+" button to add a plot.
+1. Choose the topic you want to visualize from the list, select the message
+ field, and click "OK."
+1. The plot will start displaying the data sent over the selected topic.
+
+## Configuring RQT
+
+RQT allows users to customize its appearance and layout to suit their preferences.
+
+### Theme Configuration
+
+1. Open RQT using the command mentioned earlier.
+1. Click on the "View" menu in the top toolbar and select "Settings."
+1. In the "Settings" window, go to the "Appearance" tab.
+1. Here, you can change the color scheme, font size, and other visual settings.
+
+### Layout Configuration
+
+1. Open RQT using the command mentioned earlier.
+1. Rearrange existing plugins by clicking on their tab and dragging them to
+ a new position.
+1. To create a new tab, right-click on any existing tab and select "Add New Tab."
+1. Drag and drop desired plugins onto the new tab.
+1. Save your customized layout by going to the "View" menu and selecting
+ "Perspectives" > "Save Perspective."
+
+## Writing RQT Plugins
+
+RQT allows users to create their custom plugins to extend its functionality.
+Writing RQT plugins is essential when the available plugins do not fully
+meet your application's requirements.
+
+### Plugin Structure
+
+To write an RQT plugin, you need to follow a specific directory structure and
+include Python or C++ code to implement the plugin's functionality. The
+essential components of an RQT plugin are:
+
+- **Plugin XML (`plugin.xml`)**: This file defines the plugin and its
+ dependencies, specifying essential information like name, description,
+ and which ROS packages it depends on.
+
+- **Python or C++ Code**: This code contains the actual implementation of the
+ plugin's functionality. For Python plugins, the code should extend the
+ `rqt_gui_py::Plugin` class, while for C++ plugins, it should extend the
+ `rqt_gui_cpp::Plugin` class.
+
+### Implementing a Basic Plugin
+
+In this section, we will walk through an example of implementing a basic RQT
+plugin. We will create a simple plugin to display the current time published
+by a ROS topic. The plugin will consist of a label that updates with the
+current time whenever a new message is received.
+
+#### Step 1: Create the Plugin Package
+
+Create a new ROS package for your plugin using the `catkin_create_pkg` command:
+
+```bash
+catkin_create_pkg my_rqt_plugin rospy rqt_gui_py
+```
+
+The package dependencies `rospy` and `rqt_gui_py` are required to work with
+ROS and create a Python-based RQT plugin.
+
+#### Step 2: Implement the Plugin Code
+
+Next, create a Python script for your plugin. In the `src` directory of your
+package, create a file named `my_rqt_plugin.py` with the following content:
+
+```python
+#!/usr/bin/env python
+
+import rospy
+from rqt_gui_py.plugin import Plugin
+from python_qt_binding.QtWidgets import QLabel, QVBoxLayout, QWidget
+from std_msgs.msg import String
+import time
+
+class MyRqtPlugin(Plugin):
+
+ def __init__(self, context):
+ super(MyRqtPlugin, self).__init__(context)
+ self.setObjectName('MyRqtPlugin')
+
+ # Create the main widget and layout
+ self._widget = QWidget()
+ layout = QVBoxLayout()
+ self._widget.setLayout(layout)
+
+ # Create a label to display the current time
+ self._label = QLabel("Current Time: N/A")
+ layout.addWidget(self._label)
+
+ # Subscribe to the topic that provides the current time
+ rospy.Subscriber('/current_time', String, self._update_time)
+
+ # Add the widget to the context
+ context.add_widget(self._widget)
+
+ def _update_time(self, msg):
+ # Update the label with the received time message
+ self._label.setText(f"Current Time: {msg.data}")
+
+ def shutdown_plugin(self):
+ # Unregister the subscriber when the plugin is shut down
+ rospy.Subscriber('/current_time', String, self._update_time)
+
+ def save_settings(self, plugin_settings, instance_settings):
+ # Save the plugin's settings when needed
+ pass
+
+ def restore_settings(self, plugin_settings, instance_settings):
+ # Restore the plugin's settings when needed
+ pass
+
+```
+
+In this code, we create a plugin class named `MyRqtPlugin`, which inherits
+from `rqt_gui_py.Plugin`. The `__init__` method sets up the GUI elements, such
+as a label, and subscribes to the `/current_time` topic to receive time updates.
+
+#### Step 3: Add the Plugin XML File
+
+Create a file named `plugin.xml` in the root of your package to define the
+plugin. Add the following content to the `plugin.xml`:
+
+```xml
+
+
+
+ A custom RQT plugin to display the current time.
+
+
+ My RQT Plugin
+ settings
+ Display the current time.
+
+
+
+```
+
+This XML file defines the plugin class, its description, and the icon to be
+displayed in the RQT GUI.
+
+#### Step 4: Build the Plugin
+
+Build your plugin package using `catkin_make`:
+
+```bash
+catkin_make
+```
+
+#### Step 5: Launch RQT and Load the Plugin
+
+Launch RQT using the command mentioned earlier:
+
+```bash
+rqt
+```
+
+Once RQT is open, navigate to the "Plugins" menu and select "My RQT Plugin"
+from the list. The plugin will be loaded, and you should see the label
+displaying the current time.
+
+### Adding Custom Functionality
+
+The example plugin we implemented is a simple demonstration of how to create
+an RQT plugin. Depending on your application's requirements, you can add more
+sophisticated features, such as custom data visualization, interactive
+controls, and integration with other ROS elements.
+
+You can also improve the plugin by adding error handling, additional options
+for time formatting, and the ability to pause/resume the time updates.
+
+## Implementing a More Advanced Plugin
+
+In this section, we will implement a more advanced RQT plugin that visualizes
+data from multiple ROS topics using a 2D plot. This plugin will allow users to
+choose which topics to plot and specify the message field to display on the X
+and Y axes. Let's call this plugin "ROS Data Plotter."
+
+### Step 1: Create the Plugin Package
+
+Create a new ROS package for your plugin using the `catkin_create_pkg` command:
+
+```bash
+catkin_create_pkg ros_data_plotter rospy rqt_gui_py matplotlib
+```
+
+The package dependencies `rospy`, `rqt_gui_py`, and `matplotlib` are required
+to work with ROS, create a Python-based RQT plugin, and plot data, respectively.
+
+### Step 2: Implement the Plugin Code
+
+Next, create a Python script for your plugin. In the `src` directory of your
+package, create a file named `ros_data_plotter.py` with the following content:
+
+```python
+#!/usr/bin/env python
+
+import rospy
+from rqt_gui_py.plugin import Plugin
+from python_qt_binding.QtWidgets import QWidget, QVBoxLayout, QComboBox
+from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
+from matplotlib.figure import Figure
+from std_msgs.msg import Float32 # Modify this import based on your data type
+
+class ROSDataPlotter(Plugin):
+
+ def __init__(self, context):
+ super(ROSDataPlotter, self).__init__(context)
+ self.setObjectName('ROSDataPlotter')
+
+ # Create the main widget and layout
+ self._widget = QWidget()
+ layout = QVBoxLayout()
+ self._widget.setLayout(layout)
+
+ # Create a combo box to select topics and message fields
+ self._topic_field_selector = QComboBox()
+ self._topic_field_selector.currentIndexChanged.connect(self._update_plot)
+ layout.addWidget(self._topic_field_selector)
+
+ # Create the matplotlib figure and plot
+ self._figure = Figure()
+ self._canvas = FigureCanvas(self._figure)
+ layout.addWidget(self._canvas)
+
+ # Initialize the plot
+ self._update_plot()
+
+ # Add the widget to the context
+ context.add_widget(self._widget)
+
+ def _update_plot(self):
+ # Clear the previous plot data
+ self._figure.clear()
+ axes = self._figure.add_subplot(111)
+
+ # Get the selected topic and field from the combo box
+ selected_topic_field = self._topic_field_selector.currentText()
+ topic, field = selected_topic_field.split(' - ')
+
+ # Subscribe to the selected topic
+ rospy.Subscriber(topic, Float32, self._plot_data) # Modify this based on your data type
+
+ def _plot_data(self, msg):
+ # Get the selected topic and field from the combo box
+ selected_topic_field = self._topic_field_selector.currentText()
+ topic, field = selected_topic_field.split(' - ')
+
+ # Plot the data on the graph
+ # Modify this part based on your data type and plot requirements
+ x_data = rospy.Time.now().to_sec() # Use timestamp as X-axis
+ y_data = getattr(msg, field) # Use the specified field from the message as Y-axis data
+ axes = self._figure.add_subplot(111)
+ axes.plot(x_data, y_data)
+
+ # Refresh the plot
+ self._canvas.draw()
+
+ def shutdown_plugin(self):
+ # Unsubscribe from the topic when the plugin is shut down
+ self._topic_field_selector.clear()
+ rospy.Subscriber(topic, Float32, self._plot_data)
+
+ def save_settings(self, plugin_settings, instance_settings):
+ # Save the plugin's settings when needed
+ pass
+
+ def restore_settings(self, plugin_settings, instance_settings):
+ # Restore the plugin's settings when needed
+ pass
+
+```
+
+In this code, we create a plugin class named `ROSDataPlotter`, which inherits
+from `rqt_gui_py.Plugin`. The `__init__` method sets up the GUI elements,
+such as a combo box to select topics and message fields, and the matplotlib
+figure to plot the data. The `_update_plot` method updates the plot whenever
+a new topic or message field is selected from the combo box. The `_plot_data`
+method is called when new messages are received on the selected topic, and it
+plots the data on the graph.
+
+### Step 3: Add the Plugin XML File
+
+Create a file named `plugin.xml` in the root of your package to define the
+plugin. Add the following content to the `plugin.xml`:
+
+```xml
+
+
+
+ An advanced RQT plugin to plot data from multiple ROS topics.
+
+
+ ROS Data Plotter
+ settings
+ Plot data from selected ROS topics.
+
+
+
+```
+
+This XML file defines the plugin class, its description, and the icon
+to be displayed in the RQT GUI.
+
+### Step 4: Build the Plugin
+
+Build your plugin package using `catkin_make`:
+
+```bash
+catkin_make
+```
+
+### Step 5: Launch RQT and Load the Plugin
+
+Launch RQT
+
+ using the command mentioned earlier:
+
+```bash
+rqt
+```
+
+Once RQT is open, navigate to the "Plugins" menu and select "ROS Data Plotter"
+from the list. The plugin will be loaded, and you should see a combo box to
+select topics and fields, and a graph to display the plotted data.
+
+### Adding Custom Functionality
+
+In this more advanced example, we created an RQT plugin that allows users to
+plot data from multiple ROS topics. The example focused on plotting Float32
+messages, but you can modify the `_plot_data` method to handle different
+message types or plot multiple data series on the same graph.
+
+You can further enhance the plugin by adding features like legends, axis
+labels, custom plot styles, data smoothing, and real-time updates.
+Additionally, you can provide options to save the plotted data as CSV
+or images for further analysis.
+
+With custom plugins, you have the freedom to tailor RQT to suit your
+specific application's visualization needs, making it a versatile tool
+for ROS developers.
+
+## External Resources
+
+- [ROS wiki page for rqt](https://wiki.ros.org/rqt)
+- [GeorgiaTech RoboJacket's rqt tutorial](https://www.youtube.com/watch?v=o90IaCRje2I)
+- [Creating Custom rqt Plugins](https://github.com/ChoKasem/rqt_tut)
+
+## Conclusion
+
+Congratulations! You have now learned the basics of using RQT, including
+monitoring information sent over specific topics, configuring RQT to your
+preferences, writing your custom plugins, and understanding the importance
+of using RQT in ROS development. RQT provides a user-friendly and powerful
+graphical interface for ROS applications, making it an essential tool for
+developers and researchers working with ROS-based robotic systems. By
+leveraging RQT's capabilities, you can streamline your development process
+and gain valuable insights into your robot's behavior.
diff --git a/docs/software/rtx_2080_drivers.md b/docs/software/rtx_2080_drivers.md
new file mode 100644
index 0000000..5625613
--- /dev/null
+++ b/docs/software/rtx_2080_drivers.md
@@ -0,0 +1,72 @@
+# Installing Drivers for RTX 2080
+
+Here is a quick guide for how to install the latest NVIDIA GPUs for the shuttle computer (which uses the NVIDIA GEFORCE GTX 970).
+
+## Installing the NVIDIA Driver
+First of all, you want to add the `ppa:graphics-drivers/ppa` repository into your computer system.
+
+Run the commands:
+
+ $ sudo apt-add-repository ppa:graphics-drivers/ppa
+ $ sudo apt update
+
+Update the packages that you downloaded with:
+
+ $ sudo apt-get update
+ $ sudo apt-get upgrade
+
+Next, verify that your system recognizes the correct graphic card model and recommended driver by running the command:
+
+ $ ubuntu-drivers devices
+
+All the recommended drivers for your computer should appear in the terminal like this:
+
+ $ ubuntu-drivers devices
+ == /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
+ modalias : pci:v000010DEd000013C2sv00003842sd00002976bc03sc00i00
+ vendor : NVIDIA Corporation
+ model : GM204 [GeForce GTX 970]
+ driver : nvidia-driver-430 - third-party free
+ driver : nvidia-driver-390 - third-party free
+ driver : nvidia-driver-435 - distro non-free
+ driver : nvidia-driver-440 - third-party free recommended
+ driver : nvidia-driver-410 - third-party free
+ driver : nvidia-driver-415 - third-party free
+ driver : xserver-xorg-video-nouveau - distro free builtin`
+
+To install the recommended driver automatically, run:
+
+ $ sudo ubuntu-drivers autoinstall
+
+To select a specific driver that needs to be installed, run the command:
+
+ $ sudo apt install nvidia-
+
+Once this is done installing, reboot the system with:
+
+ $ sudo reboot
+
+## Verifying that the correct GPU is being used and is in Default Compute Mode
+
+The drivers that we install on this computer must be defaulted to Compute Mode. To verify that the correct driver is being used, run the command:
+
+ $ nvidia-smi
+
+An interface containing information about your NVIDIA driver should show up in your terminal.
+
+On the top of the table that appears should be the Driver Version. Verify that this is the correct driver you want installed. Below this, under the GPU section, there will be a '0' or a '1'. If the GPU is defaulted to '0', then the driver is already in Compute Mode. If not (or if you want further verification that the driver is in compute mode), run:
+
+ $ nvidia-smi -i 0 -c 0
+
+If the device was already in Default Compute mode, a message will appear in the terminal.
+
+## References
+For references on how the driver was installed, visit these websites:
+
+
+
+
+
+For how to switch the GPUs into Compute Mode, visit this website:
+
+
diff --git a/docs/software/scripts.md b/docs/software/scripts.md
new file mode 100644
index 0000000..88c780a
--- /dev/null
+++ b/docs/software/scripts.md
@@ -0,0 +1,36 @@
+# Scripts
+
+At MIL, we use a lot of scripts to help us complete tasks quickly! Check out some things you can do with them:
+
+## Occupancy Grid
+
+**Draw an occupancy grid:**
+
+ $ roscd mil_tools && ./mil_tools/nodes/ogrid_draw.py
+
+**Maintains a bag file with multiple topics:**
+
+ $ roscd mil_tools && ./mil_tools/nodes/online_bagger.py
+
+## Keyboard Control
+To control the robot using the keyboard, use the ``KeyboardClient`` and ``KeyboardServer``
+classes inside the ``navigator_keyboard_control`` package.
+
+The two nodes within the package can be run through ``rosrun``.
+
+## Alarms
+**Clear an alarm:**
+
+ $ roscd ros_alarms && rosrun nodes/clear
+
+**Monitor an alarm:**
+
+ $ roscd ros_alarms && rosrun nodes/monitor
+
+**Raise an alarm:**
+
+ $ roscd ros_alarms && rosrun nodes/raise
+
+**Reports the status of an alarm:**
+
+ $ roscd ros_alarms && rosrun nodes/report
diff --git a/docs/software/submodule.md b/docs/software/submodule.md
new file mode 100644
index 0000000..82fb343
--- /dev/null
+++ b/docs/software/submodule.md
@@ -0,0 +1,101 @@
+# Working with Git Submodules
+
+Submodules are an important part of the MIL repo! These submodules allow our code to function properly! Formally, these submodules are directories inside our repository somewhere which are actually a Git repository themselves. In essence, these directories (inside the main MIL directory) are pointing at a specific commit inside another Git repository.
+
+This pattern can be confusing, so here are some commands to help you out!
+
+## Adding a new submodule
+
+To add a new submodule into a repository, you can use `git submodule add `!
+
+```sh
+$ git submodule add https://github.com/chaconinc/DbConnector
+```
+
+When you do this, a new directory called `DbConnector` will appear, and the `.gitmodules` file (which keeps track of your submodules) will be updated. Now, you'll need to actually commit it to the repository, like any other folder you add:
+```sh
+$ git commit -am 'Add DbConnector module'
+$ git push
+```
+
+## Cloning a repository with submodules
+
+When you clone a repository with nested submodules, you must run some commands to get your submodules up and running:
+```sh
+$ git submodule update --init --recursive
+```
+In this command, `--init` initializes your submodule configuration file, while `--recursive` does this for all nested submodules in the project.
+
+## Pulling in upstream changes in submodules
+### Through the submodule remote
+
+Sometimes, submodules can be updated by another user, and you'll need to pull these changes into your own copy. If you would like to do this for one submodule, `cd` into the submodule, and then update the specific submodule yourself:
+
+```sh
+$ cd DbConnector
+$ git fetch
+$ git merge origin/master
+$ cd ..
+$ git commit -am 'Pulled in new submodule code'
+$ git push
+```
+
+Because you committed with the new submodule code, whenever others fetch new changes, they will also get the update submodule changes.
+
+While the above is great for small, independent submodule changes where you want more customizability in how the submodule is updated, repeatedly doing multiple commands to update the submodule can get annoying! Thankfully, git helps to fix that with:
+```sh
+$ git submodule update --remote
+```
+This command will update all submodules from their `remote` repositories. If you want to update a submodule from another branch its on, you can change your Git config.
+```sh
+$ git config .gitmodules submodule.DbConnector.branch stable
+$ git submodule update --remote DbConnector
+```
+Now, when you update the `DbConnector` repository, it will pull from the `stable` branch. You can then `git commit` and `git push` as normal.
+
+### Through the main project remote
+
+Normally, to update the project, you would run `git pull`. However, when working with submodules, this won't be enough to create effective changes. This will get the relevant changes that occurred in the submodules, but it won't actually *update* the submodules.
+
+Instead, you will also need to run:
+```sh
+$ git submodule update --init --recursive
+```
+
+These two commands can be simplified into one through:
+```sh
+$ git pull --recurse-submodules
+```
+
+Sounds like a lot to type? Let's make `--recurse-submodules` default!
+```sh
+$ git config submodule.recurse true
+```
+
+## Working on a submodule
+Eventually, you may want to make some changes to the submodule to help improve the code!
+
+Before working, let's merge in any changes from the upstream:
+```sh
+$ git submodule update --remote --merge
+```
+
+Now, we can make some changes:
+```sh
+$ cd DbConnector/
+$ vim src/example.cpp
+$ git commit -am "Add example test"
+```
+
+You've now made a commit to the submodule. If it's been a while, and you want to rebase changes from the upstream:
+```sh
+$ git submodule update --remote --rebase
+# OR
+$ git submodule update --remote --merge
+```
+
+But, we still haven't actually pushed the changes!
+```sh
+$ git push --recurse-submodules=on-demand
+```
+Note that this will push any commits for **every** submodule. If you want to push some commits for one submodule, then `cd` into the submodule directory and use `git push`.
diff --git a/docs/software/zobelisk.md b/docs/software/zobelisk.md
new file mode 100644
index 0000000..900075c
--- /dev/null
+++ b/docs/software/zobelisk.md
@@ -0,0 +1,83 @@
+# Accessing Zobelisk
+In MIL, we have a high performance desktop computer called Zobelisk. We leverage
+our development containers to run multiple robot solutions and simulations at
+once all in separate isolated environments connected to the network.
+
+:::{note}
+In order to access Zobelisk, you must have an account on Zobelisk and be
+connected to the MIL network.
+
+In order to gain a login for Zobelisk, please reach out to a software lead.
+:::
+
+## Logging In
+To access the basic bash shell associated with your user account, you can use standard
+SSH protocol. This can be helpful if you'd like to store long-term material under
+your username on Zobelisk.
+
+To do so, sign in with `ssh` on your own Ubuntu installation:
+
+ $ ssh @192.168.37.176
+
+The IP address is the IP address of Zobelisk on the MIL network.
+
+## Get your UID
+After signing in over `ssh`, you can get your UID (user ID) assigned to your username
+by Linux:
+
+ zobelisk$ echo $UID
+
+This should print out a number around 1000. This number is your UID!
+
+## Using `sshfs` with Docker
+Great! Now that you've successfully signed in to Zobelisk, let's take it to the next
+level.
+
+If you'd like, you can use `sshfs` with Docker to run programs safely on Zobelisk.
+This means that instead of running programs in a bash terminal, that you will
+instead run them in a containerized environment (a fresh installation of Linux!).
+
+
+:::{warning}
+Currently, the MIL Software Team has reduced its usage of Docker compared to
+previous editions of the team. Therefore, these steps are not required, and
+we believe that you will be safe running most programs in a bash terminal
+on Zobelisk.
+
+The below scripts have not been thoroughly tested by this edition of the software
+team.
+:::
+
+To use a helpful script for this, try running
+
+ $ ./scripts/sshzobelisk
+
+This script does several things:
+
+1. Sets up an `openssh` server between you and Zobelisk.
+1. Generates an ssh key so that you can securely connect to Zobelisk.
+1. Starts (and then detaches from) a new `tmux` session capable of running ROS (the
+`$ROS_MASTER_URI` variable has been exported to it).
+1. Generates and launches a new Docker container with your copy of the repository
+(through the `ssh` server) and MIL-related tools.
+
+After the repository finished building, you can jump into the `tmux` session and
+began working on your project.
+
+## Test Your Setup
+In the remote container, launch SubjuGator with
+
+ @192.168.36.176$ roslaunch subjugator_launch gazebo.launch
+
+Then in the tmux session running on your computer, run
+
+ @192.168.36.176$ rostopic echo /odom
+
+If your setup is working correctly, you should see the changing odometry values of
+a moving sub simulation.
+
+## Log out
+
+To log out of the remote container, run
+
+ @192.168.36.176$ exit
diff --git a/docs/subjugator/cameras.md b/docs/subjugator/cameras.md
new file mode 100644
index 0000000..c1ad92d
--- /dev/null
+++ b/docs/subjugator/cameras.md
@@ -0,0 +1,22 @@
+# SubjuGator Cameras
+
+The SubjuGator comes with three cameras: two front cameras and a down camera.
+The front cameras can be used for obstacle avoidance, path planning, or any
+other vision tasks. The down camera is primarily used for objects placed on the
+ground; frequently, objects on the ground are helpful for indicating the direction
+of various other objects.
+
+## Namespaces
+
+The sub's cameras can be accessed through a selection of ROS topics. These topics
+usually indicate which camera is producing the image, along with any added filters
+or pipelines used on the image. Like every topic, the topics publishing data
+have names and namespaces.
+
+For example, the topic `/camera/front/right/image_raw` indicates that the image
+published on the topic is from the front right camera, and is the raw image from
+that camera.
+
+If you are planning to add new vision topics to the architecture of the sub,
+please follow these already existing organizational rules. It helps to have
+these topics under understandable names so new and old members are not confused.
diff --git a/docs/subjugator/design.rst b/docs/subjugator/design.rst
new file mode 100644
index 0000000..e7639e5
--- /dev/null
+++ b/docs/subjugator/design.rst
@@ -0,0 +1,6 @@
+Software Design
+---------------
+For an overview of the various nodes running on SubjuGator and how they
+interact, see the below graph (open in a new window).
+
+.. graphviz:: ../../SubjuGator/docs/high_level_architecture.dot
diff --git a/docs/subjugator/electrical.md b/docs/subjugator/electrical.md
new file mode 100644
index 0000000..eef1e7f
--- /dev/null
+++ b/docs/subjugator/electrical.md
@@ -0,0 +1,5 @@
+# Electrical Design
+
+The electrical design of the sub is featured below:
+
+
diff --git a/docs/subjugator/enabling.md b/docs/subjugator/enabling.md
new file mode 100644
index 0000000..13d7917
--- /dev/null
+++ b/docs/subjugator/enabling.md
@@ -0,0 +1,41 @@
+# Enabling SubjuGator
+
+Eventually, after working in simulations and theory for some amount of time,
+you're going to want to go out to a real body of water to test the submarine!
+That's perfect, this guide will help to walk you through some of the background
+info needed to get moving.
+
+## Power
+
+SubjuGator 8 can be powered through two methods, AC power, and batteries. You're
+going to want to use one over the other depending on where you're testing the
+robot. If you're testing out of the water, you're going to want to use AC power,
+as this will give you a nice, smooth uninterrupted power supply. If you're testing
+in the water, then AC power is no longer an option unless you want to break the
+power supply. Therefore, you'll need to use batteries.
+
+The AC power looks like a gray metal box, with a fan at two ends. It plugs into
+a wall. You should then be able to use the power supply with the sub through a
+connecting cable.
+
+Otherwise, you can use two 24V LiPo batteries in the sub's battery compartment.
+These batteries only last for a while, so use them sparingly, and don't try to
+use them excessively. Misusing batteries will typically result in a fire or puffy
+batteries.
+
+The submarine automatically boots up whenever power is connected. There's no
+on button!
+
+## SSH
+
+Now that the sub is on, you may to want to see what it's doing. That's where
+the magical SSH comes in! You can run programs on the sub's computer, which is
+helpful when you want to record bag files, run programs, see diagnostics, or
+do anything else!
+
+To be able to `ssh` into SubjuGator, you're going to need to be on the same
+network as the sub. Frequently, the [MIL Network Box](/infrastructure/network_box.rst)
+is used to achieve this. You should connect an ethernet cable to the sub over
+tether, and then insert this cable into the box. Then, you can insert your own
+Ethernet cables and be connected to the sub. For more information on the box,
+see its documentation page.
diff --git a/docs/subjugator/index.rst b/docs/subjugator/index.rst
new file mode 100644
index 0000000..14422e0
--- /dev/null
+++ b/docs/subjugator/index.rst
@@ -0,0 +1,34 @@
+SubjuGator
+==========
+
+This page provides general info about developing for
+`RoboSub `__, an annual
+competition for autonomous submarines. MIL has participated in RoboSub
+for 20+ years. Most code for this is hosted under ``SubjuGator/``.
+
+SubjuGator 8
+------------
+.. toctree::
+ :maxdepth: 1
+
+ design
+ testingprocedures.md
+ Simulating
+ Enabling
+ Cameras
+ PID Controller
+ Navigation Tube
+ Watercooling
+
+ electrical
+
+RoboSub
+-------
+.. toctree::
+ :maxdepth: 1
+
+ RoboSub
+
+ Lessons from 2023
+ Lessons from 2022
+ Lessons from 2019
diff --git a/docs/subjugator/lessons19.md b/docs/subjugator/lessons19.md
new file mode 100644
index 0000000..e7370bd
--- /dev/null
+++ b/docs/subjugator/lessons19.md
@@ -0,0 +1,18 @@
+# Lessons from RoboSub 2019
+
+- **Hydrophones**
+ - Before putting in water, rub dish soap over them. This will keep bubbles off.
+ - Air bubbles/pockets/vessels are the biggest problem and will cause distortion
+ Hydrophones should be placed as far away from air as is feasible and minimizing
+ material that might contain air pockets (such as 3D printed parts) near the
+ hydrophones is critical
+- Molykote 44 medium should be used to cover all of the holes on the female connector
+every time before inserting the connector.
+- **We should have had a prep checklist.** - This should be mandatory for each time
+the sub is put into the water. In RoboSub19 we forgot to close one of the air tubes
+in the valve box so it flooded during a semifinal run.
+- **We should design a method to perform effective surveying.** - Surveying consists
+of estimating the distances and angles between objects underwater. In RoboSub 2019
+the 3rd place team, Arizona State University, was able to navigate between tasks because
+they used an exceptional surveying method and leveraged an optic gyroscopic system
+to precisely rotate the sub.
diff --git a/docs/subjugator/lessons22.md b/docs/subjugator/lessons22.md
new file mode 100644
index 0000000..f2c2735
--- /dev/null
+++ b/docs/subjugator/lessons22.md
@@ -0,0 +1,182 @@
+# Lessons from RoboSub 2022
+
+## Overall Process
+
+* **TEST BEFORE, A LOT.** - At least a semester prior to the summer of the competition, a testing
+ schedule needs to be designed which involves pretty much testing biweekly in spring and weekly
+ during the summer. Test first single tasks in the smaller and more accessible pools but also,
+ test in a full course at least at a big pool such as Florida pool as much as possible when the
+ single tasks have been mastered. As soon as you arrive to the competition, dedicate the first
+ few tests to check the behavior of the sub in tasks that might have changed between Gainesville
+ and the new pool. We made the mistake of not taking this too seriously.
+
+* **We need to implement an automated check system for all systems.** - For example,
+the battery system should report it's voltage and the thrusters should be verified
+to ensure that the proper thrusters spin when asked. Other examples include having
+a check that cameras and sensors such as DVL, gyroscope, depth, output reasonable values.
+This should be automated and required (and hopefully quick) so that we can avoid having
+busted batteries or accidentally loose connections. At the competition, we needed to
+take out the robot multiple times because of things which could have been verified
+_before_ the sub was put in the water.
+
+* **We need to practice the logistic of testing in water more.** - The process for
+going to, working at, and packing up from the pool at the competition needs to be
+practiced. We need to have comprehensive list of equipment needed for any testing.
+The lists _must_ include only things that are brought with us to all testing, and
+it _must_ include all of the things that we need for any reasonably possible challenge.
+We should aim to be fully ready to test 10 minutes before when we actually plan
+to enter the water, as practice.
+
+* **We need a dedicated testing leader.** - One person needs to be fully responsible
+for assuring that these procedures are followed every time we do anything in or
+near the water. This assures that bystander effect doesn't lead to avoidable
+mistakes causing large setbacks. This does not mean that everyone else is unresponsible
+for ensuring proper testing techniques, rather, having a dedicated member helps
+to ensure that the practices will always be followed.
+
+* **We need to rest responsibly.** - Several nights during the competition we
+would not fall asleep until 1-2AM, and then be up before 6AM for the mandatory
+testing time drawing. This lack of sleep caused us to make mistakes we may
+not have made had we been more well-rested.
+
+* **We should have interacted more with other teams.** - One of the most notable
+things we missed out on was getting to interact with and learn from the other
+teams at the event, as we were always chasing our own issues. Had we been more
+stable at the competition, we likely would have had the time to interact with more
+teams.
+
+* **We should have had more of a social media presence.** - There is a lot of
+opportunities for recruiting, outreach, connection with mentor-ship and sponsorship
+opportunities, and interaction with other teams over the internet. Be it Instagram,
+Band, the mysterious data sharing platform, or old fashioned email, we are missing
+lots of support, motivation, opportunity, and experience that can be found through
+these platforms.
+
+* **We should have a designated person that signs up for testing slots.** - Two days
+of competition we missed chances to test in the pool because none of our team members
+woke up early to sign up for the slots. A way to solve this is to have a designated
+person sign up for the slots or at least a rotation where a person is responsible to
+sign up per day.
+
+* **We need to pack a replacement for everything in the sub.** - We forgot the radiator,
+spare thrusters and spare motherboards. The process of packing should not be done in a rush
+and on it we should think about what could break in the sub, and bring a replacement for
+every part of the sub.
+
+## Shipping
+Total items shipped for the team was:
+| # | Type | Shipped Via |
+|---|------------------------|---------------|
+| 3 | Large Pelicans | FedEx Ground |
+| 4 | Medium Pelicans | FedEx Ground |
+| 1 | Small Pelicans | FedEx Ground |
+| 1 | Sub Shipping Container | FedEx Freight |
+| 1 | Battery Box | UPS |
+
+Shipping was extremely painful to arrange this year. There were several primary reasons:
+ - Our shipping was arranged the week that we needed to ship, and the process of
+ loading wasn't completed until the day we were shipping the items.
+ - The items that were loaded were mostly cataloged, but not all of them were enumerated.
+ - The cataloguing wasn't for each box, it ended up being for the set of items each team was packing.
+ - We didn't know how many pelicans we would need, and ended up having to go get
+ more from [Solar Park](../../infrastructure/solar_park).
+ - Arranging the shipping pickup at the event ended up taking another day after
+ a FedEx Express Shipment truck attempted to pick up our packages instead of
+ a FedEx Ground Shipment truck.
+ - FedEx didn't ask or specify when Dr. Schwartz scheduled the pickup, and they
+ sent us a FedEx express truck who couldn't take our packages because they
+ were labeled for FedEx Ground.
+ - **Takeaway:** Make sure to check what label you got, and arrange shipping
+ to include the return label when getting it in the first place
+ - We should have taken more Pelican cases, as packing materials for the return trip
+ is more difficult because of time crunches, missing foam, and tiredness.
+ - The shipping paperwork, labels, return shipping, pick-up and drop-off times
+ and locations, and shipping manifests need to be completed several weeks
+ before the competition. Arranging them last minute is a recipe for failure.
+
+## Electrical
+
+Many issues faced by the electrical team during the competition were preventable.
+Lack of documentation and effective ways to debug costed us a lot of time. The
+following will need to be worked and improved on:
+
+- **We need more extensive electrical documentation.**
+ - Lack of documentation made debugging harder, as we had to quickly learn how
+ certain systems operated at the competition site.
+ - Documentation for each individual board and the higher level system will be
+ beneficial for understanding the submarine and help make onboarding easier.
+ - Have consistent format and include information such as purpose, bill of
+ material (BOM), and a description.
+
+- **We need to add more electrical redundancy.**
+ - We need to add a circuit which reports battery voltage and cuts off the batteries
+ if their voltage drops too low.
+ - Many batteries were lost due to running the sub too long and forgetting to
+ remove certain cables. There is a need for a board to warn and cut the power
+ once the battery goes under a certain percentage.
+ - We need to add locking connectors. These would have prevented cables from
+ accidentally coming loose while the sub was on the move.
+
+### Hydrophones
+
+We talked with Forrest during the 2022 competition and he warned us that the
+Sylphase hydrophone board was very sensitive to moisture. While it initially had
+a desiccant pack placed inside during shipping, we failed to pack more to replace
+it after it was saturated.
+
+The moisture causes the board to misbehave. We experienced an issue where a self
+check (reading and writing a value from a place called `"ADDR15"`) failed repeatedly.
+
+The connector in the hydrophone vessel was also problematic. We started getting an
+inconsistent "device not found" error after arriving at the competition.
+For some unknown reason, the connector used was a reversible USB micro B cable
+that none of us had ever seen used for anything else. Needless to say, it was
+rather janky. We ended up swapping it out for a standard USB micro B cable.
+
+## Mechanical
+
+- The weight of the sub is a detriment to testing and transport.
+ - We implemented a [litter](https://en.wikipedia.org/wiki/Litter_(vehicle))
+ style carrier that allowed us to carry the sub with relative ease.
+ - This comprised of two ~8' round wooden 1.5" diameter rods. These rods were
+ then tied ~6" apart in two places in their middles to prevent them from
+ opening too wide. After that, a rope with a loop in each end can be passed
+ through the sub's frame, above it's center of mass, and all loops are passed
+ over opposing ends of the rods. Two people can then crouch under the pair
+ of rods, placing one on each shoulder, and then they can stand and lift
+ the sub.
+ - This system would be much improved by adding some kind of formed shoulder
+ pads to spread the weight and add stability.
+- If we are going to continue using SubjuGator 8, the mechanical team will need
+ to find a way to transport the bot around efficiently.
+- Several mechanical and electrical systems were damaged by transport (either from
+ shipping or moving the sub around from the team village to the pool) and had to
+ be fixed multiple times. This involved opening up the main computer vessel,
+ the nav tube, the valve box, and hydrophone enclosure multiple times each. Most
+ of this damage came down to loose, non-locking connectors. (Mechanically this
+ was mostly represented as parts moving around inside of their respective vessels
+ and bumping wires and connectors loose.)
+
+## Software
+
+- We need to add Vim plugins on the sub's computer for all of our code so we can
+ quickly put together tests and missions as needed. We had lots of time loss
+ from not understanding what specific modules, classes, and functions did, and
+ from syntax errors that could have been avoided by a checker.
+- We need to practice quickly putting together missions in order to be ready to
+ adapt as situations and capabilities change on the day.
+ - This could be helped by improving our knowledge of prebuilt, generalized
+ functions that handle more complex behaviors. (Align in front of vision
+ target, move until target is seen, orbit position, etc...)
+- We should be able to write and test code without the sub being on.
+ - Multiple times during the competition we had 5-10 minutes waiting to get
+ in to the water, and that time ended up being dead time because we weren't
+ confident that we could move our code on to the sub once it was tethered.
+ - Not implementing a gazebo sim exacerbated these issues, as we couldn't do
+ even basic sanity checks until the sub was hooked up.
+ - We need to come up with a way to move code from the developer's computer
+ to the sub's computer that hopefully prevents mistakes when migrating.
+- Everyone working on the sub should be running the same version of the sub's
+ current OS if at all possible. This lowers the amount of churn and multiple
+ configurations that we need to keep a working knowledge of, and makes using
+ tools like `ROS_MASTER_URI` forwarding quicker and easier.
diff --git a/docs/subjugator/lessons23.md b/docs/subjugator/lessons23.md
new file mode 100644
index 0000000..815f047
--- /dev/null
+++ b/docs/subjugator/lessons23.md
@@ -0,0 +1,13 @@
+# Lessons from RoboSub 2023
+
+Paraphrasing Dan Frank, “it's clear that if we had made all these mistakes back in Gainesville, we could have been in way better shape for the competition”.
+
+* **Make a plan and be familiar with the sub** - We should create a solid checklist that spells out all the basic stuff we need to nail before we leave. This should cover nailing down sub moves commands, getting familiar with the missions we already have written, testing those missions in the pool, and making sure our kill system is on point and integrates well with our software. Having a game plan for finals that's solid and picking out a reliable run that can get enough points to really boost our chances is really important. Let's not leave our presentation prep for the last minute – we need to make the presentation and practice at least a week before the competition hits. We should have deadlines for all of these.
+
+* **Make a plan and be familiar with the sub** - We need to have a Plan B when someone can't make it or falls sick. At least 2-3 people need to be able to rock the sub operation, change and charge batteries, replace mechanical things, etc. Roles in the team need to be crystal clear during the competition.
+
+* **Track issues and maintenance of parts** - We should track intermitten issues; investigate them, and deal with them, before leaving. The issues showed up every now and then, but we brushed them off thinking they’ll go away. They should've been solved earlier. Also we need a proper log of when we're swapping out parts or using them. That way, we know when it's time for replacements. We only made the move of MacArtney connector switch after stumbling on a Slack conversation from 2019. Having a grip on the tether's age would've helped sort things out sooner.
+
+* **Easier debugging and Sub Status** - When hardware kills don't unkill after rebooting and sticking the kill wand back in, we should've cracked open those CAN messages to see what was going wrong. Having all this info on a screen or sent to our computers would've made life simpler. About lights and screens, having status symbols or messages on screens for errors or warnings from each board would make debugging easier. Same goes for side lights on the sub – they'd be useful for the electrical and softwar.
+
+* **Document** - Since hardware takes more effort than firmware, we could try to make it easier to write working prototype firmware to have more time for making hardware. We currently have MIL written drivers, but they have inconsistent documentation and are confusing for some members to use (especially the ones for CAN).
diff --git a/docs/subjugator/navtube.rst b/docs/subjugator/navtube.rst
new file mode 100644
index 0000000..caf58ad
--- /dev/null
+++ b/docs/subjugator/navtube.rst
@@ -0,0 +1,97 @@
+========
+Nav Tube
+========
+
+One of the major components of SubjuGator 8 is the navigation (nav tube). This pressure vessel is located right below the main pressure vessel and contains all of our navigation sensors and equipment. The navigation computer located inside the vessel allows access to the data from these components through a direct ethernet connection.
+
+.. warning::
+
+ This system was originally used on SubjuGator 7 and it was ported over with little to no changes in hardware. This does mean that the system will need a major overhaul for continued use of SubjuGator 8.
+
+Navigation Computer
+===================
+
+The navigation computer consists of a Gumstix Overo Computer-on-Module that mounts to a carrier board. The carrier board contains headers for the Teledyne Dopper Velocity Logger (DVL) connector board, Analog Devices Inertial Measurement Unit (IMU), and the pressure sensor. At one point, the navigation computer was also connected to a GPS antenna.
+.. warning::
+
+ No documentation or PCB design files exist for the navigation computer carrier board and there are no more functioning spare boards. Additionally, only the newer GumStix Overo COM boards are available to purchase (with a lead time of roughly 1 year) which may not be compatible with the current system. Be very careful when working inside of the navigation tube.
+
+Troubleshooting The Nav Tube Connection
+---------------------------------------
+
+If you cannot ping the Navigation Computer (192.168.37.61), please ensure (in the following order) that:
+
+* You are pinging 192.168.37.61.
+* The ethernet subconn cable has been connected between both pressure vessels.
+* You restart the sub at least once.
+* That the proper ethernet interface is configured in /etc/netplan YAML file. You may need to check ifconfig for the 'enpXs0' interface (where X is a whole number) if you have unplugged and replugged anything in the sub recently (especially the graphics card). Make sure to test the netplan with ``sudo netplan try`` so that you don't get locked out of the sub because of a bad configuration!
+* The ethernet cables are properly connected inside the main pressure vessel.
+* The ethernet cables and other cables are properly connected inside the Nav tube.
+* The navigation computer is receiving power AND is turned on (green AND blue light on the GumStix). Make sure to be extra careful and vigilent when opening and handling the navigation computer.
+
+ADIS16400/16405-BMLZ IMU & Magnetometer
+===========================================
+
+The `ADIS16400-BMLZ `_ / `ADIS16405-BMLZ `_ is the device responsible for tracking our position and orientation in the water. Currently, there is an ADIS16400 IMU in the sub, but it previously used an ADIS16405.
+
+.. warning::
+
+ These components are obsolete! It may be difficult to find replacement parts in the future if SubjuGator 8 will see continued use...
+
+Calibrating the Magnetometer
+----------------------------
+
+The magnetometer inside of the ADIS16400/16405 measures the strength of the magnetic field at the orientation it faces. We use this data in conjunction with the IMU's gyroscopes and accelerometers to determine the orientation of the sub in the water. The process of calibrating the magnetometer is called magnetic hardsoft compensation and essentially changes how we bias the data it gives us.
+
+.. note::
+
+ Calibrating the magnetometer must be done in a pool.
+
+To calibrate the magnetometer you must first collect magnetometer data (``/imu/mag_raw``) to use for the calibration script. This can be done through the following:
+
+.. code-block:: bash
+
+ $ roslaunch subjugator_launch sub8.launch
+
+or if you prefer to not launch the entire sub:
+
+.. code-block:: bash
+
+ $ roslaunch subjugator_launch nav_box.launch imu:=true
+
+Then, in a separate terminal window, navigate to a known directory start recording the rosbag by typing:
+
+.. code-block:: bash
+
+ $ rosbag record -O .bag /imu/mag_raw
+
+where is a substitute for whatever name you want to give to your bag (I recommend something memorable, like Frank or Penelope). This will record the bag data in the directory that the terminal window is in.
+
+When you have started recording the bag, have members who are in the water rotate the sub. Only the sub should move, not the members holding onto the sub. The calibration can be done in any order, but you must complete a full roll, pitch, and yaw rotation plus have a few minutes of data with all three occurring at the same time. Once you are done collecting data, kill the recording window using ``ctrl+c``.
+
+Next, we must run the calibration script with our data. This script is located in ``SubjuGator/drivers/magnetic_compensation/sub8_magnetic_hardsoft_compensation/scripts``. Type the following:
+
+.. code-block:: bash
+
+ $ ./generate_config
+
+note that this is a python script, so
+
+.. code-block:: bash
+
+ $ python3 generate_config
+
+is also valid.
+
+.. note::
+
+ If the script fails because of the ``fit_ellipsoid`` method and the points on the first figure are colinear or nearly colinear you may not have collected thorough enough data. The alternate possibility is a malfunctioning magnetometer.
+
+The output of the script should be a 3x3 matrix labeled ``scale`` and a length 3 vector labeled ``shift``. These values go into the ``scale`` and ``shift`` values located inside of ``subjugator_launch/launch/subsystems/nav_box.launch``.
+
+After running ``cm``, you will have (hopefully) successfully calibrated the magnetometer. Make sure to test the sub after calibration to see if the new configuration values are an improvement over the old ones.
+
+Important Links and Datasheets
+==============================
+
+- `ADIS16400/ADIS16405 Datasheet `_
diff --git a/docs/subjugator/pid.rst b/docs/subjugator/pid.rst
new file mode 100644
index 0000000..c2feeae
--- /dev/null
+++ b/docs/subjugator/pid.rst
@@ -0,0 +1,26 @@
+PID Controller
+--------------
+
+SubjuGator 8 uses 6 PID controllers for its 6 degrees of freedom (x, y, z, roll, pitch, yaw). The gain for these PID controllers can be adjusted in ``adaptive_controller.yaml`` found in the ``subjugator_launch/config`` directory. Since the weight of the sub shifts with each component modified, the PID controller values have to be adjusted from time to time. There are two approaches to adjust PID values in the water:
+
+1. Have someone with experience in tuning PID controllers swim with the sub and use the sub's response to movement commands to adjust the gains.
+2. Eliminate the error in each axis by adjusting the gains and evaluating the RMS error in each axis after sending the same movement commands.
+
+PID Controller Tuning Tips
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* The learning gains (``ki`` and ``kd``) provide very little input to the wrenches applied to the sub, so it is better to treat it as a PD controller to start with. You can disable the learning gains using ``use_learned: false``.
+* While you are tuning the PID values, keep a history of the values you have tried for further analysis during and after testing. You can use ``scp`` for this, but it may just be easier to take a screenshot or a photo. You can also take videos of the sub from the side of the pool to reference later.
+
+PID Debugging Data Collection
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: bash
+
+ $ roslaunch subjugator_launch bag_debugging_controller.launch prefix_name:="my_prefix"
+
+This launch file records a bag file containing adaptive controller ``pose_error``, ``twist_error``, ``adaptation``, ``dist``, and ``drag`` data along with ``wrench``, ``trajectory``, ``odom``, ``imu/data_raw``, and ``dvl/range`` data. This data is useful in determining if the PID values are getting better or worse using simulations. The resulting bag file will be located in ``gnc/subjugator_controller/debug_bags/``. This launch file was written by Andres Pulido.
+
+.. warning::
+
+ This launch file needs the sub launch file (``sub8.launch``) running in order to function properly.
diff --git a/docs/subjugator/reference.rst b/docs/subjugator/reference.rst
new file mode 100644
index 0000000..66a3cea
--- /dev/null
+++ b/docs/subjugator/reference.rst
@@ -0,0 +1,380 @@
+SubjuGator Software Reference
+=============================
+
+Below is the reference documentation for the code on our submarine robot, SubjuGator.
+The following systems are relevant only to this robot, and no other robot. However,
+hyperlinks may link to systems on other robots.
+
+Messages
+--------
+
+Thrust
+^^^^^^
+.. attributetable:: subjugator_msgs.msg.Thrust
+
+.. class:: subjugator_msgs.msg.Thrust
+
+ Message type indicating commands for each thruster.
+
+ .. attribute:: thruster_commands
+
+ The commands for the thrusters.
+
+ :type: List[:class:`~subjugator_msgs.msg.ThrusterCmd`]
+
+ThrusterCmd
+^^^^^^^^^^^
+.. attributetable:: subjugator_msgs.msg.ThrusterCmd
+
+.. class:: subjugator_msgs.msg.ThrusterCmd
+
+ A command for a specific thruster.
+
+ .. attribute:: thrust
+
+ The amount of thrust for the specific thruster.
+
+ :type: :class:`float`
+
+ .. attribute:: name
+
+ The name of the thruster.
+
+ :type: :class:`str`
+
+Services
+--------
+
+SetValve
+^^^^^^^^
+.. attributetable:: sub_actuator_board.srv.SetValveRequest
+
+.. class:: sub_actuator_board.srv.SetValveRequest
+
+ The request class for the ``sub_actuator_board/SetValve`` service.
+
+ .. attribute:: actuator
+
+ Which actuator on the sub the message references.
+
+ :type: int
+
+ .. attribute:: opened
+
+ Whether the valve should be opened or closed.
+
+ :type: bool
+
+.. attributetable:: sub_actuator_board.srv.SetValveResponse
+
+.. class:: sub_actuator_board.srv.SetValveResponse
+
+ The response class for the ``sub_actuator_board/SetValve`` service.
+
+ .. attribute:: success
+
+ The success of the operation.
+
+ :type: bool
+
+ .. attribute:: message
+
+ If an error occurred, a message depicting the error.
+
+ :type: bool
+
+Actuator Board
+--------------
+
+ActuatorBoard
+^^^^^^^^^^^^^
+.. attributetable:: sub_actuator_board.ActuatorBoard
+
+.. autoclass:: sub_actuator_board.ActuatorBoard
+ :members:
+
+ActuatorBoardSimulation
+^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: sub_actuator_board.ActuatorBoardSimulation
+
+.. autoclass:: sub_actuator_board.ActuatorBoardSimulation
+ :members:
+
+ActuatorPacketId
+^^^^^^^^^^^^^^^^
+.. autoclass:: sub_actuator_board.ActuatorPacketId
+ :members:
+
+ActuatorSetPacket
+^^^^^^^^^^^^^^^^^
+.. attributetable:: sub_actuator_board.ActuatorSetPacket
+
+.. autoclass:: sub_actuator_board.ActuatorSetPacket
+ :members:
+
+ActuatorPollRequestPacket
+^^^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: sub_actuator_board.ActuatorPollRequestPacket
+
+.. autoclass:: sub_actuator_board.ActuatorPollRequestPacket
+ :members:
+
+ActuatorPollResponsePacket
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: sub_actuator_board.ActuatorPollResponsePacket
+
+.. autoclass:: sub_actuator_board.ActuatorPollResponsePacket
+ :members:
+
+Sub8 Thrust and Kill Board
+--------------------------
+
+ThrusterAndKillBoard
+^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: sub8_thrust_and_kill_board.ThrusterAndKillBoard
+
+.. autoclass:: sub8_thrust_and_kill_board.ThrusterAndKillBoard
+ :members:
+
+KillMessage
+^^^^^^^^^^^
+.. attributetable:: sub8_thrust_and_kill_board.KillMessage
+
+.. autoclass:: sub8_thrust_and_kill_board.KillMessage
+ :members:
+
+HeartbeatMessage
+^^^^^^^^^^^^^^^^
+.. attributetable:: sub8_thrust_and_kill_board.HeartbeatMessage
+
+.. autoclass:: sub8_thrust_and_kill_board.HeartbeatMessage
+ :members:
+
+ThrustPacket
+^^^^^^^^^^^^
+.. attributetable:: sub8_thrust_and_kill_board.ThrustPacket
+
+.. autoclass:: sub8_thrust_and_kill_board.ThrustPacket
+ :members:
+
+ThrusterAndKillBoardSimulation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: sub8_thrust_and_kill_board.ThrusterAndKillBoardSimulation
+
+.. autoclass:: sub8_thrust_and_kill_board.ThrusterAndKillBoardSimulation
+ :members:
+
+Thruster
+^^^^^^^^
+.. attributetable:: sub8_thrust_and_kill_board.Thruster
+
+.. autoclass:: sub8_thrust_and_kill_board.Thruster
+ :members:
+
+Sub9 Thrust and Kill Board
+--------------------------
+
+HeartbeatSetPacket
+^^^^^^^^^^^^^^^^^^
+.. attributetable:: sub9_thrust_and_kill_board.HeartbeatSetPacket
+
+.. autoclass:: sub9_thrust_and_kill_board.HeartbeatSetPacket
+ :members:
+
+HeartbeatReceivePacket
+^^^^^^^^^^^^^^^^^^^^^^
+.. attributetable:: sub9_thrust_and_kill_board.HeartbeatReceivePacket
+
+.. autoclass:: sub9_thrust_and_kill_board.HeartbeatReceivePacket
+ :members:
+
+ThrusterId
+^^^^^^^^^^
+.. attributetable:: sub9_thrust_and_kill_board.ThrusterId
+
+.. autoclass:: sub9_thrust_and_kill_board.ThrusterId
+ :members:
+
+ThrustSetPacket
+^^^^^^^^^^^^^^^
+.. attributetable:: sub9_thrust_and_kill_board.ThrustSetPacket
+
+.. autoclass:: sub9_thrust_and_kill_board.ThrustSetPacket
+ :members:
+
+KillStatus
+^^^^^^^^^^
+.. attributetable:: sub9_thrust_and_kill_board.KillStatus
+
+.. autoclass:: sub9_thrust_and_kill_board.KillStatus
+ :members:
+
+KillSetPacket
+^^^^^^^^^^^^^
+.. attributetable:: sub9_thrust_and_kill_board.KillSetPacket
+
+.. autoclass:: sub9_thrust_and_kill_board.KillSetPacket
+ :members:
+
+KillReceivePacket
+^^^^^^^^^^^^^^^^^
+.. attributetable:: sub9_thrust_and_kill_board.KillReceivePacket
+
+.. autoclass:: sub9_thrust_and_kill_board.KillReceivePacket
+ :members:
+
+Object Detection
+----------------
+
+SubjuGatorBuoyDetector
+^^^^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: SubjuGatorBuoyDetector
+
+.. doxygenclass:: SubjuGatorBuoyDetector
+
+SubjuGatorStartGateDetector
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: SubjuGatorStartGateDetector
+
+.. doxygenclass:: SubjuGatorStartGateDetector
+
+SubjuGatorTorpedoBoardDetector
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: SubjuGatorTorpedoBoardDetector
+
+.. doxygenclass:: SubjuGatorTorpedoBoardDetector
+
+TorpedoBoardReprojectionCost
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: TorpedoBoardReprojectionCost
+
+.. doxygenclass:: TorpedoBoardReprojectionCost
+
+Computer Vision
+---------------
+
+Utility Functions
+^^^^^^^^^^^^^^^^^
+.. doxygenfunction:: sub::voxel_filter
+
+.. doxygenfunction:: sub::statistical_outlier_filter
+
+.. doxygenfunction:: sub::closest_point_index_rayOMP
+
+.. doxygenfunction:: sub::closest_point_index_ray
+
+.. doxygenfunction:: sub::closest_point_ray
+
+.. doxygenfunction:: sub::project_uv_to_cloud_index
+
+.. doxygenfunction:: sub::project_uv_to_cloud
+
+.. doxygenfunction:: sub::point_to_eigen
+
+.. doxygenfunction:: sub::compute_normals
+
+.. doxygenfunction:: sub::segment_rgb_region_growing
+
+.. doxygenfunction:: sub::segment_box
+
+.. doxygenfunction:: anisotropic_diffusion
+
+.. doxygenfunction:: best_plane_from_combination
+
+.. doxygenfunction:: calc_plane_coeffs
+
+.. doxygenfunction:: point_to_plane_distance
+
+Type Definitions
+^^^^^^^^^^^^^^^^
+.. doxygentypedef:: ROSCameraStream_Vec3
+
+.. doxygentypedef:: PointNT
+
+.. doxygentypedef:: PointCloudNT
+
+.. doxygentypedef:: PointXYZT
+
+.. doxygentypedef:: PointCloudT
+
+.. doxygentypedef:: ColorHandlerT
+
+SubjuGatorObjectFinder
+^^^^^^^^^^^^^^^^^^^^^^
+.. cppattributetable:: SubjuGatorObjectFinder
+
+.. doxygenclass:: SubjuGatorObjectFinder
+
+StereoBase
+^^^^^^^^^^
+.. cppattributetable:: StereoBase
+
+.. doxygenclass:: StereoBase
+
+RvizVisualizer
+^^^^^^^^^^^^^^
+.. cppattributetable:: sub::RvizVisualizer
+
+.. doxygenclass:: sub::RvizVisualizer
+
+OccGridUtils
+^^^^^^^^^^^^
+.. attributetable:: subjugator_vision_tools.OccGridUtils
+
+.. autoclass:: subjugator_vision_tools.OccGridUtils
+ :members:
+
+Searcher
+^^^^^^^^
+.. attributetable:: subjugator_vision_tools.Searcher
+
+.. autoclass:: subjugator_vision_tools.Searcher
+ :members:
+
+Classification
+^^^^^^^^^^^^^^
+.. cppattributetable:: Classification
+
+.. doxygenclass:: Classification
+
+OGridGen
+^^^^^^^^
+.. cppattributetable:: OGridGen
+
+.. doxygenclass:: OGridGen
+
+Simulation
+----------
+BagManager
+^^^^^^^^^^
+.. attributetable:: subjugator_gazebo_tools.BagManager
+
+.. autoclass:: subjugator_gazebo_tools.BagManager
+ :members:
+
+6DOF Controller
+---------------
+Controller
+^^^^^^^^^^
+.. attributetable:: rise_6dof.Controller
+
+.. autoclass:: rise_6dof.Controller
+ :members:
+
+Dynamics
+--------
+SubjuGatorDynamics
+^^^^^^^^^^^^^^^^^^
+.. attributetable:: subjugator_system_id.SubjuGatorDynamics
+
+.. autoclass:: subjugator_system_id.SubjuGatorDynamics
+ :members:
+
+Missions
+--------
+PoseEditor
+^^^^^^^^^^
+.. attributetable:: subjugator_missions.PoseEditor
+
+.. autoclass:: subjugator_missions.PoseEditor
+ :members:
diff --git a/docs/subjugator/robosub.md b/docs/subjugator/robosub.md
new file mode 100644
index 0000000..c59eb61
--- /dev/null
+++ b/docs/subjugator/robosub.md
@@ -0,0 +1,15 @@
+# RoboSub competition
+
+## Overview
+The fundamental goal of the RoboSub competition is for an Autonomous Underwater Vehicle
+(AUV) to demonstrate its autonomy by completing underwater tasks, with a new theme each year.
+The theme does not usually impact what the tasks themselves. There are usually tasks that
+involve passing through a gate, recognizing images and shooting torpedoes at targets,
+recognizing downfacing objects and dropping a marker, listening and localizing sound pingers
+and navigate towards them, and surface in a specified area.
+
+## Lessons Learned
+
+If you're working on the sub and/or you are planning on going to competition it is
+**strongly recommended to read the [lessons learned in 2019](/subjugator/lessons19.md)
+and the [lessons learned in 2022](/subjugator/lessons22.md)**.
diff --git a/docs/subjugator/simulating.rst b/docs/subjugator/simulating.rst
new file mode 100644
index 0000000..e386b81
--- /dev/null
+++ b/docs/subjugator/simulating.rst
@@ -0,0 +1,86 @@
+Simulating SubjuGator
+---------------------
+
+Launch Gazebo Server
+~~~~~~~~~~~~~~~~~~~~
+
+In one panel, run:
+
+.. code-block:: bash
+
+ $ roslaunch subjugator_launch gazebo.launch
+
+This will launch the server side of the gazebo simulator. The gazebo server (a.k.a. ``gzserver``)
+is the half of the simulator that will do all the heavy lifting in terms of simulating physics,
+running stock / custom plugins (of which we have many), and tying into ROS.
+
+Run Gazebo Client
+~~~~~~~~~~~~~~~~~
+
+Gazebo also has GUI visualization component named Gazebo Client (a.k.a ``gzclient``).
+This half of the simulator really only does image rendering of the simulated environment.
+
+.. warning::
+
+ Simulated cameras are rendered in `gzserver`.
+
+We have a custom `alias `__ setup
+to run the gazebogui with special parameters:
+
+.. code-block:: bash
+
+ $ gazebogui
+
+This will show you ground truth of the simulated environment. However, when debugging robot behavior, it is usually more usful to have an idea of exactly what the robot knows, which is why there is also Rviz.
+
+Run RVIZ
+~~~~~~~~
+
+You can visualize what the robot knows by running the sub visualization alias in
+a new terminal:
+
+.. code-block:: bash
+
+ $ subviz
+
+``subviz`` is an `alias `__
+which launches `RVIZ `__ with a configuration
+for SubjuGator. Generally speaking, this will show what information is available
+to the robot.
+
+Clear the Kill
+~~~~~~~~~~~~~~
+
+Whenever SubjuGator is initialized, it is a state called "kill" for
+safety. While in the kill state, the sub will not actuate in any way so
+it is safe for people the physically handle it. The sub must be put into
+a state of "unkill" to actually do anything. To unkill the sub, go to a
+new panel and run:
+
+.. code-block:: bash
+
+ $ amonitor kill
+
+and then hold ``Shift + C`` until the terminal turns green.
+
+To initiate a software kill, press the space bar into the same terminal where
+you unkilled.
+
+Give a move command
+~~~~~~~~~~~~~~~~~~~
+
+Give SubjuGator a move command with ``submove``:
+
+.. code-block:: bash
+
+ $ submove forward 5m
+
+The sub should move forward by 5 meters.
+
+See the current odometry
+~~~~~~~~~~~~~~~~~~~~~~~~
+Try streaming the content of a rostopic in a new panel by running:
+
+.. code-block:: bash
+
+ $ rostopic echo /odom
diff --git a/docs/subjugator/sub8_electrical_diagram.png b/docs/subjugator/sub8_electrical_diagram.png
new file mode 100644
index 0000000..d4f3944
Binary files /dev/null and b/docs/subjugator/sub8_electrical_diagram.png differ
diff --git a/docs/subjugator/testingprocedures.md b/docs/subjugator/testingprocedures.md
new file mode 100644
index 0000000..b1a6d4d
--- /dev/null
+++ b/docs/subjugator/testingprocedures.md
@@ -0,0 +1,62 @@
+# SubjuGator Testing Procedures
+
+## Before leaving
+
+For best results, packing should be done at least one day before a testing session. This
+
+### Packing list
+* Power Strip
+* Table
+* Extension Cord
+* Battery Box
+* Battery charger
+* Tether
+* Network Box
+* Ethernet Cables (2 + #of devs)
+* Laptops
+* 7/16 wrench
+* 5/32 Allen Key
+* Duct tape and scissor
+* Buoyancy foams for the sub
+* Pliers
+* Flat-head screwdriver
+* Kill wand
+* Multimeter
+* Goggles / Snorkeling Tube
+* Pool noddles
+* Dive fins
+* O'ring grease (Molykote 55)
+* Cable grease (Molykote 44)
+* Hot glue gun
+* Hot glue sticks
+* Large and small zip ties
+* clippers
+* Towel(s)
+* [Sunscreen](https://www.youtube.com/watch?v=sTJ7AzBIJoI)
+* Tent (If going to Graham Pool or Florida Pool)
+* Chairs (If going to Graham Pool)
+
+### Software/Electrical Checklist
+* Update (`git pull`) and build (`cm`) code.
+* Verify all sensors output data.
+* Verify that the correct thrusters spin given the appropriate command.
+* Verify kill (soft and hard).
+* Grease all electrical connectors appropriately.
+
+## At testing site
+* Get wall power to powerstrip.
+* Setup and connect to Network Box.
+* Roll tether and connect it to network box. **(DO NOT USE POE)**
+* Connect Sub to to tether. **(NOT POE)**
+* Connect battery alarm, power on sub.
+* SSH into sub.
+* Start tmux, write code.
+* Grease O-rings with Molykote 55 every time a pressure vessel is closed.
+* * **ENSURE THAT THE RED PRESSURE RELIEF CAP ON THE BATTERY TUBE HAS BEEN SCREWED IN PLACE AFTER CHANGING BATTERIES**
+* Person getting into the pool must do backflip.
+* Deploy sub. (check for bubbles, make sure buoyancy is correct).
+* Verify odometry.
+
+### Troubleshooting
+
+- :ref:`Troubleshooting The Nav Tube Connection`
diff --git a/docs/subjugator/watercooling.rst b/docs/subjugator/watercooling.rst
new file mode 100644
index 0000000..5344e68
--- /dev/null
+++ b/docs/subjugator/watercooling.rst
@@ -0,0 +1,70 @@
+============
+Watercooling
+============
+
+SubjuGator 8's hardware requires a watercooling loop for the CPU, graphics card, and ESCs.
+
+Filling the Water cooling Loop
+==============================
+
+.. note::
+
+ Filling the water cooling loop requires at least 2 people.
+
+Materials
+---------
+
+* Sub Shore Power Supply
+* Sub battery tube cover
+* Sub battery cables
+* Large Funnel
+* Small Funnel
+* Stool or Chair
+* Deionized Water w/ Biocide
+* Vacuum Pump
+* Extra water cooling connectors and tubing
+* Water cooling reservoir
+* Bucket
+
+.. note::
+
+ While deionized water with biocide is preferred for longevity, distilled water will work fine. You should not use purified water. Bonus points if the water is dyed orange :)
+
+No-Pump Procedure
+-----------------
+
+These steps should be taken when there is no external pump to help with the filling process.
+
+.. warning::
+
+ Exercise caution during steps 8 and 9 as the sub will be powered on with a water hazard nearby.
+
+#. Move the main vessel onto the wooden platform and down to the floor.
+#. Set up the environment as shown in the picture below.
+#. Gravity feed the system by filling the reservoir with water and letting the bubbles come out naturally. Move on when no more bubbles come out.
+#. Empty the reservoir until the water is below the "stove pipe" (metal tube inside the reservoir).
+#. Blow into the tube exposed to air to force the water into the loop while extracting the air inside of the loop. Make sure to fill the reservoir until the water is below the "stove pipe" when there is an air gap inside of the water inlet tube. Move on when you cannot remove any more bubbles.
+#. Attach the vacuum pump to the tube exposed to air and pump until the pressure reaches around 10 PSI. Pinch the outlet tube and break the vacuum to allow water to fill the low pressure spots. Repeat this step until at least a decent amount of water makes it past the pump.
+#. With water at the ready, connect the sub to shore power and fill the reservoir with water (you do not have to worry about the "stove pipe").
+#. Wiggle the sub around while the pump is running to extract any trapped bubbles.
+
+Emptying the Water Cooling Loop
+===============================
+
+The water cooling loop should be emptied before the sub is shipped anywhere. Emptying the water cooling loop is easier than filling it up.
+
+.. note::
+
+ Emptying the water cooling loop requires at least 2 people.
+
+Materials
+---------
+
+* Vacuum pump
+* Extra water cooling connectors and tubing
+* Water cooling reservoir
+* Bucket
+
+
+Procedure
+---------
diff --git a/docs/uf-mil-pygments/setup.py b/docs/uf-mil-pygments/setup.py
new file mode 100644
index 0000000..75a4f23
--- /dev/null
+++ b/docs/uf-mil-pygments/setup.py
@@ -0,0 +1,8 @@
+from setuptools import setup
+
+setup(
+ name="uf-mil-pygments",
+ version="1",
+ py_modules=["uf_mil_pygments"],
+ entry_points={"pygments.styles": "mil=uf_mil_pygments:MILStyle"},
+)
diff --git a/docs/uf-mil-pygments/uf_mil_pygments.py b/docs/uf-mil-pygments/uf_mil_pygments.py
new file mode 100644
index 0000000..045f65e
--- /dev/null
+++ b/docs/uf-mil-pygments/uf_mil_pygments.py
@@ -0,0 +1,68 @@
+"""
+Pygments style for the UF-MIL docs.
+"""
+
+from pygments.style import Style
+from pygments.token import (
+ Comment,
+ Error,
+ Generic,
+ Keyword,
+ Name,
+ Number,
+ Operator,
+ String,
+ Whitespace,
+)
+
+alachua = "#F2A900"
+gator_orange = "#FA4616"
+
+
+class MILStyle(Style):
+ background_color = "#f0f0f0"
+ default_style = ""
+
+ styles = {
+ Whitespace: "#bbbbbb",
+ Comment: "italic #3D7B7B",
+ Comment.Preproc: "noitalic #9C6500",
+ # Keyword: "bold #AA22FF",
+ Keyword: f"bold {gator_orange}",
+ Keyword.Pseudo: "nobold",
+ Keyword.Type: "nobold #B00040",
+ Operator: "#666666",
+ Operator.Word: "bold #AA22FF",
+ Name.Builtin: gator_orange,
+ Name.Function: alachua,
+ Name.Class: "bold #0000FF",
+ Name.Namespace: "bold #0000FF",
+ Name.Exception: "bold #CB3F38",
+ Name.Variable: "#19177C",
+ Name.Constant: "#880000",
+ Name.Label: "#767600",
+ Name.Entity: "bold #717171",
+ Name.Attribute: "#687822",
+ Name.Tag: f"bold {gator_orange}",
+ Name.Decorator: "#AA22FF",
+ String: "#BA2121",
+ String.Doc: "italic",
+ String.Interpol: "bold #A45A77",
+ String.Escape: "bold #AA5D1F",
+ String.Regex: "#A45A77",
+ # String.Symbol: "#B8860B",
+ String.Symbol: "#19177C",
+ String.Other: gator_orange,
+ Number: "#666666",
+ Generic.Heading: "bold #000080",
+ Generic.Subheading: "bold #800080",
+ Generic.Deleted: "#A00000",
+ Generic.Inserted: "#008400",
+ Generic.Error: "#E40000",
+ Generic.Emph: "italic",
+ Generic.Strong: "bold",
+ Generic.Prompt: "bold #000080",
+ Generic.Output: "#717171",
+ Generic.Traceback: "#04D",
+ Error: "border:#FF0000",
+ }
diff --git a/docs/welcome.md b/docs/welcome.md
new file mode 100644
index 0000000..1616b30
--- /dev/null
+++ b/docs/welcome.md
@@ -0,0 +1,70 @@
+# Welcome to MIL!
+If you have reached this page, you likely want to get started working in MIL.
+We're quite excited to have you on the team! MIL has been committed to designing
+high-quality robots for several decades at the University of Florida, and we're excited
+that you're interested in becoming part of that history.
+
+Our team has world championship tournaments across the globe five times, and
+we've placed amongst the top three teams fifteen times. You can help us to win
+our sixth championship!
+
+## What is MIL?
+From our website:
+
+> _The Machine Intelligence Laboratory (MIL) provides a synergistic environment dedicated to the study and development of intelligent, autonomous robots. The faculty and students associated with the laboratory conduct research in the theory and realization of machine intelligence covering topics such as machine learning, real-time computer vision, statistical modeling, robot kinematics, autonomous vehicles, teleoperation and human interfaces, robot and nonlinear control, computational intelligence, neural networks, and general robotics. Applications of MIL research include autonomous underwater vehicles (AUVs), autonomous water surface vehicles (ASVs), autonomous land vehicles, autonomous air vehicles (AAVs including quadcopters and micro air vehicles, MAVs) , swarm robots, humanoid robots, and autonomous household robots."_
+>
+> -- [https://mil.ufl.edu](https://mil.ufl.edu)
+
+That indeed is a great insight into some of the technologies used in our lab. The
+technologies used in MIL are generally split across three different teams, the Mechanical
+Team, Electrical Team, and Software Team. These teams typically develop individual systems
+by themselves and then share the results with the other teams. This allows for the desired
+synergy when constructing world-class robots.
+
+You can join any of these three teams (or multiple!). Each team has one or more leaders
+who help to coordinate the responsibilities of the team.
+
+## Culture of MIL
+MIL does things differently than many other labs or student organizations. Our lab
+aims to be very inclusive, in order to find the best ideas from the student body.
+There is no application process to join, and members choose the amount to which they
+want to get involved. We hope that this flexibility inspires innovation across and
+between the teams.
+
+Alumni are also a large part of MIL (if you come in frequently, you will get to meet
+some of them!). Alumni from MIL are scattered all throughout the world, some of whom
+have founded their own companies, or joined notable technical companies. We are
+gracious that our alumni continue to rigorously support MIL.
+
+Outside of the technical aspect of MIL, we are a strong community. Members will
+frequently hang out together on the weekends, be in the lab late at night, go on
+"food trains" (a bunch of MILers heading to a restaurant for a bite to eat), and
+embark on trips across the world. We'd love to have you become a MILer, too!
+
+For more information, read about our [culture](/culture).
+
+## Join Slack and say hello!
+We use Slack as our primary communication platform. On Slack, you can communicate
+with members of your team, and members of other teams. This is where we can stay
+up to date with each other about the progress of the robots.
+
+Our Slack workspace can be found at [uf-mil.slack.com](https://uf-mil.slack.com).
+Ask someone in MIL to invite you, or email [ems@ufl.edu](mailto:ems@ufl.edu) (the
+lab director, Dr. Eric Schwartz).
+
+## Jump in!
+Well - we hope that was a great introduction to what we do! We hope that you're feeling
+excited to jump right in - if not, no worries, we're here to help you!
+
+:::{note}
+Our first meeting of the Fall 2021 semester was recorded. The meeting includes a brief
+overview of MIL (similar to the above) and a tour of the lab. We encourage you to
+watch, but it's not required to get started.
+
+You can find the recording [here](https://mil.ufl.edu/videos/MIL_Kick_Off_Fall_2021.mp4).
+:::
+
+The next step is to look into joining a specific team:
+- Click here to embark on the [Mechanical Team onboarding](/mechanical/onboarding).
+- Click here to embark on the [Electrical Team](/electrical/onboarding).
+- Click here to embark on the [Software Team](/software/getting_started).
diff --git a/scripts/install.sh b/scripts/install.sh
index 878667a..363b9e3 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -239,7 +239,7 @@ sudo rosdep update
# will bypass this check.
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
if [[ $SCRIPT_DIR != "$HOME/mil2/scripts" && -z ${ALLOW_NONSTANDARD_DIR:-} ]]; then
- echo "${Red}Error: This script must be located in ~/mil2/scripts/install.sh. Please review the installation guide and try again.${Res}"
+ echo "${Red}Error: This script must be located in ~/mil2/scripts/install.sh. You do not need to nest it in catkin_ws/src, as that is only for ROS2. Please review the installation guide and try again.${Res}"
exit 1
fi
# COLCON_SOURCE_DIR="$HOME/src"