From 88d78bab4b747fc976ac97231407408ca8d2329f Mon Sep 17 00:00:00 2001
From: ci-bot physics_engine_node
Welcome to the UBC Sailbot software team docs
Looking to get started with running the Sailbot codebase? Start by setting up the Sailbot Workspace:
Getting Started
"},{"location":"#what-information-is-on-this-website","title":"What information is on this website?","text":"Information on our current project is contained on this website. In particular, information on each of our major software projects are provided in detail.
Current Project Overview
References to the software tools that we use are also provided on this website. This includes basic information on these tools, how we use these tools on UBC Sailbot, and external links to helpful references and tutorials.
Software Team References
"},{"location":"#who-is-this-website-for","title":"Who is this website for?","text":"The docs site is primarily for the members on the UBC Sailbot software team. However, curious members of the public and/or those who are interested in contributing to our open source software would also benefit from this site.
"},{"location":"#prospective-members","title":"Prospective Members","text":"Are you a member of the UBC community? Are you interested in what we do at UBC Sailbot? We are always looking for motivated students to help us tackle the challenge of autonomous sailing. Learn more below!
Software Team Posting
Apply to join UBC Sailbot
"},{"location":"about_us/","title":"About Us","text":"UBC Sailbot is an engineering design team at The University of British Columbia that designs, constructs, and tests autonomous sailboats. We have 3 technical sub-teams: Mechanical, Electrical, and Software.
This repository, sailbot_workspace, contains all the code, infrastructure, and documentation for the project we are currently working on, Polaris.
To learn more about what the UBC Sailbot Software Team does, read our Team Posting. If you are a UBC student interested in joining, you can apply here.
"},{"location":"current/overview/","title":"Current Project Overview","text":"Our current project, Polaris, is an autonomous research vessel capable of collecting oceanic and atmospheric data. With our expertise in autonomous sailing, the goal is to monitor the health of our oceans while collaborating with stakeholders and researchers involved in climate science and oceanography.
The software team is responsible for designing, implementing, and testing the software system of our autonomous sailboats. We work on both low-level and high-level integration, from interfacing with sensors to planning sea routes with pathfinding algorithms.
"},{"location":"current/overview/#dataflow","title":"Dataflow","text":"The software architecture for our next autonomous sailboat is split across two computers: the on board computer on board and the remote server off board. The following paragraphs will follow the flow of data between the software components (bolded) on each computer.
On the remote server, global pathfinding uses the A* pathfinding algorithm to create a sailing path, a list of global waypoints from the current position to destination. Global sailing paths are sent via the Remote Transceiver to the Local Transceiver on the on board computer.
On the on board computer, the CAN Transceiver receives GPS and wind data from their respective sensors. This raw data is filtered before being used in the other software components. Local Pathfinding uses GPS and wind data, as well as the global path and AIS data from the AIS Receiver, to create a local path, a list of local waypoints from the current position to the next global waypoint. The Controller uses wind data and the relative bearing to the local path to adjust the rudder and sails accordingly. The state of the boat and research data we collect is sent via the Local Transceiver to the Remote Transceiver on the remote server.
Back on the remote server, the Website presents the boat state and research data for monitoring and analysis purposes. The Remote Transceiver additionally includes manual overrides such as resetting the boat state and modifying the global path.
As for the communication mediums, the computers communicate via satellite, and components on the on board computer communicate through the Robot Operating System framework, or ROS for short.
For software development purposes, all software components will be able to run and communicate with each other locally. To accomplish this, we will:
In these diagrams, the bubbles represent components of our software system, and the direction of arrows connecting the bubbles represent the flow of data between them. The color of the bubbles denote the sub-team leading their development:
Components that are used in both the production and development environments are darker, while ones that are only used in one are lighter.
Interacting with the diagram
Source code
The source code for Boat Simulator can be found in src/boat_simulator
. Its README has been copied below.
UBC Sailbot's boat simulator for the new project. This repository contains a ROS package boat_simulator
. This README contains only setup and run instructions. Further information on the boat simulator can be found on the software team's docs website.
The boat simulator is meant to be ran inside the Sailbot Workspace development environment. Follow the setup instructions for the Sailbot Workspace here to get started and build all the necessary ROS packages.
"},{"location":"current/boat_simulator/overview/#run","title":"Run","text":"The launch/
folder contains a ROS 2 launch file responsible for starting up the boat simulator. To run the boat simulator standalone, execute the launch file after building the boat_simulator
package:
ros2 launch boat_simulator main_launch.py [OPTIONS]...\n
To see a list of options for simulator configuration, add the -s
flag at the end of the above command.
Run the test
task in the Sailbot Workspace. See here on how to run vscode tasks.
Source code
The source code for Controller can be found in src/controller
. Its README has been copied below.
UBC Sailbot's controller for the new project. This repository contains a ROS package controller
. This README contains only setup and run instructions. Further information on the controller can be found on the software team's docs website.
The controller is meant to be ran inside the Sailbot Workspace development environment. Follow the setup instructions for the Sailbot Workspace here to get started and build all the necessary ROS packages.
"},{"location":"current/controller/overview/#run","title":"Run","text":"The launch/
folder contains a ROS 2 launch file responsible for starting up the controller. To run the controller standalone, execute the launch file after building the controller
package:
ros2 launch controller main_launch.py [OPTIONS]...\n
To see a list of options for configuration, add the -s
flag at the end of the above command.
Run the test
task in the Sailbot Workspace. See here on how to run vscode tasks.
Source code
The source code for Custom Interfaces can be found in src/custom_interfaces
. Its README has been copied below.
UBC Sailbot's custom interfaces ROS package. To add custom_interfaces
to another ROS package, follow the instructions here.
The terminology that we use in this document are the following:
.msg
or .srv
file associated with that interface.ROS messages and services used across many ROS packages in the project.
"},{"location":"current/custom_interfaces/overview/#project-wide-external-interfaces","title":"Project-wide External Interfaces","text":""},{"location":"current/custom_interfaces/overview/#project-wide-internal-interfaces","title":"Project-wide Internal Interfaces","text":"Interface Used In HelperAISShip AISShips HelperBattery Batteries HelperDimension HelperAISShip HelperGenericSensor GenericSensors HelperHeading DesiredHeading, GPS, HelperAISShip HelperLatLon GPS, HelperAISShip, Path HelperROT HelperAISShip HelperSpeed GPS, HelperAISShip, WindSensor"},{"location":"current/custom_interfaces/overview/#boat-simulator-interfaces","title":"Boat Simulator Interfaces","text":"ROS messages and services used in our boat simulator.
"},{"location":"current/custom_interfaces/overview/#boat-simulator-external-interfaces","title":"Boat Simulator External Interfaces","text":"Topic Type Publisher Subscriber(s)mock_kinematics
SimWorldState Simulator Physics Engine Simulator Visualizer"},{"location":"current/custom_interfaces/overview/#boat-simulator-actions","title":"Boat Simulator Actions","text":"Action Client Node Server Node SimRudderActuation Simulator Physics Engine Simulator Low Level Controller SimSailTrimTabActuation Simulator Physics Engine Simulator Low Level Controller"},{"location":"current/custom_interfaces/overview/#resources","title":"Resources","text":""},{"location":"current/custom_interfaces/overview/#common-interfaces","title":"Common Interfaces","text":"The ROS2 common_interfaces repository defines a set of packages which contain common interface files. Since we are using the Humble version of ROS2, see the humble
branch. These interfaces can be used in this repository or as a reference for ideas and best practices.
For more detail on the usefulness of each package, see this issue comment. If you are interested in creating your own custom message or service, see the ROS Humble documentation.
"},{"location":"current/local_pathfinding/overview/","title":"Overview","text":"Source code
The source code for Local Pathfinding can be found in src/local_pathfinding
. Its README has been copied below.
UBC Sailbot's local pathfinding ROS package
"},{"location":"current/local_pathfinding/overview/#run","title":"Run","text":"Using main launch file: ros2 launch local_pathfinding main_launch.py
Launch arguments are added to the run command in the format <name>:=<value>
.
log_level
Logging level A severity level (case insensitive)"},{"location":"current/local_pathfinding/overview/#server-files","title":"Server Files","text":"The server files: get_server.py
and post_server.py
are basic http server files which are used for testing the global_path module's GET and POST methods.
Source code
The source code for Network Systems can be found in src/network_systems
. Its README has been copied below.
This repository contains the source code for all of UBC Sailbot's Network Systems programs. It is made to work as part of Sailbot Workspace, and is not meant to be built as an independent project.
"},{"location":"current/network_systems/overview/#setup","title":"Setup","text":"For comprehensive setup instructions, follow our setup guide.
"},{"location":"current/network_systems/overview/#building","title":"Building","text":"Option A: With sailbot_workspace open, invoke the VSCode build
or debug
task.
Option B: Run /workspaces/sailbot_workspace/build.sh
Instructions found here.
For example:
ros2 launch network_systems main_launch.py\n
This is the best option if multiple modules need to be run at once. Launch configurations are found under the config folder. These configurations define which modules to enable/disable and what parameters to use.
"},{"location":"current/network_systems/overview/#ros-run","title":"ROS Run","text":"If you just want to run a single module, then this is a direct and easy way to do it.
For example:
ros2 run network_systems example --ros-args -p enabled:=true\n
"},{"location":"current/network_systems/overview/#binary","title":"Binary","text":"Not recommended as you cannot pass ROS parameters, so modules may not work by default. Binaries for each module found under projects can be found under /workspaces/sailbot_workspace/build/network_systems/projects/{module_name}/{module_name}
.
For example:
/workspaces/sailbot_workspace/build/network_systems/projects/example/example\n
"},{"location":"current/network_systems/overview/#testing","title":"Testing","text":"Unit tests specific to Network Systems is done using GoogleTest. Unit tests are defined per module. For example, under projects/example/test/.
"},{"location":"current/network_systems/overview/#run-all-tests","title":"Run All Tests","text":"Option A: With sailbot_workspace open, invoke the VSCode test
task.
Option B: Under the sailbot_workspace directory, run /workspaces/sailbot_workspace/scripts/test.sh
Both options will run all of UBC Sailbot's tests, including those from other projects. More often than not, this is unnecessary.
"},{"location":"current/network_systems/overview/#run-and-debug-specific-tests","title":"Run and Debug Specific Tests","text":"This is the preferred way to run and debug tests. When you open a test source file like the example's, there will be green arrows next to each TEST_F
macro. Clicking a double green arrow runs a test suite, while clicking single green arrow runs one unit test. Right clicking either arrow will open a prompt with a debug test option. When running a test via the debug option, we can set breakpoints and step through our code line by line to resolve issues.
This convenient testing frontend is thank's to the TestMate extension.
Warning: Large failing tests can crash VSCode. If this happens, either lower the size of the tests (ex. reduce the number of iterations) or run the test binary directly.
"},{"location":"current/network_systems/overview/#run-test-binaries","title":"Run Test Binaries","text":"Test binaries for each module found under projects can be found under /workspaces/sailbot_workspace/build/network_systems/projects/{module_name}/test_{module_name}
.
For example:
/workspaces/sailbot_workspace/build/network_systems/projects/example/test_example\n
"},{"location":"current/sailbot_workspace/overview/","title":"Overview","text":"Source code
The Sailbot Workspace README has been copied below.
"},{"location":"current/sailbot_workspace/overview/#sailbot-workspace","title":"Sailbot Workspace","text":"This repository will get you set up to develop UBCSailbot's software on VS Code. It is based on athackst's vscode_ros2_workspace.
"},{"location":"current/sailbot_workspace/overview/#features","title":"Features","text":"An overview of Sailbot Workspace's features can be found below. See our docs site for how to use these features.
"},{"location":"current/sailbot_workspace/overview/#style","title":"Style","text":"C++ and Python linters and formatters are integrated into Sailbot Workspace:
The ament linters are configured to be consistent with the ROS style guide.
"},{"location":"current/sailbot_workspace/overview/#dev-container","title":"Dev Container","text":"Dev Containers enable us to use a Docker container as a fully-featured development environment containing all our configuration and dependencies. Our Dev Container configuration can be found in .devcontainer/
.
Workspaces are VS Code instances that contain one or more folders. Our workspace configuration file can be found at sailbot.code-workspace
.
Our software spans many repositories: software team repositories. Multi-root workspaces make it easy to work with multiple repositories at the same time. Our roots are defined in the folders
section of our workspace file.
Launch configurations have been created to debug our software. They are defined in the launch
section of our workspace file.
Tasks provide an alternative to memorizing the multitude of CLI commands we use to setup, build, lint, test, and run our software. They are defined in tasks
section of our workspace file.
Actions were used to build our Docker containers and lint and test our code the same way it is done locally in Sailbot Workspace on GitHub. We use a reusable workflow to create a single source of truth for our tests across all our repositories. Our CI can be found in .github/workflows/
.
This repository supports user-specific configuration files. To set this up, see How to use your dotfiles.
"},{"location":"current/sailbot_workspace/overview/#run-rayes-software","title":"Run Raye's Software","text":"Raye was our previous project. Her software can be run in the raye
branch following the instructions in How to run Raye's software. The initial differences between the main
and raye
branches are summarized in this PR.
Further documentation, including setup and run instructions, can be found on our Docs website.
"},{"location":"current/sailbot_workspace/overview/#tutorial","title":"Tutorial","text":"Disclaimer
This tutorial was done a while ago, so some parts may no longer be relevant. For the most up to date information, consult the docs pages and the software leads.
"},{"location":"current/sailbot_workspace/scripts/","title":"Scripts","text":"Source code
Our scripts can be found in scripts
. Its README has been copied below.
All scripts in this directory should be able to be run with ./path/to/script
(excluding arguments). For this to work, the script will need to have a shebang and be executable. For more details, see this tutorial.
ament-lint.sh
","text":"Script to lint source code in all ROS packages.
"},{"location":"current/sailbot_workspace/scripts/#buildsh","title":"build.sh
","text":"Script to build all ROS packages in the Sailbot Workspace.
"},{"location":"current/sailbot_workspace/scripts/#clang-tidysh","title":"clang-tidy.sh
","text":"Script to run Clang-Tidy using ament_clang_tidy.py
.
run_virtual_iridium.sh
","text":"./run_virtual_iridium.sh <(optional) webhook server url> <(optional) virtual iridium http server port>\n
Creates a pair of socat sockets $LOCAL_TRANSCEIVER_TEST_PORT
and $VIRTUAL_IRIDIUM_PORT
and binds the latter to a virtual iridium server running on localhost:8080, which substitutes the Rockblock HTTP server used in deployment. Allows testing of satellite code without needing physical hardware.
Optional argument - webhook server url:
http://127.0.0.1:8081
, which assumes fully local testing.Optional argument - virtual iridium server port
$LOCAL_TRANSCEIVER_TEST_PORT
acts as the serial port for AT commands. For example, to test via CLI:
./run_virtual_iridium.sh
$LOCAL_TRANSCEIVER_TEST_PORT
without extra debug messages, in a new terminal run cat $LOCAL_TRANSCEIVER_TEST_PORT
. What you see output from this command will be what the Local Transceiver reads and sends.stty 19200 < $LOCAL_TRANSCEIVER_TEST_PORT
to set the baud rate.printf \"at+sbdix\\r\" > $LOCAL_TRANSCEIVER_TEST_PORT
. This command queries the (currently empty) mailbox.curl -X POST -F \"test=1234\" http://localhost:8080
(this is garbage data - it doesn't mean anything). You should see the original terminal print that it received a POST request.printf \"at+sbdix\\r\" > $LOCAL_TRANSCEIVER_TEST_PORT
to view the mailbox again. It will now indicate that it has the data.Other relevant commands include (but are not limited to):
at+sbdwb=<msg_length>\\r
: Setup the port to receive binary data of length msg_length
on next input.at+sbdrb\\r
: Read binary content in the mailbox.at+sbdd2\\r
: Clear all buffers.run-tests.sh
","text":"Script to setup, build, and test all ROS packages.
"},{"location":"current/sailbot_workspace/scripts/#run_softwaresh","title":"run_software.sh
","text":"Script to setup, build, and run all ROS packages.
"},{"location":"current/sailbot_workspace/scripts/#setupsh","title":"setup.sh
","text":"Script to handle ROS setup.
"},{"location":"current/sailbot_workspace/scripts/#testsh","title":"test.sh
","text":"Script to run tests in all ROS packages.
"},{"location":"current/sailbot_workspace/reference/deployment/","title":"Deployment","text":"Source code
The source code for deployment can be found in scripts/deployment
. Its README has been copied below.
Deploying our software to our autonomous sailboat's main computer.
"},{"location":"current/sailbot_workspace/reference/deployment/#scripts","title":"Scripts","text":""},{"location":"current/sailbot_workspace/reference/deployment/#setup_bootsh","title":"setup_boot.sh
","text":"Configures programs and scripts that need to run when the main computer boots. Only needs to be run once unless the script is updated. Does not need to be rerun if any scripts or programs it targets are updated, with the exception of renaming or moving the file.
Usage:
sudo ./setup_boot.sh
start_containers.sh
","text":"Runs our Docker Compose files. You may have to install commands like wget
. Would recommend running this script in its own clone of sailbot_workspace (not the one you open in VS Code).
Usage:
./start_containers.sh
--website
argument to additionally run the website container--interactive
argument to manually run commands in the sailbot workspace container--help
argument to see all available argumentsA table detailing the Docker images used to create the Dev Container can be found below. Click on an image to learn more about its features and how to update it.
Image Parent Image Source Code Why it is Rebuilt Where it is Builtpre-base
Ubuntu 22.04 base-dev.Dockerfile
To install ROS or OMPL Personal computer base
pre-base
base-dev.Dockerfile
To install core dependencies Workflow dispatch local-base
base
base-dev.Dockerfile
To install core dev dependencies Workflow dispatch dev
local-base
base-dev.Dockerfile
To install dev dependencies Workflow dispatch Dev Container dev
Dockerfile
To configure the Dev Container VS Code docs
mkdocs-material
docs.Dockerfile
To install and run docs site VS Code (optional) website
javascript-node
website.Dockerfile
To install and run website VS Code (optional)"},{"location":"current/sailbot_workspace/reference/docs_site/","title":"Docs Site","text":"UBCSailbot software team's documentation site. It is meant to be developed in Sailbot Workspace in conjunction with our other software, but doesn't have to be. There are instructions for both cases below.
"},{"location":"current/sailbot_workspace/reference/docs_site/#setup","title":"Setup","text":""},{"location":"current/sailbot_workspace/reference/docs_site/#setup-in-sailbot-workspace","title":"Setup in Sailbot Workspace","text":"docs/docker-compose.docs.yml
in .devcontainer/devcontainer.json
8000:8000
in .devcontainer/docker-compose.yml
Refer to How to work with containerized applications for more details.
"},{"location":"current/sailbot_workspace/reference/docs_site/#setup-standalone","title":"Setup Standalone","text":"Manually install social plugin OS dependencies
Install Python dependencies
pip install --upgrade pip pip install -Ur docs/requirements.txt
After setup, the Docs site should be running on port 8000.
Refer to How to work with containerized applications for more details.
"},{"location":"current/sailbot_workspace/reference/docs_site/#run-standalone","title":"Run Standalone","text":"mkdocs serve\n
"},{"location":"current/sailbot_workspace/reference/docs_site/#update-dependencies","title":"Update Dependencies","text":"This site is built using the latest versions of dependencies in docs/requirements.txt
at the time of the most recent commit to the main branch. To see exactly how the site will look when deployed, ensure your local dependencies are up to date.
Rebuild the Dev Container.
"},{"location":"current/sailbot_workspace/reference/docs_site/#update-dependencies-by-itself","title":"Update Dependencies By Itself","text":"pip install -Ur docs/requirements.txt\n
"},{"location":"current/sailbot_workspace/reference/docs_site/#maintain","title":"Maintain","text":""},{"location":"current/sailbot_workspace/reference/docs_site/#contribute-to-this-site","title":"Contribute to This Site","text":"Read our Markdown Reference Page for the syntax supported by this site.
"},{"location":"current/sailbot_workspace/reference/docs_site/#delete-docs-versions","title":"Delete Docs Versions","text":"A version of the docs site is created when a PR is open, and is deleted when it is merged or closed. However, the CI that does this is very finicky, so if 2 PR's are trying to update the site at the exact same time one might fail.
This is especially annoying if this happens to be one that deletes a version, because this means that there is a version still open for a merged/closed PR. To manually clean up these PR's, run the following commands in the docs container (in Docker Desktop, the exec tab):
git config user.name <your github username>\ngit config user.email <your github email>\nmike delete --push pr-<number>\n
If you get an error that your local copy of the gh-pages
branch has diverged from the remote, you can delete it with git branch -D gh-pages
and rerun the mike delete
command above.
It will probably ask you to login to GitHub: enter your username then a GitHub access token with write permission.
"},{"location":"current/sailbot_workspace/reference/launch_files/","title":"ROS Launch Files in Sailbot Workspace","text":"ROS 2 Launch files allow us to programatically start up and configure multiple ROS nodes.1 Within Sailbot Workspace, ROS launch files are used to start up our ROS packages with ease. Additionally, we take advantage of the hierarchical properties of launch files by defining a global entry point that invokes the launch files of all ROS packages in the system.
"},{"location":"current/sailbot_workspace/reference/launch_files/#tutorial","title":"Tutorial","text":""},{"location":"current/sailbot_workspace/reference/launch_files/#launch-file-architecture","title":"Launch File Architecture","text":"There are two launch processes that we utilize: namely the Package Launch Process and the Global launch process.
"},{"location":"current/sailbot_workspace/reference/launch_files/#the-package-launch-process","title":"The Package Launch Process","text":"The package launch process is intended to start up a specific ROS package by directly using the package launch file. The process is as follows:
Some packages rely on the data produced by other packages in the system. This may cause only partial functionality of the ROS node(s) that are running inside the launched package. Therefore, it may be necessary to launch multiple packages manually to get the desired functionality.
"},{"location":"current/sailbot_workspace/reference/launch_files/#the-global-launch-process","title":"The Global Launch Process","text":"The global launch process is intended to start up the entire system (both the development and production environments). This process invokes the package launch files for each ROS package used in the system through a global launch file. The process is as follows:
Entering Ctrl+C in the terminal where the launch file was invoked will stop all associated ROS packages from running.
Use Cmd+C for Mac OS
"},{"location":"current/sailbot_workspace/reference/launch_files/#package-launch","title":"Package Launch","text":"At the bare minimum, the following packages need to be built with the Build
or Build All
VS Code task before launching:
custom_interfaces
Packages only need to be rebuilt either when the workspace is first set up, or if any changes are made to the ROS package. Once built, the package launch file can be invoked either in the CLI or using a VS Code command:
CLI VS CodeEither the package and launch file name, or the path to the launch file can be used:
ros2 launch <package> <launch file>
. This method can only be used when a launch file is part of a built ROS package.ros2 launch <path to launch file>
. This method can be used regardless if a launch file is in a ROS package or not.Launch via CLI Examples
Let's launch local pathfinding using both CLI methods:
Method 1
ros2 launch local_pathfinding main_launch.py\n
Method 2
ros2 launch $ROS_WORKSPACE/src/local_pathfinding/launch/main_launch.py\n
Run the following VS Code command from the Run and Debug tab: ROS: Launch (workspace)
There will be a prompt to select which launch file to run. Select the desired launch file.
"},{"location":"current/sailbot_workspace/reference/launch_files/#global-launch","title":"Global Launch","text":"Before running the system, be sure to run the Build All
VS Code task to build all ROS packages. If the ROS launch debug configuration is being used, then this step is not necessary as the Build All
task is ran automatically before launch.
Run the entire system with the following CLI command:
ros2 launch $ROS_WORKSPACE/src/global_launch/main_launch.py\n
Run the following VS Code command from the Run and Debug tab: ROS: Launch (workspace)
There will be a prompt to select which launch file to run. Select the desired launch file.
Remember to that you need to potentially reload the window if the nodes are not being detected by VS Code. This usually happens when somebody build for the first time. Also, note that the global launch file is not part of a ROS package, so the path to the global launch file always must be provided. This is not always the case when a launch file is contained within a ROS package.
"},{"location":"current/sailbot_workspace/reference/launch_files/#using-cli-arguments","title":"Using CLI Arguments","text":"Invoking the launch files as is will provide the system with the default CLI arguments. As an example, the following command will launch local pathfinding while setting the log level to \"debug\":
ros2 launch local_pathfinding main_launch.py log_level:=debug\n
It can also be ran with the VS Code command named ROS: Launch.
Passing arguments takes the form of <arg name>:=<arg value>
. To list the arguments that a launch file takes, simply add the -s
flag at the end of the launch command.
-s
flag in a launch command Let's add the -s
flag after the global launch command to see the list of arguments:
ros2 launch $ROS_WORKSPACE/src/global_launch/main_launch.py -s\n
The following output is observed in the terminal (as of September 2023):
Arguments (pass arguments as '<name>:=<value>'):\n\n'config':\n Path to ROS parameter config file. Controls ROS parameters passed into ROS nodes\n (default: '/workspaces/sailbot_workspace/src/global_launch/config/globals.yaml')\n\n'log_level':\n Logging severity level. A logger will only process log messages with severity levels at or higher than the\n specified severity. Valid choices are: ['debug', 'info', 'warn', 'error', 'fatal']\n (default: 'info')\n\n'mode':\n System mode. Decides whether the system is ran with development or production interfaces. Valid choices are:\n ['production', 'development']\n (default: 'development')\n
Example using multiple CLI arguments ros2 launch local_pathfinding main_launch.py log_level:=debug mode:=production\n
Example passing local launch arguments to the global launch file As long as an argument is valid inside one of the package launch files, it may be passed to the global launch file without generating any errors. This is valid even though the argument doesn't show up in the argument list for the global launch file. For example, the following will run:
ros2 launch $ROS_WORKSPACE/src/global_launch/main_launch.py enable_sim_multithreading:=true\n
Compare the argument list between the global launch file and the package launch file for the boat_simulator
package. It will be observed that the argument enable_sim_multithreading
shows up in the boat_simulator
package argument list, but not for the global launch file.
All launch files in Sailbot Workspace accept a configuration file, which controls the ROS parameters that the ROS nodes in the system have access to. This makes our system highly configurable and customizable during development and testing. See more about ROS parameters.
ROS Launch File Documentation \u21a9
Source code
The source code for Notebooks can be found in notebooks
. Its README has been copied below.
UBC Sailbot's Jupyter notebooks for researching and exporing implementations.
"},{"location":"current/sailbot_workspace/reference/notebooks/#standards","title":"Standards","text":"Source code
Our ROS parameters can be found in src/global_launch/config
. Its README has been copied below.
The description of each parameter contained in globals.yaml
are described in this README. Descriptions of parameters for each node are included. These parameters can be changed dynamically as well via the command line interface. To learn more, see the ROS 2 documentation on ROS 2 Parameters.
Each parameter is specified in the following format:
[]
denotes inclusive boundaries, while ()
denotes non-inclusive boundaries. For strings, the acceptable values are listed.Additional information may be included when necessary.
[!IMPORTANT] This document should be updated when any changes occur to the ROS parameters specified in globals.yaml
.
ROS parameters common across all ROS nodes in the network.
pub_period_sec
double
(0.0, MAX_DOUBLE)
ROS parameters specific to the nodes in the local_pathfinding package.
"},{"location":"current/sailbot_workspace/reference/parameters/#mgp_main","title":"mgp_main
","text":"global_path_filepath
string
interval_spacing
double
(0.0, MAX_DOUBLE)
write
boolean
true
, false
gps_threshold
double
(1.0, MAX_DOUBLE)
force
boolean
true
, false
navigate_main
","text":"path_planner
string
\"bitstar\"
, \"bfmtstar\"
, \"fmtstar\"
, \"informedrrtstar\"
, \"lazylbtrrt\"
, \"lazyprmstar\"
, \"lbtrrt\"
, \"prmstar\"
, \"rrtconnect\"
, \"rrtsharp\"
, \"rrtstar\"
, \"rrtxstatic\"
, \"sorrtstar\"
ROS parameters specific to the nodes in the Controller.
"},{"location":"current/sailbot_workspace/reference/parameters/#wingsail_ctrl_node","title":"wingsail_ctrl_node","text":"reynolds_number
double
(0.0, MAX_DOUBLE)
angle_of_attack
double
(-180.0, 180.0]
ROS parameters specific to the nodes in the boat simulator.
"},{"location":"current/sailbot_workspace/reference/parameters/#low_level_control_node","title":"low_level_control_node
","text":"info_log_throttle_period_sec
double
(0.0, MAX_DOUBLE)
logging_throttle_period_sec
double
(0.0, MAX_DOUBLE)
qos_depth
int
[1, MAX_INT)
rudder.actuation_execution_period_sec
double
(0.0, MAX_DOUBLE)
rudder.disable_actuation
boolean
true
, false
rudder.fixed_angle_deg
rudder.disable_actuation
is true.double
[-45.0, 45.0]
rudder.pid.buffer_size
int
[1, MAX_INT)
rudder.pid.kd
rudder.disable_actuation
is false.double
[0.0, MAX_DOUBLE)
rudder.pid.ki
rudder.disable_actuation
is false.double
[0.0, MAX_DOUBLE)
rudder.pid.kp
rudder.disable_actuation
is false.double
[0.0, MAX_DOUBLE)
wingsail.actuation_execution_period_sec
double
(0.0, MAX_DOUBLE)
wingsail.actuation_speed_deg_per_sec
double
(0.0, MAX_DOUBLE)
wingsail.disable_actuation
boolean
true
, false
wingsail.fixed_angle_degree
wingsail.disable_actuation
is true.double
[-180.0, 180.0)
physics_engine_node
","text":"action_send_goal_timeout_sec
double
(0.0, MAX_DOUBLE)
info_log_throttle_period_sec
double
(0.0, MAX_DOUBLE)
logging_throttle_period_sec
double
(0.0, MAX_DOUBLE)
qos_depth
int
[1, MAX_INT)
rudder.actuation_request_period_sec
double
(0.0, MAX_DOUBLE)
wingsail.actuation_request_period_sec
double
(0.0, MAX_DOUBLE)
wind_sensor.constant_params.value
x
and y
components of the velocity. Only used if wind_sensor.generator_type
is constant
.double
array, length 2(MIN_DOUBLE, MAX_DOUBLE)
wind_sensor.gaussian_params.corr_xy
wind_sensor.generator_type
is gaussian
.double
[-1.0, 1.0]
wind_sensor.gaussian_params.mean
x
and y
components of the velocity. Only used if wind_sensor.generator_type
is gaussian
.double
array, length 2(MIN_DOUBLE, MAX_DOUBLE)
wind_sensor.gaussian_params.std_dev
x
component, and one for the y
component. Only used if wind_sensor.generator_type
is gaussian
.double
array, length 2(0.0, MAX_DOUBLE)
wind_sensor.generator_type
string
gaussian
, constant
wind_generation.mvgaussian_params.mean
double
array, length 2(0.0, MAX_DOUBLE)
wind_generation.mvgaussian_params.cov
double
array, since ROS parameters do not support native 2D array types.string
(0.0, MAX_DOUBLE)
current_generation.mvgaussian_params.mean
double
array, length 2(0.0, MAX_DOUBLE)
current_generation.mvgaussian_params.cov
double
array, since ROS parameters do not support native 2D array types.string
(0.0, MAX_DOUBLE)
data_collection_node
","text":"file_name
string
qos_depth
int
[1, MAX_INT)
topics
['topic_name_1', 'topic_type_1', ...]
.string
array with an even lengthbag
boolean
true
, false
json
boolean
true
, false
write_period_sec
double
(0.0, MAX_DOUBLE)
If you are not satisfied with the performance of Sailbot Workspace, here are some things you can try:
-q
argument takes about a minute. If your computer takes longer than, or you want to free up memory and disk space, you can setup Sailbot Workspace in a GitHub CodespaceIf you are having some trouble running our software, here are some things you can try:
"},{"location":"current/sailbot_workspace/usage/help/#sailbot-workspace-troubleshooting","title":"Sailbot Workspace Troubleshooting","text":"setup
task to update package dependenciesclean
task to delete C++ generated filespurge
task to delete ROS generated filesBuild All
task to rebuildDev Containers: Rebuild Container
VS Code commandDeveloper: Reload Window
VS Code commandHelp: Start Extension Bisect
VS Code commandwsl --shutdown
in PowerShellDelete Docker files
Running Docker CLI commands on WindowsOn Windows, Docker CLI commands should be run in the Ubuntu terminal while Docker Desktop is running.
docker system prune
to remove all unused containers, networks, and dangling and unreferenced images--all
to additionally remove unused images (don't have a container associated with them)--volumes
to additionally remove volumes (makes Bash history and ROS logs persist across containers)docker rmi -f $(docker images -aq)
to remove all imagesAfter using Docker and Ubuntu for a while, you may notice that the vdisks are very large. As of May 2024, they are located at C:\\Users\\<user>\\AppData\\Local\\Docker\\wsl\\data\\ext4.vhdx
and C:\\Users\\<user>\\AppData\\Local\\Packages\\CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc\\LocalState\\ext4.vhdx
, respectively.
The problem is that these vdisks can automatically grow but not shrink, so if you download large files (like Docker images) and delete them once they're not needed the space is not freed. You can shrink vdisk using these commands.
"},{"location":"current/sailbot_workspace/usage/how_to/","title":"How-To's","text":""},{"location":"current/sailbot_workspace/usage/how_to/#run-vs-code-commands-tasks-and-launch-configurations","title":"Run VS Code commands, tasks, and launch configurations","text":"MacOS keyboard shortcuts
For keyboard shortcuts on MacOS, substitute Ctrl with Cmd.
VS Code commands can be run in the Command Palette. Open the Command Palette from the View
menu or with Ctrl+Shift+P.
Tasks can be run using the Tasks: Run Task
VS Code command. Build tasks can be run with Ctrl+Shift+B.
Launch configurations can be run from the Run and Debug view.
You can also run VS Code commands, tasks, launch configurations, and much more by typing their prefixes into an empty Command Palette. Open an empty Command Palette with Ctrl+P or by clicking the box in the center of the title bar. See the list below for some prefixes and their functions. For prefixes that are words, you will have to append a space to them to bring up their functions.
>
: VS Code commandstask
: tasksdebug
: launch configurations?
: list all prefixes and their functionsWe have containerized the following applications for a variety of reasons:
In the first section of dockerComposeFile
of .devcontainer/devcontainer.json
, there is a list of files: each file contains the configuration for one or more applications.
The ones that are commented out are not run. To run them:
.devcontainer/docker-compose.yml
Dev Containers: Rebuild Container
VS Code command to restart Sailbot WorkspaceTo stop running them:
.devcontainer/devcontainer.json
and port mapping in .devcontainer/docker-compose.yml
Connect the MongoDB VS Code extension to the running database: Create a Connection for Deployment
mongodb://localhost:27017
Docs runs on port 8000 and Website 3005. You can see them in your browser at localhost:<port>
. To open them using VS Code:
Ports: Focus on Ports View
VS Code commandTurn off auto saving
Changes made to their files are loaded when they are saved, so if Auto Save is on, turn it off so that the Docs/Website servers aren't continuously reloading. Auto Save is on by default in GitHub Codespaces
"},{"location":"current/sailbot_workspace/usage/how_to/#managing-containerized-applications","title":"Managing containerized applications","text":"Each application runs in a Docker container. Containers can be managed using Docker Desktop or CLI commands:
View Sailbot Workspace containers
Docker Desktop CLI Commandsdocker ps -a\n
sailbot_workspace_devcontainer-<application>-<number>
STATUS
column shows whether a container is running or notView a container's logs, the output of the container (including errors that caused it to stop)
Docker Desktop CLI Commandsdocker logs <container>\n
Start a container that is not running
Docker Desktop CLI Commandsdocker start <container>\n
Stop a container that is running
Docker Desktop CLI Commandsdocker stop <container>\n
Why can't I just install the dependencies myself in the command line interface with pip
or apt
?
Although this will temporarily work, installing apt and/or Python dependencies directly in sailbot workspace using the commandline interface will not persist between container instances. The dependencies will need to be manually installed every single time you create a new instance of sailbot workspace, which is not feasible when we start to use many dependencies at once.
Of course, one could also install dependencies inside the sailbot workspace Docker images to allow such dependencies to persist across container instances. However, putting dependencies inside package.xml
distinguishes between what dependencies are needed for ROS packages and what dependencies are needed for infrastructure purposes.
If running your ROS packages requires external dependencies from an apt repository or python package, one of the following tags should be added to the package.xml
file in the root directory of the ROS package:
<depend>ROSDEP_KEY</depend>\n<build_depend>ROSDEP_KEY</build_depend>\n<build_export_depend>ROSDEP_KEY</build_export_depend>\n<exec_depend>ROSDEP_KEY</exec_depend>\n<test_depend>ROSDEP_KEY</test_depend>\n
Learn what each tag is used for here.
Replace ROSDEP_KEY
with the rosdep key for the dependency, which can be found online.
package.xml
python3-
(python-
is usually for Python 2)If there isn't rosdep key for the dependency, you can add your own to custom-rosdep.yaml
in the root directory of the ROS package
After completing these steps, run the setup
task and the desired dependencies should be installed. ROS uses a dependency management utility, rosdep, to handle the installation of dependencies. In addition to runtime dependencies, rosdep also handles dependencies for build time, dependencies for testing, sharing dependencies between ROS packages, and more. See the ROS documentation on rosdep to learn more.
There are a couple cases where you would want to add dependencies to a Docker image instead of ROS package:
To verify your changes, you can add them to .devcontainer/Dockerfile
then run the Dev Containers: Rebuild Container
VS Code command. Once verified, migrate the changes to one of the upstream images: base
, local-base
, dev
, or pre-base
.
GitHub Copilot is an AI paired programming tool that can help you accelerate your development by providing suggestions for whole lines or entire functions inside your editor.1 To enable GitHub Copilot:
Apply to GitHub Global Campus as a student to use GitHub Copilot and get other student benefits for free. It may take a few days for your student status to be verified. In the meantime, you can still continue with the next steps. However, you will need to use the GitHub Copilot free trial until your account is verified.
Sign up for GitHub Copilot for your personal account. If it offers a free trial, then take it. You should see a page telling you that you can use GitHub Copilot for free (if you have a verified student account).
Uncomment the github.copilot
extension in .devcontainer/devcontainer.json
and run the Dev Containers: Rebuild Container
VS Code command
Sign into your GitHub account in VS Code. The GitHub Copilot extension should automatically prompt you to sign into your account if you are not already.
VS Code is not prompting me to sign into my accountYou may already be signed in into your GitHub account. You can check by clicking on the Accounts icon in the bottom-left corner in VS Code and verify that you see your GitHub account.
If you do not see your account, you can get the sign in prompt by trying:
Developer: Reload Window
Dev Containers: Rebuild Container
If all the previous steps were done correctly, you should see the GitHub Copilot icon in the bottom-right corner of VS Code without any error messages. For more information on how to use Copilot and a tutorial, refer to:
Dotfiles are configuration files for various programs.2
More about dotfiles.
)ls
command, specify the -a
argument: ls -a
Dotfiles that are commonly modified include:
~/.bashrc
~/.gitconfig
~/.vimrc
To use your dotfiles:
base
, local-base
, or dev
image installs the programs that the dotfiles correspond toCopy the dotfiles to the .devcontainer/config/
directory. If a dotfile is located in a child directory, you will have to created it. For example, if a dotfile's path is ~/.config/ex_dotfile
, you will need to copy it to .devcontainer/config/.config/ex_dotfile
Special cases
~/.gitconfig
: there is no need copy your Git dotfile, as Dev Containers do this automatically~/.bashrc
: don't copy your Bash dotfile, as it would override the one created in the dev
image. Instead, add your bash configuration .aliases.bash
or .functions.bash
in the config directory, as these are sourced by the created Bash dotfile.Run the Dev Containers: Rebuild Container
VS Code command
Raye was our previous project. Her software can be run in the raye
branch:
raye
branch: git switch raye
Dev Containers: Rebuild Container
VS Code commandraye
branch disclaimers
raye
(and Raye's codebase in general) is not in active development, it may not be 100% functional or contain all the features in main
raye
is more memory intensive than main
because the parent image of its Dev Container is much larger; this may lead to worse performanceTo build Raye's ROS packages, run the following commands:
roscd\ncatkin_make\n
"},{"location":"current/sailbot_workspace/usage/how_to/#run-packages-from-different-workspaces","title":"Run packages from different workspaces","text":"The raye
branch has two ROS workspaces: one for Raye and one for the new project. To run ROS packages, you will have to source the overlay of the workspace that it is in:
srcnew\n
srcraye\n
Then you can run launch files or package-specific executables in that workspace with:
New ProjectRayeros2 launch ...
or ros2 run ...
, respectively.
roslaunch ...
or rosrun ...
, respectively.
Run commands for Raye packages are very slow
On non-Ubuntu-based Linux operating systems, Run commands for Raye packages may take a long time to start-up. This is because the system has trouble resolving the local hostname.
To resolve this bug, run the commands below in the Dev Container:
echo 'export ROS_HOSTNAME=localhost' >> ~/.bashrc\necho 'export ROS_MASTER_URI=http://localhost:11311' >> ~/.bashrc\n
GitHub Copilot Quickstart Guide \u21a9
Dotfiles \u2013 What is a Dotfile and How to Create it in Mac and Linux \u21a9
Sailbot Workspace can be run on Windows, Linux, or macOS, but is the easiest to set up and performs the best on Ubuntu and its derivatives. The workspace may not perform well on Windows computers with 8GB of memory or less; in this case, please check out our recommendations in the Performance Issues section.
"},{"location":"current/sailbot_workspace/usage/setup/#1-setup-prerequisites","title":"1. Setup prerequisites","text":""},{"location":"current/sailbot_workspace/usage/setup/#docker","title":"Docker","text":"Docker is a platform that uses OS-level virtualization1 to develop, ship, and run applications.2 We use it to separate our applications from our infrastructure2 so that we can update and version control our infrastructure for every use case (software members, CI, deployment) in one place: this repository.
Docker Engine is a software used to run Docker. However, it can only be installed on Linux. Docker Desktop is a software used to run Docker in a VM,3 allowing it to be installed on Windows and macOS in addition to Linux.
Windows macOS LinuxSet up prerequisites, WSL and Ubuntu:
In PowerShell, run wsl --install Ubuntu
, then exit
, wsl --update
, and wsl --set-default Ubuntu
If Ubuntu is already installed, check that it is the right WSL version:
wsl -l -v
VERSION
is 1, upgrade it to WSL 2 with wsl --set-version Ubuntu 2
Open the Ubuntu app to set up or verify its configuration:
Run whoami
to verify that it returns your Ubuntu username
whoami
returns root
If whoami
returns root
:
ubuntu config --default-user <username>
in PowerShell, replacing <username>
with the name of the newly-created userwhoami
after closing and reopening Ubuntu, verifying that it returns your Ubuntu usernameInstall Docker Desktop with the WSL 2 backend
Docker Desktop - Unexpected WSL ErrorIf the above error shows when trying to start Docker Desktop on your laptop:
C:\\Users\\user_name
and delete the .Docker folderIf Ubuntu can't start up and WSL hangs when restarting:
netsh winsock reset
More potential solutions can be found here: Link
Install Docker Desktop for your computer's CPU.
Visual Studio Code is a powerful and customizable code editor for Windows, Linux, and macOS. We strongly recommend that you use this editor to develop our software so that you can use all the features of Sailbot Workspace.
Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.4
git --version
(on Windows, run command in PowerShell)Login to GitHub
Windows macOS / LinuxRun the git config
command for your Git version in Git Credential Manager setup (run command in Ubuntu)
Which Git to check
Git is installed seperately in Windows and Ubuntu, so they could be at different versions. We want to check the version of Git on Windows, not Ubuntu: run git --version
in PowerShell and not Ubuntu. However, the git config
command itself is run in Ubuntu.
gh auth login
and select the first option for all choicesVerify that you have successfully logged in to GitHub by cloning a private GitHub repository (run command in Ubuntu)
git clone https://github.com/UBCSailbot/raye-ais.git
rm -rf raye-ais
X11 forwarding is a mechanism that enables Sailbot Workspace to run GUI applications.
You can skip this step since we currently aren't running any GUI applications
Setup instructions for X11 forwardingVerify that echo $DISPLAY
returns something like :0
echo $DISPLAY
doesn't return anything If echo $DISPLAY
doesn't return anything, set it to :0
on shell initialization:
echo $SHELL
~/.bashrc
~/.zshrc
echo 'export DISPLAY=:0' >> <rc file path>
, replacing <rc file path>
with the path to your shell's rc fileecho $DISPLAY
after closing and reopening your terminal, verifying it returns something like :0
Install a X11 server
Windows macOS LinuxWSL includes a X11 server.
cp /opt/X11/etc/X11/xinit/xinitrc ~/.xinitrc
xhost +localhost
to ~/.xinitrc
after its first lineAs of February 2023, almost all Linux distributions include a X11 server, Xorg. This may change in the future as Wayland matures.
sudo pacman -S xorg-xhost
cp /etc/X11/xinit/xinitrc ~/.xinitrc
xhost +local:docker
to ~/.xinitrc
after its first lineVerify that X11 forwarding works:
Install x11-apps
In Ubuntu, sudo apt install x11-apps
.
XQuartz includes x11-apps
. Ensure that XQuartz is running.
Install x11-apps
using your desired package manager.
Verify that running xcalc
opens a calculator and that you can use it
Where to clone on Windows
Run the command below in the Ubuntu app to clone it in the Ubuntu file system, otherwise sailbot workspace will not work. Windows has a native file system as well as file systems for each WSL distribution.
git clone https://github.com/UBCSailbot/sailbot_workspace.git\n
"},{"location":"current/sailbot_workspace/usage/setup/#4-open-sailbot-workspace-in-vs-code","title":"4. Open Sailbot Workspace in VS Code","text":"Install code
command in PATH
The code
command is installed by default.
See launching from the command line.
The code
command is installed by default.
Open the sailbot_workspace/
directory in VS Code: run code <relative path to sailbot workspace>
code sailbot_workspace
Click the popup to Open Workspace
. If there isn't a popup:
sailbot.code-workspace
in VS CodeOpen Workspace
Reopen in Container
. If there isn't a popup, run the Dev Containers: Reopen in Container
VS Code commandBuild All
task","text":"Wait before running
Ensure that the postCreateCommand from devcontainer.json
has completed before running this task.
The Build All
task builds all the ROS packages.
Delete all open terminals and run the Developer: Reload Window
VS Code command to detect the files that were generated from building.
Run the entire system to verify everything is working using the following command in the VS Code terminal:
ros2 launch $ROS_WORKSPACE/src/global_launch/main_launch.py\n
Use Ctrl+C in the terminal to stop the system.
"},{"location":"current/sailbot_workspace/usage/setup/#setup-sailbot-workspace-in-a-github-codespace","title":"Setup Sailbot Workspace in a GitHub Codespace","text":"A codespace is a development environment that's hosted in the cloud.5 Since Sailbot Workspace is resource intensive, it has high hardware requirements and power consumption, which aren't ideal for development on laptops. GitHub Codespaces provide a seamless experience to work on repositories off-device, especially if they specify a Dev Container like Sailbot Workspace. Codespaces can run in VS Code or even in a browser for times when you aren't on your programming computer.
Once you have a codespace set up:
Codespaces: Stop Current Codespace
VS Code commandKnown limitations of running Sailbot Workspace in a GitHub Codespace
Wikipedia Docker page \u21a9
Get Docker \u21a9\u21a9
What is the difference between Docker Desktop for Linux and Docker Engine \u21a9
Git SCM \u21a9
GitHub Codespaces overview \u21a9
Once you have set up Sailbot Workspace, you can open it by opening a new VS Code window and selecting:
File > Open Recent > /workspaces/sailbot_workspace/.devcontainer/config/sailbot_workspace (Workspace) [Dev Container: Sailbot Workspace]\n
Another way to open Sailbot Workspace on Windows sailbot_workspace (Workspace) [Dev Container]
Then you can open Sailbot Workspace by selecting it from the \"Pinned\" section of the VS Code taskbar icon's right-click menu.
"},{"location":"current/sailbot_workspace/usage/workflow/#2-update-sailbot-workspace","title":"2. Update Sailbot Workspace","text":"Sailbot Workspace is still in active development, check out its recent releases and commit history. If there are new features or bug fixes that you want to try, you will need to update your local version of Sailbot Workspace:
Switch Sailbot Workspace to the main branch if you aren't in it already
If you running Git commands in the CLI, make sure that you are in the correct repositorySailbot Workspace contains other repositories in the src/
directory, so if you are in one of its subdirectories you may be in the wrong repository.
To check which repository you are in, run git remote -v
; if its output contains sailbot_workspace
, you are good to go. If not, you can navigate the root directory of the Sailbot Workspace repository with cd $ROS_WORKSPACE
, or open a new terminal in its root directory with Ctrl+Shift+` then Enter.
Pull the latest changes
If prompted, rebuild the Dev Container
When does the Dev Container need to be rebuilt?To apply the modifications to its configuration files in .devcontainer/
that occurred since it was last built.
VS Code will prompt you to rebuild when devcontainer.json
, Dockerfile
, or docker-compose*.yml
. These file may be modified if you:
.devcontainer/
yourselfHowever, there may be changes to the Dev Container that VS Code can't detect. To rebuild it yourself, run the Dev Containers: Rebuild Container
VS Code command.
If you want to run our docs or website, see How to work with containerized applications
We make changes to our software following our GitHub development workflow. Of particular relevance is the Developing on Branches page.
Git interfaces
One way to interface with Git is through CLI commands. However, you may find it faster to use VS Code's interface, especially when working with multiple repositories.
Things to note when making changes:
In general, changes need to be built before they can be run. You can skip this step if you only modified Python source or test files (in python_package/python_package/
or python_package/test
, respectively), or are running a launch type launch configuration.
Build All
or Build Package
taskclang-tidy
, use the -q
build argument (default) for quicker build timesIf you want to run GUI applications on macOS, ensure that XQuartz is running.
"},{"location":"current/sailbot_workspace/usage/workflow/#lint-and-test","title":"Lint and Test","text":"Run lint and test tasks to make sure you changes will pass our CI:
ament lint
clang-tidy
test
In addition to VS Code tasks, the Testing tab on the VS Code primary sidebar contains individual tests. One can run specific unit tests by clicking the Run Test icon beside the test name.
"},{"location":"current/sailbot_workspace/usage/workflow/#run-a-package","title":"Run a Package","text":"To verify that your changes do what you expect, you may want to run the package you modified. The run commands for each package should be documented in their READMEs, but in general they can be run using a CLI or VS Code command:
CLI VS Coderos2 launch <package> <launch file>
ros2 launch <path to launch file>
ros2 run <package> <executable>
There are many commands that can be autocompleted in the terminal. Take advantage of this so that you run commands faster and memorize less syntax. If there is only one possibility, pressing tab once will complete it. If there is more than one possibility, pressing tab again will list them out.
Some tab completion use cases:
View available commands: lists all ros2
commands
$ ros2 <tab><tab>\naction extension_points multicast security\nbag extensions node service\n...\n
Complete commands: runs ros2 launch local_pathfinding main_launch.py
$ ros2<tab>la<tab>loc<tab>m<tab>\n
Navigate to directories: runs cd .devcontainer/config
from the root directory of Sailbot Workspace
$ cd .d<tab>c<tab>\n
Furthermore, navigate past commands with Up and Down and search through them with Ctrl+R.
ROS: Run a ROS launch file (roslaunch)
ROS: Run a ROS executable (rosrun)
For more information on launch file use in our system, see this page.
"},{"location":"current/sailbot_workspace/usage/workflow/#run-the-system","title":"Run the System","text":"To verify that you didn't break anything, you may want to run the entire system. See Invoking Launch Files for more information on running the system.
"},{"location":"current/sailbot_workspace/usage/workflow/#debugging","title":"Debugging","text":"Debug your changes if they aren't behaving how you expect by setting breakpoints and running one of our launch configurations in the Run and Debug tab on the VS Code primary sidebar. The launch configuration types are:
ROS: Launch
C++ (GDB): Launch
ROS: Attach
Source code
The source code for Website can be found in src/website
. Its README has been copied below.
In the website development timeline, we are currently evaluating the folllowing software stack: Next.js website (this repository), Typescript, React + Redux, and the MongoDB database. The easiest way to evaluate these potential solutions for our purposes is in sailbot_workspace.
"},{"location":"current/website/overview/#database","title":"Database","text":"MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era. If you want to learn more about MongoDB, visit their docs site: MongoDB Documentation.
"},{"location":"current/website/overview/#setup","title":"Setup","text":""},{"location":"current/website/overview/#environment-variables","title":"Environment variables","text":"We have two separate configurations: one for development .env.development
, the other for production .env.production
. The values may vary, but the environment variables are the same. See below:
MONGODB_URI
: Your MongoDB connection string. Use mongodb://localhost:27017/<DB_NAME>
to establish a connection with the local database.NEXT_PUBLIC_SERVER_HOST
: The host URL of the website.NEXT_PUBLIC_SERVER_PORT
: The port number of the website.NEXT_PUBLIC_POLLING_TIME_MS
: The time interval for polling the database in milliseconds.The following command installs all required dependencies listed in the package.json
file:
npm install\n
Once the installation is complete, you should see a node_modules
directory in the project's root. This directory contains all installed packages.
When installing a new package to the website, please follow the steps below:
Access the terminal of the website container on Docker.
Run the command npm install <package-name>
. Replace <package-name>
with the actual name of the package you want to add.
Should you encounter errors related to resolving peer dependencies, please re-run the command with the header --legacy-peer-deps
. Do not to use --force
unless you're well aware of the potential consequences.
Review the package.json
file to ensure the new package and its version have been added to the dependencies section.
package-lock.json
has also been updated. This file holds specific version information to ensure consistent installations across different environments.package.json
and package-lock.json
. These files are essential for version controlling the dependencies that have been added.Using Sailbot Workspace, the website should be up and running on http://localhost:3005.
Otherwise, you execute the following commands to run it in development mode:
npm run dev\n
"},{"location":"current/website/overview/#linters","title":"Linters","text":"Before merging in new changes to the repository, please execute the following commands in order:
npm run format\n
This command runs Prettier to automatically format the code according to the rules defined in the configuration file .prettierrc
.
npm run lint\n
This command runs ESLint to analyze the code for potential errors and enforce coding style based on the rules defined in the configuration file .eslintrc
.
Docker is a platform that uses OS-level virtualization1 to develop, ship, and run applications.2
"},{"location":"reference/docker/#tutorial","title":"Tutorial","text":"Wikipedia Docker page \u21a9
Get Docker \u21a9
Markdown is a lightweight markup language that you can use to add formatting elements to plaintext text documents.1 You can do anything with Markdown, from creating websites to PDF documents, all in a clean format that is easy to learn. Many of your favorite services use Markdown, so it would be useful to pick it up to write technical documentation.
Markdown is not standardized across services. Many services that support Markdown have their own \"flavour\" of Markdown. Be sure to know the Markdown features of the service you are using so that your Markdown renders properly.
"},{"location":"reference/markdown/#getting-started","title":"Getting Started","text":"We recommend markdownguide.org to be your first point of reference if\\ you are learning Markdown for the first time. It covers topics like what Markdown is, its syntax, advanced tips, and the different services that support Markdown. Flavours of Markdown specific to a service build on top of these basics.
"},{"location":"reference/markdown/#sailbot-and-markdown","title":"Sailbot and Markdown","text":"We write Markdown for GitHub and Material for MkDocs. The following sections detail how Markdown is used in these services.
"},{"location":"reference/markdown/#github","title":"GitHub","text":"We use Markdown in GitHub for technical documentation and collaboration. This includes:
README.md
filesAlmost all places where text is written in GitHub support Markdown. GitHub also allows you to preview your Markdown before you submit any comments.
Before RenderingAfter RenderingThe image above shows an example of a \"write\" and a \"preview\" tab for writing a comment on an issue. It might look different depending on where you are writing, but there usually exists a preview option!
GitHub-Flavoured Markdown
GitHub uses its own \"flavour\" of Markdown. Certain features, like using HTML, are excluded for security reasons. Visit the official GitHub Markdown guide for more information on the available features.
"},{"location":"reference/markdown/#material-for-mkdocs","title":"Material for MkDocs","text":"We use Markdown in Material for MkDocs to create this website! Since it is written in Markdown, no frontend experience is required to contribute to our docs.
Material for MkDocs supports powerful features purpose-built to take technical documentation to the next level. Feel free to browse this site to see how we use these features, exploring their syntax in the source code. Since GitHub renders Markdown files automatically you will need to click the \"Raw\" button to view their contents.
Material-Flavoured Markdown
Material for MkDocs' flavour of Markdown extends upon vanilla Markdown, adding features such as admonitions (like this note) and content tabs. Refer to the official Material for MkDocs reference page for more information on the available features.
"},{"location":"reference/markdown/#rendering-markdown","title":"Rendering Markdown","text":"You have a few choices to render Markdown on your computer. Be advised that if you are using an extended version of Markdown, you will need to consult the documentation from the service provider to render their flavour of Markdown properly. The following resources are good for rendering Markdown:
Vanilla Github Material for MkDocsOther resources exist to render Markdown like browser extensions that render Markdown as HTML and GitHub repositories that contain source code to render your Markdown. Feel free to browse around for the solution that suits your needs.
"},{"location":"reference/markdown/#linting","title":"Linting","text":"We lint our Markdown files to reduce errors and increase readability. In particular, we use two tools:
markdownlint is used to enforce a style guide. Its configuration file for this repository is .markdownlint.json
. If you use VS Code, there is a markdownlint extension.
markdown-link-check is used to check for broken links. Its configuration file for this repository is .markdown-link-check.json
.
https://www.markdownguide.org/getting-started/ \u21a9
Robot Operating System (ROS) is a set of software libraries and tools for building robot applications.1 It provides functionality for hardware abstraction, device drivers, communication between processes over multiple machines, tools for testing and visualization, and much more.2
We use ROS because it is open-source, language-agnostic, and built with cross-collaboration in mind. It enables our sub-teams to work independently on well-defined components of our software system without having to worry about the hardware it runs on or the implementation of other components.
The official ROS 2 documentation contains everything you need to get started using ROS. From it we have hand-picked the resources that are most relevant to our current and expected future usage of ROS assuming that you use our preconfigured workspace. To run our software on your device without our workspace, you would have to install ROS and the dependencies that are in our Docker images yourself.
"},{"location":"reference/ros/#tutorial","title":"Tutorial","text":""},{"location":"reference/ros/#workspace-configuration","title":"Workspace Configuration","text":"To get our workspace configuration running on your computer:
.devcontainer/Dockerfile
, then run the \"Dev Containers: Rebuild Container\" VS Code command, to install the tutorials' dependencieshumble
branch), py_pubsub_ex, and cpp_pubsub_ex, then run the setup
VS Code task to install their dependenciesOur workspace configuration contains easier methods of accomplishing some of the tutorial steps, or eliminates the need for them altogether.
Tutorial step Sailbot Workspace configuration Install a package All packages used in the tutorials are already installed (step 2 above) Clone a sample repo (ros_tutorials) ros_tutorials is already cloned (step 3 above) Resolve dependencies Run the \"install dependencies\" VS Code task Build the workspace Run the \"Build\" VS Code task, AKA Ctrl+Shift+B Source the overlay Run thesrcnew
terminal command Create a package with a node Run the \"new ament_(python|cmake) package with a node\" VS Code task"},{"location":"reference/ros/#tutorials","title":"Tutorials","text":"We encourage all software members to work through the ROS tutorials that are listed below in order. For tutorials that have both C++ and Python versions, NET members should do the C++ version while CTRL and PATH members should do the Python version.
turtlesim
and rqt
rqt_console
to view logsros2doctor
to identify issuesWe encourage all software members to read the following documentation on key ROS concepts:
There are two major versions of ROS, aptly named ROS 1 and ROS 2. Our previous project, Raye, uses ROS 1 because it was the only version available during her design process. Our new project will use ROS 2, a complete re-design of the framework that tackles the shortcomings of ROS 1 to bring it up to industry needs and standards.3 If you are curious about the changes made in ROS 2 compared to 1, this article is a worthwhile read.
ROS 2 includes the ROS 1 Bridge, a collection of packages that can be installed alongside ROS 1 to help migrate code from ROS 1 to ROS 2. As we will be reusing parts of Raye's codebase, it is essential to know how to use these packages. Until we are completely done with Raye, our preconfigured workspace will have ROS 1, ROS 1 Bridge, and ROS 2 installed.
We encourage all software members work through the ROS 1 Bridge README. For PATH members, the Migrating launch files from ROS 1 to ROS 2 page will be a helpful reference when we do so.
https://docs.ros.org/en/humble/index.html \u21a9
https://www.toptal.com/robotics/introduction-to-robot-operating-system \u21a9
https://ubuntu.com/robotics/what-is-ros \u21a9
For most use cases, you can think of C++ as a superset of C. While this is not technically true, more often than not you are able to write standard C code for a C++ program without issues. However, doing so ignores a lot of the benefits and reasons to use C++.
"},{"location":"reference/cpp/differences/#classes-and-structs","title":"Classes and Structs","text":"In C structs can only contain member variables, but in C++ structs are basically classes but with a default member visibility of public instead of private.
ExampleThe following code blocks are equivalent.
struct foo {\nprivate:\n int x;\n void helper(void);\npublic:\n foo(int y);\n}\n
class foo {\nprivate:\n int x;\n void helper(void);\npublic:\n foo(int y);\n}\n
"},{"location":"reference/cpp/differences/#namespaces","title":"Namespaces","text":"One problem that is prevalent in C concerns the scoping of names. For example, let there be two files A.h
and B.h
and a program ighxy.c
, and let them both contain a float x
and int bar(void)
.
Our program cannot compile because the linker cannot distinguish which bar()
function we want to use! One way to fix this in a C program would be to rename them a_bar()
and b_bar()
. Although this fix seems trivial for this example, applying it to a file that has potentially 100 functions can be a lot more difficult, especially if two files just happen to share the same prefix for their functions!
C++ introduces namespaces to tackle this problem. With namespaces, we can deal with naming conflicts much more easily. Though be aware that namespaces are not necessary everywhere. See the following code snippet to see how they work.
Example CC++ A.hfloat x;\nint bar(void);\n
B.hfloat x;\nint bar(void);\n
ighxy.c#include \"A.h\"\n#include \"B.h\"\n\nint main(void) {\n int a = bar();\n ...\n}\n/* Error, does not compile*/\n
A.hnamespace a {\nfloat x;\nint bar(void);\n}\n
B.hnamespace b {\nfloat x;\nint bar(void);\n}\n
ighxy.cpp#include \"A.h\"\n#include \"B.h\"\n\nint main(void) {\n int a = a::bar();\n int b = b::bar();\n float xa = a::x;\n float xb = b::x;\n /* No problem! */\n ...\n}\n
Warning You may come across something like:
example.cppusing namespace std;\nnamespace io = std::filesystem;\n\nint main(int argc, char* argv[]) {\n bool isDirectory = io::is_directory(argv[1]); // Equivalent to std::filesystem::is_directory(argv[1])\n cout << isDirectory << endl;\n return 0;\n}\n
There are two things going on here.
First, using namespace std
makes all functions and types defined within the standard namespace and included via #include
directives visible to example.cpp
. If you are familiar with Python, the Python equivalent of this would be import std as *
. However, it is considered bad practice to do this as it eliminates the point of using namespaces.
class string {\n // Insert implementation here\n }\n\n int main(void) {\n string ourString = \"Our own string implementation\";\n std::string stdString = \"Standard Library string implementation\";\n ...\n }\n
using namespace std;\n\n // ERROR - multiple definitions of type string\n class string {\n\n }\n
The compiler cannot infer which implementation we want.
Secondly, namespace io = std::filesystem
is basically an alias for the std::filesystem
namespace. This practice is acceptable for long namespace identifiers, but be careful as it can still run into namespace conflicts if your alias is the same as another namespace or alias.
In C, if we want to declare a constant or a function/expression that we want to be evaluated at compile time, we need to use #define
statements. One of the problems with #define
statements is that they perform a simple copy paste wherever they're used. For example:
#define PI 3.14F\n#define AREA_OF_CIRCLE(radius) ((PI) * (radius) * (radius))\n\nint main(void) {\n float area = AREA_OF_CIRCLE(2.5F);\n ...\n}\n
int main(void) {\n float area = ((3.14F) * (2.5F) * (2.5F));\n ...\n}\n
Note
AREA_OF_CIRCLE
is a macro with arguments. If you are confused by it, this resource has a detailed explanation on how they work.
Because of this copy-pasting, you need to be very careful with syntax, sometimes necessitating an ugly do {} while(0)
wrapper. Moreover, symbols declared with #define
are always globally visible, ignoring namespaces!
In C++, the use of constant expressions are preferred.
constexpr float pi = 3.14F;\nconstexpr float area_of_circle(float radius) {\n return pi * radius * radius;\n}\n
Constant expressions do not get copy pasted, and are instead placed in program memory just like a normal variable or function. They also respect namespaces and function scopes, meaning the following code compiles.
Constant Expression Scopingvoid foo(void) {\n constexpr float rand = 123.456;\n ...\n}\n\nvoid bar (void) {\n constexpr float rand = 789.123;\n ...\n}\n
"},{"location":"reference/cpp/differences/#lambdas","title":"Lambdas","text":"Lambdas are primarily useful when you need to register a callback function one time and don't feel it's necessary to write out a full function. They are in no way required though, so do not worry about learning them. However, it's necessary to know that they exist such that you don't get confused when reading code. For more information, go here for Microsoft's explanation.
"},{"location":"reference/cpp/differences/#misc","title":"Misc","text":""},{"location":"reference/cpp/differences/#arrays","title":"Arrays","text":"Using the C++ implementation of arrays is preferred over C arrays. It is simply easier and safer to work with than a standard C array without any performance costs.
ExamplePassing an array to a function an iterating over it
CC++#include \"stdio.h\"\n\nvoid print_contents(int *arr, int size) {\n for (int i = 0; i < size; i++) {\n printf(\"%d\\n\", *arr);\n }\n}\n\nint main(void) {\n int arr[5] = {0, 1, 2, 3, 4};\n foo(arr, 5);\n return 0;\n}\n
We can't even guarantee that the integer pointer arr
is an array! C++ 20 makes passing arrays around a lot simpler. Do not worry about understanding the code shown below. It uses some fairly advanced concepts and exists to illustrate how different such a simple operation can be.
#include <iostream>\n#include <array>\n#include <span>\n\nvoid print_contents(std::span<int> container) {\n for (const auto &e : container) {\n std::cout << e << std::endl;\n }\n}\n\nint main(void) {\n std::array<int, 5> arr = {0, 1, 2, 3, 4};\n foo(arr);\n return 0;\n}\n
The advantages of the C++ version are:
UBC Sailbot's Network Systems team uses C++ for its software. If you know already know C, then you already know the bare minimum to write C++. This is a good starting point, but the additional features C++ provides allow for safer programming practices.
"},{"location":"reference/cpp/start/#for-cc-beginners","title":"For C/C++ Beginners","text":"If you just need to know how C++ is different from C, then see the Differences Between C and C++. You should also look at it if you go through and finish this section.
If you are new to C and C++, then this the best place to start. The tutorials provided in this section will help you learn the fundamentals of the language. Do not feel pressured to do all the tutorials! Just get comfortable with the syntax and the mechanisms of the language.
Note
The hardest part about this will likely be pointers and dynamic memory, so pay close attention to tutorials concerning them! Additionally, dynamic memory requires the usage of pointers, but pointers do not require dynamic memory!
Tip
Dynamic memory is much more prone to error than statically allocated memory, so try to use static allocation whenever possible
Resource Description w3schools Tutorial A structured tutorial that goes through basic concepts in C++. It's good to do up to the section on Classes. YouTube Tutorial If you prefer video tutorial, then this is a comprehensive 4 hour video covering similar concepts to the one above. It is 4 hours long though. Dynamic Memory Overview A page going over how dynamic memory works in C++.Feel free to add other resources other than the ones listed above if you find any that you like!
"},{"location":"reference/cpp/tools/","title":"Tools","text":"A lot goes into making a well structured C++ project, much more than any one team should have to do.
"},{"location":"reference/cpp/tools/#cmake","title":"CMake","text":"CMake is a powerfull build automation tool that makes compiling code for large projects with a lot of interoperating files a lot easier. Steps 1-3 of the official tutorial are great for understanding the basics.
"},{"location":"reference/cpp/tools/#gdb","title":"GDB","text":"The GNU Project Debugger is the most commonly debugger for the C language family. VSCode also has a degree of integration with GDB that allows an easy to use GUI. This GDB cheat sheet has all the GDB comands you will need to know. Be aware the VSCode has GUI buttons for some of these commands that are easier to use.
"},{"location":"reference/cpp/tools/#googletest","title":"GoogleTest","text":"GoogleTest is the C++ unit testing framework we will be using. The GoogleTest Primer is a good place to start.
Example Cached Fibonacci ProgramTest Cached Fibonacci Program cached_fib.h#include <vector>\nclass CachedFib {\npublic:\n void CachedFib(int n);\n int getFib(int n);\nprivate:\n std::vector<int> cache;\n}\n
cached_fib.cpp#include <iostream>\n#include <vector>\n#include \"cached_fib.h\"\n\nvoid CachedFib::CachedFib(int n) {\n cache.push_back(0);\n cache.push_back(1);\n for (int i = 2; i < n; i++) {\n cache.push_back(cache[i - 1] + cache[i - 2]);\n }\n}\n\nint CachedFib::getFib(int n) {\n if (cache.size() < n) {\n for (int i = cache.size(); i < n; i++) {\n cache.push_back(cache[i-1] + cache[i-2]);\n }\n }\n std::cout << cache[n - 1] << std::endl;\n}\n
test_cached_fib.cpp#include \"cached_fib.h\"\n#include \"gtest/gtest.h\"\n\nCachedFib::testFib;\n\nclass TestFib : public ::testing::Test {\nprotected:\n void Setup override {\n // Every time a test is started, testFib is reinitialized with a constructor parameter of 5\n testFib = CachedFib(5);\n }\n}\n\nTEST_F(TestFib, TestBasic) {\n ASSERT_EQ(getFib(5), 3) << \"5th fibonacci number must be 3!\";\n}\n\n// more tests\n
"},{"location":"reference/cpp/tools/#google-protocol-buffer","title":"Google Protocol Buffer","text":"Google Protocol Buffer (Protobuf) is a portable data serialization method. We use it over other methods like JSON and XML because it produces smaller binaries, an important consideration when sending data across an ocean. Unfortunately, there does not seem to be a easy to follow tutorial for using them, but here are the C++ basics. The page is quite dense and can be hard to follow, so do not worry if you do not understand it.
"},{"location":"reference/cpp/tools/#clang","title":"Clang","text":"In its most basic form, Clang is a compiler for the C language family. Clang has multiple benefits like easier portability compared to, for example, GCC. Clang is actually \"half\" the compiler, the other half being LLVM. Without going into unnecessary detail, Clang compiles C++ code to a generic language before LLVM compiles it to machine specific language.
"},{"location":"reference/cpp/tools/#clangd","title":"Clangd","text":"Clangd is the Clang language server. It provides a much more powerful intellisense than the default one used in VSCode's C/C++ extension.
"},{"location":"reference/cpp/tools/#clang-tidy","title":"Clang-Tidy","text":"Clang-Tidy is a linting tool, who's main purpose is to catch potential programming errors caused by bad programming style/practices using just static analysis.
"},{"location":"reference/cpp/tools/#clang-format","title":"Clang Format","text":"An autoformatting tool that makes enforcing style guidelines much easier. When se tup, it corrects formatting as soon as you hit save.
"},{"location":"reference/cpp/tools/#llvm-cov","title":"llvm-cov","text":"We will use llvm-cov to evaluate our test coverage. When used with genhtml, we can generate HTML reports that that show our line, function, and branch coverage line-by-line.
"},{"location":"reference/github/advanced_git/","title":"Advanced Git","text":""},{"location":"reference/github/advanced_git/#tutorial","title":"Tutorial","text":""},{"location":"reference/github/github_actions/","title":"GitHub Actions","text":""},{"location":"reference/github/github_actions/#tutorial","title":"Tutorial","text":""},{"location":"reference/github/workflow/branches/","title":"Developing on Branches","text":"We use branching to work on issues without modifying the main line. This ensures that the main line only contains functional code and handles merge conflicts that arise when multiple people are developing at the same time. For a quick rundown on branching in git, consult the official git documentation.
"},{"location":"reference/github/workflow/branches/#creating-a-branch","title":"Creating a branch","text":"When starting a new issue, you will want to create a new branch for it:
Caution
When creating branches locally, it uses your local copy to create the new branch. Remember to do a git pull
if you intend on using the latest changes from the remote branch you are creating from.
# Switch to main\ngit switch main\n\n# Update your local copy\ngit pull\n\n# Clone a new branch from main\ngit switch -c <branch_name>\n
IMPORTANT: When creating a new branch for an issue, you must create the branch from main
.
When working on a new issue, you will want to create a branch to work on it. We have the following branch naming convention:
<github_username>/<issue_number>-<issue_description>\n
Example
If Jill (GitHub Username: jill99) is going to take on an issue titled \"Fix bug on pathfinding software\" and the issue number is 39, then the branch named can be named something like user/jill99/39-fix-pathfinding-bug
.
If the branch that you are creating is not tied to an issue, then you do not need to put an issue number. A descriptive title will suffice.
"},{"location":"reference/github/workflow/branches/#tracking-and-committing-changes","title":"Tracking and committing changes","text":"All files where new changes have been made must first be \"staged\" in order to make commits:
git add <FILES>\n
Files that are staged will be part of your next commit. Once you are confident in your changes and you are ready to finalize them, then you should commit your changes:
git commit -m \"<commit_message>\"\n
Be sure to add a commit message that is descriptive of the changes that you made. It is encouraged that you make commits often so you can keep track of your changes more easily and avoid overwhelmingly large commits when you look back on your version history.
When you are ready to move your local changes to a remote branch, you want to push to the correct branch and potentially set the upstream if it does not yet exist:
git push -u origin <current_branch_name>\n
"},{"location":"reference/github/workflow/branches/#merging-branches","title":"Merging branches","text":"There may be times where you want to merge two branches together, whether you diverged on some ideas and finally want to synthesize them, or you just want to update your issue's branch with the main branch. In any case, merging branches will be inevitable as part of the development process, so it is essential to understand how to merge branches.
Merge Local BranchMerge Remote Branch# Checkout to destination branch\ngit checkout <dest_branch>\n\n# Merge with local copy of other branch\ngit merge <other_branch>\n
# Checkout to destination branch\ngit checkout <dest_branch>\n\n# Fetch from remote\ngit fetch\n\n# Merge remote copy of other branch\ngit merge origin/<other_branch>\n
Info
Merging a remote branch into its local counterpart using the method above is essentially the same operation as git pull
.
Once the merge operation is complete, your destination branch should have updates both from itself and the other branch that you merge. If you do a git log
, you will also see a new commit that indicates that the merge happened.
Merging two branches is not always easy since the commit history for both branches could look quite different, and therefore conflicting changes can easily be made. If you run into a scenario like this, you may get something like this:
Upon inspecting bar.txt
, we see the following:
Resolving merge conflicts is not always a trivial task, but there are many ways to resolve them which include:
Tip
If you cannot resolve a merge conflict on your own, reach out to your lead for help!
"},{"location":"reference/github/workflow/issues/","title":"Creating Issues","text":"GitHub issues lets us plan and track our work on GitHub.
"},{"location":"reference/github/workflow/issues/#getting-started-with-issue-templates","title":"Getting started with issue templates","text":"An issue is associated with a specific repository. To open the issues page for a given repository, click on the issues tab in the repository navigation bar.
You will see a list of current issues (if any) for the repository. To create a new issue, click on the New issue
button in the upper right corner.
When creating a new issue, you will see a few issue templates. Since issues can be created for a variety of reasons, issues may therefore be structured differently and contain different kinds of information. Issue templates were introduced to give us a quick and structured way to writing issues.
Note
GitHub issues are written using GitHub-flavoured markdown. To add a little spice to your issues, refer to the official GitHub documentation for some quick tips and tricks on how to write awesome markdown!
Click on the Get started
button to open the issue template. For this example, let's go with the New Feature
issue template. Upon opening the issue template, you should see a page like the one below:
At this point, you should give a succinct title and describe the issue in the textbox. You will also see some templated sections to fill out. Try to give only the necessary details to make a clear and concise issue. If you are unsure on how to construct your issue, take a look at current or past issues and ask the software leads for further guidance if necessary.
Finally, feel free to make suggestions on new templates or changing current templates!
Tip
We understand that some issues may need extra sections to describe the issue further, or some of the templated sections might not be relevant at all! Add or remove sections as necessary to get your point across. The goal of the issue templates is to provide guidance, not police your documentation methodologies!
"},{"location":"reference/github/workflow/issues/#adding-issues-to-a-project","title":"Adding issues to a project","text":"We use projects to plan and track the status of our issues and pull requests. To add an issue to an existing project, click on the gear icon in the Projects
section and add it to your desired project. You will almost always want to add your issue to the Software organization project.
To verify that your issue has been added to your desired project, go to the UBC Sailbot organization, go to the Projects
tab on the organization banner, and select the project that it is added to. When added to a project, it should show up under the General
tab (depending on the project, this might not always be the case).
We use milestones to track progress on groups of issues or pull requests that we want to complete by a certain date. Since our projects span over many years, it is important to work incrementally with small, yet achievable goals. If your issue should belong to a milestone, simply add it to a milestone by clicking on the gear icon in the Milestone
section and add it to your desired milestone.
Note
Unlike projects, milestones are strictly associated with a repository.
"},{"location":"reference/github/workflow/issues/#labelling-issues","title":"Labelling issues","text":"GitHub allows us to label our issues so that we can categorize them. It helps us identify at first glance what kind of a problem that an issue aims to solve and which issues are more important. To add a label to your issue, click on the gear icon in the Labels
section and add your desired label(s).
The issue templates will already have labels assigned to them, but you should add or remove labels as you see fit to make them as relevant as possible.
Note
Each repository might have different labels available, so be sure to check out all of the labels at least once in the repository that you are working in. Feel free to suggest additional labels as well!
"},{"location":"reference/github/workflow/issues/#adding-assignees","title":"Adding assignees","text":"Every issue should be assigned to at least one person to work on it. If you are not sure who should be assigned the issue initially, then don't worry about it for now since you can assign someone to the issue later on. To assign someone an issue, click on the gear icon in the Assignees
section and add the desired people.
Once you are finished writing your issue, click on the Submit new issue
button. You should now see your issue in the issues list and in the UBC Sailbot software project.
graph LR\n B[Problem Conception] --> C{Small Fix?};\n C --> |Yes| E[Development];\n C --> |No| D[Issue Creation];\n D --> E;\n E --> F[Pull Request];\n F --> G{Approved?};\n G --> |No| E;\n G --> |Yes| H[Merge PR into Main];
A good development workflow is essential to maintain a robust codebase and stay organized. The above diagram is a high level overview of how our development process works, and parts of this process are explained in subsequent sections.
"},{"location":"reference/github/workflow/overview/#tutorial","title":"Tutorial","text":""},{"location":"reference/github/workflow/overview/#version-control-git","title":"Version control: Git","text":"We use git to help us keep track of the version history of our codebase. Git is a free and open source distributed version control system, and it is commonly used by many developers to keep track of changes to their code over time. As a member of the software team on UBC Sailbot, it is absolutely necessary that you know git. If you are unfamiliar with git, here are a few resources to help you get started:
Resource Description Beginners Tutorial A 30 minute video on git for beginners. Good if you want to learn git quickly and nail all the fundamentals. Pro Git book A textbook on using git. Good if you are a completionist and want to deep dive into how git works (and if you have some time on your hands). Common Git Commands A condensed summary of some common git commands. Good to refer to once you are familiar with the fundamentals of git."},{"location":"reference/github/workflow/overview/#remote-server-github","title":"Remote server: GitHub","text":"We use GitHub as our remote server where we store our codebase. In addition to using it for storage, we also leverage many of GitHub's features to make for a smoother development process. Some examples of features that we use are:
Pull requests are used to verify code functionality and quality of a development branch before merging into the main branch, accomplished through CI and code reviews.
Note
Pull requests are much like issues where we can do many of the same things. This goes for creating comments in markdown, assigning reviewers, adding labels, adding projects, or adding milestones. Sometimes we skip writing an issue when the change is relatively small.
"},{"location":"reference/github/workflow/pr/#creating-a-pull-request","title":"Creating a pull request","text":"To create a pull request in a repository, to go the Pull requests
tab and then click New pull request
:
On the next screen, you need to select the base branch that you are merging into, and the branch that you are comparing. For the most part, the base branch will be the main branch, and the branch that you are comparing will be the issue branch.
Once you have decided on your base and compare branches, click on Create pull request
. You should see the page below (looking in the dropdown menu, you can open the pull request as a draft to avoid notifying reviewers until you are ready):
Notice how this is remarkably similar to the page of an issue. To link a pull request to an issue, simply add <KEYWORD> #<ISSUE NUMBER>
to the initial comment in the pull request. A list of valid keywords can be found here.
Example
\"This issue resolves #49. Please review my pull request!\"
Observe that the right-hand side banner contains the following:
Field Description Reviewers Assign reviewers to review your pull request. Always try to assign at least one reviewer. Assignees Assign the people who worked on the issue. Labels Assign labels to categorize pull requests. Projects Assign a pull request to a project. Milestone Assign a pull request to a milestone.Attention
If you linked the pull request to an issue, you should not add the pull request to a project or a milestone to avoid duplicate cards.
"},{"location":"reference/github/workflow/pr/#merging-into-main","title":"Merging into main","text":"Once the pull request and code reviews are complete, it is time to merge the changes in the pull request into the main branch! However, this can only be done when the following conditions are met:
If all of these conditions are met, confirm that the merge is good to go by clicking Squash and merge
:
A common activity that you will participate in is reviewing pull requests to give your feedback on other's code. You will be notified when you have been requested to review a pull request and should promptly review it as soon as time permits.
In particular, you will most likely be doing the following in a pull request:
At UBC Sailbot, we follow standards in how we code to maintain a clean and comprehensible codebase. This page addresses what conventions we use specifically when programming in Python and the tools to help us maintain these conventions.
"},{"location":"reference/python/conventions/#style-guide","title":"Style guide","text":""},{"location":"reference/python/conventions/#linting","title":"Linting","text":"To ensure that the codebase stays clean, we use flake8, which is a tool for style guide enforcement mostly based off pep8. To automate most of this process, we use autopep8, which is a tool that resolves most style issues. However, there will be some issues that must be resolved by you!
Refer to this guide on how to write readable code in python with the pep8 style guide.
Note
Our CI automatically checks that your code follows the pep8 standard. If it does not, your pull requests will be blocked from being merged until those issues are resolved!
"},{"location":"reference/python/conventions/#type-hinting","title":"Type hinting","text":"Even though Python is a dynamically typed language, newer versions support type hinting. Type hinting catches errors, documents code, improves IDEs and linters, and helps build and maintain a clean software architecture.1 Expanding on how it catches errors, a static type checker such as mypy
can be used.
There is some syntax to get familiar in order to use type checking. We recommend the following resources:
Below are a few examples of using type hinting:
Return the sum of a sequencefrom typing import Sequence, Union\n\n\nNumber = Union[int, float]\n\n\ndef sumseq(seq : Sequence[Number]) -> Number:\n return sum(seq)\n
Function with optional parameters and default values from typing import Optional\n\n\ndef printArgs(a : str, b : str=\"World\", c : Optional[str]=None) -> None:\n print(f\"Value of a: {a}\")\n print(f\"Value of b: {b}\")\n if c is not None:\n print(f\"Value of c: {c}\")\n
Function with custom class class MyClass:\n def __init__(self) -> None:\n pass\n\n\ndef foo(a : MyClass) -> None:\n print(a)\n
Forward referencing a class With __future__
Without __future__
from __future__ import annotations\n\n\ndef foo(a : MyClass) -> None:\n print(a)\n\n\nclass MyClass:\n def __init__(self) -> None:\n pass\n
def foo(a : 'MyClass') -> None:\n print(a)\n\n\nclass MyClass:\n def __init__(self) -> None:\n pass\n
Function that never returns from typing import NoReturn\n\n\ndef bar() -> NoReturn:\n while True:\n print(\"Hello World!\")\n
"},{"location":"reference/python/conventions/#documentation","title":"Documentation","text":"Code is written once and read a thousand times, so it is important to provide good documentation for current and future members of the software team. The major things that we document in our code are:
Ideally, the third point should be avoided as much as possible since we would want our code to be self explanatory. It should be done only when absolutely necessary.
"},{"location":"reference/python/conventions/#generating-docstrings","title":"Generating docstrings","text":"We use a vscode extension called autoDocstring which autogenerates docstrings that we use to document our code. To install this extension, go to the Extensions
tab in vscode and search autoDocstring
in the marketplace.
To generate docstrings, type \"\"\"
at the beginning of the function that you want to document and the template will be generated for you! If you use type hinting, this extention will autofill some of the documentation for you!
Note
The autoDocstring extension only works for functions. It does not work for classes and objects, so documenting these will have to be done manually. Be sure to follow the same format used by functions.
"},{"location":"reference/python/conventions/#example-on-documentation","title":"Example on documentation","text":"It's hard to imagine what good documentation looks like. We provide a few examples below of documenting code using the autoDocstring extension. The extension uses Google style docstrings by default.
Documentation example on a functionfrom typing import List\ndef inner_product(v1 : List[float], v2 : List[float]) -> float:\n \"\"\"\n Computes the inner product between two 1D real vectors. Input vectors should have the\n same dimensions.\n\n Args:\n v1 (List[float]): The first vector of real numbers.\n v2 (List[float]): The second vector of real numbers.\n\n Returns:\n float : The inner product between v1 and v2\n \"\"\"\n assert (len(v1) == len(v2)), \"Input lists must have same length\"\n\n # Iterate through elementwise pairs\n summation = 0\n for e1, e2 in zip(v1, v2):\n summation += (e1 * e2)\n return float(summation)\n
Documentation example with a stack from typing import Any\nclass Stack:\n\n \"\"\"\n This class represents a stack, which is an abstract data type that serves as a collection of\n elements. The stack is a LIFO datastructure defined by two main operations: Push and Pop.\n\n Attributes:\n __stack (List[Any]): A list containing the elements on the stack.\n \"\"\"\n\n def __init__(self):\n \"\"\"\n Initializes the Stack object.\n \"\"\"\n self.__stack = []\n\n def push(self, element : Any) -> Any:\n \"\"\"\n Pushes an element to the top of the stack.\n\n Args:\n element (Any): The element to be pushed on to the stack.\n \"\"\"\n self.__stack.append(element)\n\n def pop(self) -> Any:\n \"\"\"\n Removes the element at the top of the stack and returns it. If the stack is empty,\n then None is returned.\n\n Returns:\n Any, NoneType: The element at the top of the stack.\n \"\"\"\n if self.is_empty():\n return None\n else:\n return self.__stack.pop()\n\n def is_empty(self) -> bool:\n \"\"\"\n Determines whether the stack is empty or not.\n\n Returns:\n bool: Returns True if the stack is empty, and False otherwise.\n \"\"\"\n empty = (len(self.__stack) == 0)\n return empty\n\n def __len__(self) -> int:\n \"\"\"\n Gets the number of elements on the stack.\n\n Returns:\n int: The number of elements on the stack.\n \"\"\"\n length = len(self.__stack)\n return length\n
For more examples, see Example Google Style Python Docstrings.
https://realpython.com/lessons/pros-and-cons-type-hints/ \u21a9
We use Python 3 to write the majority of our software at UBC Sailbot. Pathfinding and Controls mainly use Python 3, so it is critical that you are familiar with the language if you are on one of these sub-teams.
"},{"location":"reference/python/start/#python-tutorials","title":"Python tutorials","text":"We understand that not everyone who joins Sailbot has Python in their toolkit, nor do we expect it either! Whether you are learning Python for the first time or you just want to brush up, we have provided some resources below. You may not learn absolutely everything from the resources below, but it is a good starting point. You will mostly learn through doing, as you would with most technical skills!
Resource Description The Python Tutorial The official python tutorial. Good if you have some time on your hands and you are a completionist. Sections 1 - 5 and 9 are the most relevant. w3schools Tutorial Good if you want a more brief introduction to Python. It breaks down a lot of concepts into sections. Everything up to Python Classes/Objects is relevant. YouTube Tutorial If you like video tutorials, then we recommend this tutorial. This video is about 5 hours long, but it pretty much covers everything that you'll need to know for Python and there are some hands on projects. Shorter YouTube Tutorial A shorter alternative YouTube tutorial condensed into 1 hour. It covers less material but still covers many of the essentials. CodingBat Practice Good resource to put your Python skills to practice on some simple coding problems. Note that this resource does not teach you python.Feel free to add other resources other than the ones listed above if you find any that you like!
"},{"location":"reference/python/virtual-environments/","title":"Virtual Environments","text":"The Python virtual environment is a tool for dependency management and project isolation. They solve many common issues, including:
Dependency Resolution: A project might want a package with version A while another project might want a package with version B. With a virtual environment, you can separate which packages that you want to use for a given project.
Project Isolation: The environment for your project is self-contained and reproducible by capturing all dependencies in a configuration file.
Housekeeping: Virtual environments allow you to keep your global workspace tidy.
There are two main methods of creating virtual environments: virtualenv and Anaconda. Each have their own benefits and drawbacks. Here are some differences between the two:
Virtualenv Anaconda Environment files are local. Environment files are available globally. Must activate environment by giving the path. Can activate the environment without knowing the path, but only the name. Can only usepip
to install packages. Can either use pip
or built-in conda
package manager. Installation is very simple. Installation takes more effort. Can only install python packages. In addition to packages, you can download many data science tools. We recommend virtualenv over Anaconda because of its simplicity. However, feel free to appeal to your preferences.
"},{"location":"reference/python/virtual-environments/#installation","title":"Installation","text":"Virtualenv AnacondaIf you already have python and the pip package manager installed, just execute the following:
Using pip to install virtualenvpip install virtualenv\n
Go to the official Anaconda website and follow the installation instructions for your operating system.
"},{"location":"reference/python/virtual-environments/#using-virtual-environments","title":"Using virtual environments","text":"The name of a virtual environment is configurable. For the purposes of this site, we will use env
as the environment name unless specified otherwise.
Since virtualenv creates the environment directory in a specific location, make sure that you are in the located in the project that you want to work on.
Create virtual environment with virtualenv# Go to desired location\ncd <PATH TO DIRECTORY>\n\n# Create the environment with the name env\npython3 -m venv env\n
Verify that your environment is created by examining your current directory and look for the directory that matches the name of your virtual environment.
Since the environment will be available globally, there is no need to go to a specific location to create it.
Create virtual environment with Anaconda# Create environment with name env and python version\nconda env create -n env python=<PYTHON VERSION NUM>\n
If you don't specify a python version, the default is the version you used when you downloaded and installed Anaconda. Verify that your environment is created by executing conda env list
.
To use the virtual environment, you must activate it.
Virtualenv Anaconda Windows macOS Linux Activation for Windowsenv\\Scripts\\activate\n
Activation for macOSsource env/bin/activate\n
Activation for Linuxsource env/bin/activate\n
Activation for Anacondaconda activate env\n
After activating your virtual environment, you might see (env)
on your terminal before or after your current line. Now you are in your virtual environment!
Any dependencies that you install while your virtual environment is activated are only available in your virtual environment. If you deactivate your environment and try to use those dependencies, you will find that you will get errors because they will not be found unless you install those dependencies in the other environment!
Virtualenv AnacondaUse the pip
package manager to install python dependencies. Before installing any Python dependencies, it is good practice to upgrade pip
:
pip install --upgrade pip\n
Now, install any Python dependencies pip
:
pip install <PACKAGE>\n
Option 1: pipOption 2: conda Use the pip
package manager to install python dependencies.
# Install pip using conda\nconda install pip\n\n# Install python packages using pip\npip install <PACKAGE>\n
Use the built-in conda
package manager to install python dependencies.
conda install -c <CHANNEL> <PACKAGE>\n
Sometimes, installing a package like this simply won't work because you are not installing from the correct channel. You usually will have to google the command to use in order to install your package correctly because it usually comes from a specific channel that you don't know about. Some common channels to try are:
When you are finished using your virtual environment, you will need to deactivate it.
Virtualenv Anaconda Deactivate virtualenv environmentdeactivate\n
Deactivate anaconda environmentconda deactivate\n
"},{"location":"reference/python/virtual-environments/#reproducing-your-virtual-environment","title":"Reproducing your virtual environment","text":"When you want to share your code with others, it is important for others to be able to reproduce the environment that you worked in. We discuss two topics in this section: exporting your environment and reproducing the environment.
"},{"location":"reference/python/virtual-environments/#exporting-your-virtual-environment","title":"Exporting your virtual environment","text":"In order to reproduce your virtual environment, you need to export some information about your environment. Be sure to follow the instructions below while your environment is activated.
Virtualenv AnacondaYou will create a requirements.txt
file, which essentially lists all of your python dependencies in one file:
pip freeze > requirements.txt\n
The pip freeze
command prints all of your pip dependencies, and > requirements.txt
redirects the output to a text file.
Anaconda uses configuration files to recreate an environment.
Windows macOS LinuxExecute the following command to create a file called environment.yml
:
conda env export > environment.yml\n
Then, open the environment.yml
file and delete the line with prefix:
.
Execute the following command to create a file called environment.yml
:
conda env export | grep -v \"^prefix: \" > environment.yml\n
Execute the following command to create a file called environment.yml
:
conda env export | grep -v \"^prefix: \" > environment.yml\n
"},{"location":"reference/python/virtual-environments/#reproducing-the-environment","title":"Reproducing the environment","text":"You can reproduce your virtual environment when given the information about it. The steps above tell you how to extract the information, and now we will use that information to recreate the virtual environment. Remember to deactivate the current environment before making a new environment.
Virtualenv AnacondaWe use the requirements.txt
file that we generated earlier to recreate the environment.
# Create the new environment\npython -m venv <NEW ENV NAME>\n\n# Activate the environment\nsource <NEW ENV NAME>/bin/activate\n\n# Install dependencies\npip install -r <PATH TO requirements.txt file>\n
We use the environment.yml
file that we generated earlier to recreate the environment.
# Create the new environment with the dependencies\nconda env create -f <PATH TO environment.yml> -n <ENV NAME>\n
"},{"location":"reference/python/virtual-environments/#official-references","title":"Official references","text":"In this section, we summarized what virtual environments are, why they are used, and how to use them. We did not cover all of the functions of virtual environments, but feel free to consult the official references to learn about virtual environments more in depth.
This section explains the most unfamiliar fields that we receive from the AIS.
"},{"location":"reference/sailing/ais_terms/#mmsi-aka-id","title":"MMSI a.k.a ID","text":"A 9-digit, unique identification number for the ship.
"},{"location":"reference/sailing/ais_terms/#cog-course-over-ground","title":"COG: Course over Ground","text":"The direction the boat is travelling, relative to the sea floor. This is the direction of the rate of change of the Track Made Good.
This is measured with the navigational angle convention, where 0\u00b0 is towards the North, and angles increase in the clockwise direction. If we make the slight simplification of neglecting the effect of the wind, then
The speed the boat is travelling at, relative to the sea floor. This is the magnitude of the rate of change of the Track Made Good.
\\(\\begin{align*} \\text{SoG} &= \\left|\\frac{d}{dt} \\overrightarrow{(\\text{Track Made Good})} \\right|\\\\ \\end{align*}\\)
If we make the slight simplification of neglecting the effect of the wind, then
The angular velocity of the boat (how fast it's turning), measured in degrees per minute.
"},{"location":"reference/sailing/boat_parts/","title":"Parts of a Sailboat","text":"This page names some important parts of a sailboat, and explains what the part is for. Read the descriptions of the parts below, and refer to the image to see where the part fits in.
"},{"location":"reference/sailing/boat_parts/#hull","title":"Hull","text":"The Hull is the \"boat\" part of the boat, which displaces water to create buoyancy. The following parts of the boat are attached to the hull:
It is also helpful to know the names of the following \"regions\" of the hull:
The image below shows a birds-eye view of the outline of a hull of a sailboat, where the \"regions\" of the hull are labeled.
"},{"location":"reference/sailing/boat_parts/#jib","title":"Jib","text":"The Jib is the sail located near the bow, and is the smaller of the two sails.
The Mast is the long vertical pole which connects to hull. It holds up the sails and some instruments.
The following instruments are at the top of the mast:
The mast is held upright by three lines:
The Main Sail is the larger of the two sails, and is located aft of the mast. Most of the boat's propulsion comes from the main sail.
Hopefully this section helped you gain familiarity with some common sailing terms. It likely feels like this section contains a lot of new information. It's unrealistic to remember it all perfectly, but make an effort to remember the terms which are Bolded and Italicized.
"},{"location":"reference/sailing/boat_parts/#keywords-on-this-page","title":"Keywords on this Page","text":"This section covers some other useful information.
"},{"location":"reference/sailing/miscellaneous/#wind-direction-convention","title":"Wind Direction Convention","text":"Generally speaking, there are two ways to use an angle to describe the wind direction.
In sailing, we normally talk about \"where the wind is coming from\". Somehow this ends up being more intuitive when talking about maneuvers or sail angle adjustments.
However, when describing the wind as a vector, it can make more sense for the vector to represent the actual speed and direction the air is flowing. Make sure to document which convention you are using in your work when its applicable, and don't be afraid to ask someone to clarify which convention they are using in their work.
"},{"location":"reference/sailing/miscellaneous/#navigation-terms","title":"Navigation Terms","text":""},{"location":"reference/sailing/miscellaneous/#heading","title":"Heading","text":"In navigation generally (outside of Sailbot), the Heading is the direction the bow of the boat is pointing towards. Headings are typically (but not always at Sailbot) measured relative to true North in the clockwise direction.
"},{"location":"reference/sailing/miscellaneous/#bearing","title":"Bearing","text":"A Bearing is used to describe one point in relation to another: the Bearing of point \"A\" from point \"B\" is the direction you would would look towards if you wanted to see point \"A\" while standing at point \"B\". A Range is the distance between points \"A\" and \"B\", so that a Bearing and Range together can locate point \"A\" relative to point \"B\" in polar co-ordinates. There are two main ways of measuring bearings:
In the example below, the boat \"B\" has a Heading (H) of 30\u00b0. The True Bearing (\\(B_t\\)) of the Lighthouse \"A\" from the boat is 90\u00b0. The Relative Bearing (\\(B_r\\)) of the lighthouse from the boat is 60\u00b0.
"},{"location":"reference/sailing/miscellaneous/#track-made-good","title":"Track Made Good","text":"Boats do not necessarily travel in the same direction as their Heading, due to the effects of ocean current and wind. The path the boat has traveled relative to the sea floor is called the Track Made Good. This is the same as if you measured motion compared to land or with a GPS.
"},{"location":"reference/sailing/miscellaneous/#heading-and-bearing-in-raye-project","title":"Heading and Bearing in Raye Project","text":"In Sailbot's Raye project, Heading and Bearing are used to refer to different conventions for describing which way the boat is pointing. The following 3 pieces of information are needed to unambiguously define an angle measuring convention:
Some common examples of angle measuring conventions which we use are:
The specific angle conventions which we call Heading and Bearing can be ambiguous, and may be subject to change, so they are deliberately omitted here. Refer to the applicable source code to determine what the angle conventions are.
"},{"location":"reference/sailing/miscellaneous/#true-apparent-and-boat-wind","title":"True, Apparent, and Boat Wind","text":"In the example below, suppose the wind is blowing from the North at 4 m/s, and suppose the boat is moving towards the East at 3 m/s.
In the Types of Turn page, we discussed how a Tack is a type of turn. Weirdly, the word \"tack\" actually has two more distinct meanings in sailing. The word \"Tack\" can refer to:
In order to make high-quality contributions to Sailbot's Software teams, it is extremely helpful to have some understanding of sailing. This section introduces important parts of a sailboat, explains the 4 types of turns, discusses upwind and downwind sailing, and covers some other helpful knowledge.
In this section, terms which are Bolded and Italicized are the most important terms to know. These terms are listed at the bottom of each page. Terms that are only Italicized are other helpful sailing terms. Words that are bolded are meant to be emphasized, but are not necessarily considered important vocabulary.
"},{"location":"reference/sailing/overview/#tutorial","title":"Tutorial","text":""},{"location":"reference/sailing/points_of_sail/","title":"Points of Sail","text":"In sailing, we sometimes talk about different angles that we can sail on with respect to the wind. Ranges of angles which are close together have special names. These ranges are called points of sail. The discussion below coveres the most important points of sail for software members to understand.
Notice how for higher points of sail (points of sail closer to straight into the wind), the sail is pulled tightly in to the boat. If the boat is on a lower point of sail, the sails should be let further out of the boat. For any point of sail, there is an optimum angle that the sail should be adjusted to. If the sails are adjusted too far in or too far out, the boat will not go as fast as it could if the sails were adjusted correctly.
"},{"location":"reference/sailing/points_of_sail/#irons","title":"Irons","text":"The range of angles where the boat is roughly pointing straight into the wind are called Irons, or the No-Go Zone. If the boat is pointing in these directions, the sails will be flapping regardless of how the sheets are adjusted. When the sails are flapping, they are not catching the wind in a way that can propell the boat forwards. When the boat looses propulsion, water stops flowing over the rudder, and the boat loses steering. This is why we want our sailbots to avoid being stuck in irons.
"},{"location":"reference/sailing/points_of_sail/#upwind-sailing","title":"Upwind Sailing","text":"If we want to sail to a destination that is not on too high or low of an angle upwind or downwind from our starting position, we can just point our boat in that direction, adjust our sails, and go there.
However, sometimes we want to sail to a destination that is straight upwind of our starting position. To get there, we will need to do upwind sailing. Since we can't point our boat directly into the wind, we need to sail on an angle on the edge of irons. We will need to tack back and forth every now and then if we want to go directly upwind. The point of sail on the edge of Irons is called Close Hauled.
"},{"location":"reference/sailing/points_of_sail/#downwind-sailing","title":"Downwind Sailing","text":"Raye also avoids sailing straight downwind. This means that to reach a goal downwind of the starting position, we need to gybe back and forth in a zig-zag pattern. The point of sail straight downwind is called a run, and the next point of sail higher than a run is called a broad reach.
"},{"location":"reference/sailing/points_of_sail/#keywords-on-this-page","title":"Keywords on this Page","text":"In sailing, there are 4 distinct types of turns. Read the descriptions below, and observe how they fit into the diagrams.
Note that any of these types of turn can be done in either the clockwise or counter-clockwise directions.
"},{"location":"reference/sailing/turning/#classifying-types-of-turns-summary","title":"Classifying Types Of Turns Summary","text":"The following flowchart summarizes how to distinguish between different types of turns. Note:
graph LR\n B[Classify a Turn] --> C{Does the sail change<br/>sides during the turn?};\n C --> |Yes| E{Which end of<br/>the boat is upwind<br/>during the turn?};\n C --> |No| D{Does the<br/>boat point higher<br/>or lower at the end<br/>of the turn?};\n D --> |Higher| F[Heading Up];\n D --> |Lower| G[Bearing Off];\n E --> |Bow| H[Tack];\n E --> |Stern| I[Gybe];
The diagrams in this section show outlines of the hull of a boat and its main sail going through turns. As is common in these types of diagrams, assume that the wind is blowing down from the top of the screen unless there is an arrow that indicates otherwise.
"},{"location":"reference/sailing/turning/#heading-up","title":"Heading Up","text":"When the boat makes any turn as follows, it is called Heading Up:
Unlike some of the other turns listed here, heading up can be a large turn or a small course adjustment of just a few degrees.
The image below shows a boat heading up. Notice how the sail stays on the starboard side of the boat.
"},{"location":"reference/sailing/turning/#bearing-off","title":"Bearing Off","text":"When the boat makes any turn as follows, it is called Bearing Off:
Like heading up, bearing off can be a small course adjustment.
"},{"location":"reference/sailing/turning/#tacking","title":"Tacking","text":"When the boat makes any turn as follows, it is called a Tack or Tacking:
Notice how at some point throughout this turn, the boat will be pointing straight into the wind. While the boat points nearly straight into the wind, the sails don't generate any forward propulsion. This means that a tack must be a large (at least ~90\u00b0) turn all at once, so that the boat's momentum carries it through the range of angles where it does not get propulsion.
"},{"location":"reference/sailing/turning/#gybing","title":"Gybing","text":"When the boat makes any turn as follows, it is called a Gybe or Gybing.
When sailing on most angles relative to the wind, the sail is always blown to the downwind side of the boat. However, sailing nearly straight downwind, both sides of the boat are equally \"downwind\" relative to eachother. This means that the sail can be on either side of the boat.
The sail propells the boat throughout a gybe, so it is possible to conduct the turn more gradually than a tack. However, because the sail can be on either side, the sails can switch sides in an uncontrolled way as the boat moves in the waves. For this reason, Raye avoids sailing on angles close to straight downwind, and gybes by doing a quick ~60\u00b0 turn.
Note that \"gybe\" is the spelling used in Canadian and British english, whereas in American english it is spelled \"Jibe\"
"},{"location":"reference/sailing/turning/#combinations-of-turns","title":"Combinations of Turns","text":"Of course, it is possible to do two or more of these types of turns in one continuous motion. What two types of turns does the boat do in the image below?
Answer: In the turn shown by the first arrow, the sail stays on the port side of the boat while it steers to point further downwind. This means that the first part of the maneuver is bearing off. In the next part of the maneuver, the sail changes sides and the stern of the boat is upwind of the bow. This part of the maneuver is a gybe.
"},{"location":"reference/sailing/turning/#keywords-on-this-page","title":"Keywords on this Page","text":"Welcome to the UBC Sailbot software team docs
Looking to get started with running the Sailbot codebase? Start by setting up the Sailbot Workspace:
Getting Started
"},{"location":"#what-information-is-on-this-website","title":"What information is on this website?","text":"Information on our current project is contained on this website. In particular, information on each of our major software projects are provided in detail.
Current Project Overview
References to the software tools that we use are also provided on this website. This includes basic information on these tools, how we use these tools on UBC Sailbot, and external links to helpful references and tutorials.
Software Team References
"},{"location":"#who-is-this-website-for","title":"Who is this website for?","text":"The docs site is primarily for the members on the UBC Sailbot software team. However, curious members of the public and/or those who are interested in contributing to our open source software would also benefit from this site.
"},{"location":"#prospective-members","title":"Prospective Members","text":"Are you a member of the UBC community? Are you interested in what we do at UBC Sailbot? We are always looking for motivated students to help us tackle the challenge of autonomous sailing. Learn more below!
Software Team Posting
Apply to join UBC Sailbot
"},{"location":"about_us/","title":"About Us","text":"UBC Sailbot is an engineering design team at The University of British Columbia that designs, constructs, and tests autonomous sailboats. We have 3 technical sub-teams: Mechanical, Electrical, and Software.
This repository, sailbot_workspace, contains all the code, infrastructure, and documentation for the project we are currently working on, Polaris.
To learn more about what the UBC Sailbot Software Team does, read our Team Posting. If you are a UBC student interested in joining, you can apply here.
"},{"location":"current/overview/","title":"Current Project Overview","text":"Our current project, Polaris, is an autonomous research vessel capable of collecting oceanic and atmospheric data. With our expertise in autonomous sailing, the goal is to monitor the health of our oceans while collaborating with stakeholders and researchers involved in climate science and oceanography.
The software team is responsible for designing, implementing, and testing the software system of our autonomous sailboats. We work on both low-level and high-level integration, from interfacing with sensors to planning sea routes with pathfinding algorithms.
"},{"location":"current/overview/#dataflow","title":"Dataflow","text":"The software architecture for our next autonomous sailboat is split across two computers: the on board computer on board and the remote server off board. The following paragraphs will follow the flow of data between the software components (bolded) on each computer.
On the remote server, global pathfinding uses the A* pathfinding algorithm to create a sailing path, a list of global waypoints from the current position to destination. Global sailing paths are sent via the Remote Transceiver to the Local Transceiver on the on board computer.
On the on board computer, the CAN Transceiver receives GPS and wind data from their respective sensors. This raw data is filtered before being used in the other software components. Local Pathfinding uses GPS and wind data, as well as the global path and AIS data from the AIS Receiver, to create a local path, a list of local waypoints from the current position to the next global waypoint. The Controller uses wind data and the relative bearing to the local path to adjust the rudder and sails accordingly. The state of the boat and research data we collect is sent via the Local Transceiver to the Remote Transceiver on the remote server.
Back on the remote server, the Website presents the boat state and research data for monitoring and analysis purposes. The Remote Transceiver additionally includes manual overrides such as resetting the boat state and modifying the global path.
As for the communication mediums, the computers communicate via satellite, and components on the on board computer communicate through the Robot Operating System framework, or ROS for short.
For software development purposes, all software components will be able to run and communicate with each other locally. To accomplish this, we will:
In these diagrams, the bubbles represent components of our software system, and the direction of arrows connecting the bubbles represent the flow of data between them. The color of the bubbles denote the sub-team leading their development:
Components that are used in both the production and development environments are darker, while ones that are only used in one are lighter.
Interacting with the diagram
Source code
The source code for Boat Simulator can be found in src/boat_simulator
. Its README has been copied below.
UBC Sailbot's boat simulator for the new project. This repository contains a ROS package boat_simulator
. This README contains only setup and run instructions. Further information on the boat simulator can be found on the software team's docs website.
The boat simulator is meant to be ran inside the Sailbot Workspace development environment. Follow the setup instructions for the Sailbot Workspace here to get started and build all the necessary ROS packages.
"},{"location":"current/boat_simulator/overview/#run","title":"Run","text":"The launch/
folder contains a ROS 2 launch file responsible for starting up the boat simulator. To run the boat simulator standalone, execute the launch file after building the boat_simulator
package:
ros2 launch boat_simulator main_launch.py [OPTIONS]...\n
To see a list of options for simulator configuration, add the -s
flag at the end of the above command.
Run the test
task in the Sailbot Workspace. See here on how to run vscode tasks.
Source code
The source code for Controller can be found in src/controller
. Its README has been copied below.
UBC Sailbot's controller for the new project. This repository contains a ROS package controller
. This README contains only setup and run instructions. Further information on the controller can be found on the software team's docs website.
The controller is meant to be ran inside the Sailbot Workspace development environment. Follow the setup instructions for the Sailbot Workspace here to get started and build all the necessary ROS packages.
"},{"location":"current/controller/overview/#run","title":"Run","text":"The launch/
folder contains a ROS 2 launch file responsible for starting up the controller. To run the controller standalone, execute the launch file after building the controller
package:
ros2 launch controller main_launch.py [OPTIONS]...\n
To see a list of options for configuration, add the -s
flag at the end of the above command.
Run the test
task in the Sailbot Workspace. See here on how to run vscode tasks.
Source code
The source code for Custom Interfaces can be found in src/custom_interfaces
. Its README has been copied below.
UBC Sailbot's custom interfaces ROS package. To add custom_interfaces
to another ROS package, follow the instructions here.
The terminology that we use in this document are the following:
.msg
or .srv
file associated with that interface.ROS messages and services used across many ROS packages in the project.
"},{"location":"current/custom_interfaces/overview/#project-wide-external-interfaces","title":"Project-wide External Interfaces","text":""},{"location":"current/custom_interfaces/overview/#project-wide-internal-interfaces","title":"Project-wide Internal Interfaces","text":"Interface Used In HelperAISShip AISShips HelperBattery Batteries HelperDimension HelperAISShip HelperGenericSensor GenericSensors HelperHeading DesiredHeading, GPS, HelperAISShip HelperLatLon GPS, HelperAISShip, Path HelperROT HelperAISShip HelperSpeed GPS, HelperAISShip, WindSensor"},{"location":"current/custom_interfaces/overview/#boat-simulator-interfaces","title":"Boat Simulator Interfaces","text":"ROS messages and services used in our boat simulator.
"},{"location":"current/custom_interfaces/overview/#boat-simulator-external-interfaces","title":"Boat Simulator External Interfaces","text":"Topic Type Publisher Subscriber(s)mock_kinematics
SimWorldState Simulator Physics Engine Simulator Visualizer"},{"location":"current/custom_interfaces/overview/#boat-simulator-actions","title":"Boat Simulator Actions","text":"Action Client Node Server Node SimRudderActuation Simulator Physics Engine Simulator Low Level Controller SimSailTrimTabActuation Simulator Physics Engine Simulator Low Level Controller"},{"location":"current/custom_interfaces/overview/#resources","title":"Resources","text":""},{"location":"current/custom_interfaces/overview/#common-interfaces","title":"Common Interfaces","text":"The ROS2 common_interfaces repository defines a set of packages which contain common interface files. Since we are using the Humble version of ROS2, see the humble
branch. These interfaces can be used in this repository or as a reference for ideas and best practices.
For more detail on the usefulness of each package, see this issue comment. If you are interested in creating your own custom message or service, see the ROS Humble documentation.
"},{"location":"current/local_pathfinding/overview/","title":"Overview","text":"Source code
The source code for Local Pathfinding can be found in src/local_pathfinding
. Its README has been copied below.
UBC Sailbot's local pathfinding ROS package
"},{"location":"current/local_pathfinding/overview/#run","title":"Run","text":"Using main launch file: ros2 launch local_pathfinding main_launch.py
Launch arguments are added to the run command in the format <name>:=<value>
.
log_level
Logging level A severity level (case insensitive)"},{"location":"current/local_pathfinding/overview/#server-files","title":"Server Files","text":"The server files: get_server.py
and post_server.py
are basic http server files which are used for testing the global_path module's GET and POST methods.
Source code
The source code for Network Systems can be found in src/network_systems
. Its README has been copied below.
This repository contains the source code for all of UBC Sailbot's Network Systems programs. It is made to work as part of Sailbot Workspace, and is not meant to be built as an independent project.
"},{"location":"current/network_systems/overview/#setup","title":"Setup","text":"For comprehensive setup instructions, follow our setup guide.
"},{"location":"current/network_systems/overview/#building","title":"Building","text":"Option A: With sailbot_workspace open, invoke the VSCode build
or debug
task.
Option B: Run /workspaces/sailbot_workspace/build.sh
Instructions found here.
For example:
ros2 launch network_systems main_launch.py\n
This is the best option if multiple modules need to be run at once. Launch configurations are found under the config folder. These configurations define which modules to enable/disable and what parameters to use.
"},{"location":"current/network_systems/overview/#ros-run","title":"ROS Run","text":"If you just want to run a single module, then this is a direct and easy way to do it.
For example:
ros2 run network_systems example --ros-args -p enabled:=true\n
"},{"location":"current/network_systems/overview/#binary","title":"Binary","text":"Not recommended as you cannot pass ROS parameters, so modules may not work by default. Binaries for each module found under projects can be found under /workspaces/sailbot_workspace/build/network_systems/projects/{module_name}/{module_name}
.
For example:
/workspaces/sailbot_workspace/build/network_systems/projects/example/example\n
"},{"location":"current/network_systems/overview/#testing","title":"Testing","text":"Unit tests specific to Network Systems is done using GoogleTest. Unit tests are defined per module. For example, under projects/example/test/.
"},{"location":"current/network_systems/overview/#run-all-tests","title":"Run All Tests","text":"Option A: With sailbot_workspace open, invoke the VSCode test
task.
Option B: Under the sailbot_workspace directory, run /workspaces/sailbot_workspace/scripts/test.sh
Both options will run all of UBC Sailbot's tests, including those from other projects. More often than not, this is unnecessary.
"},{"location":"current/network_systems/overview/#run-and-debug-specific-tests","title":"Run and Debug Specific Tests","text":"This is the preferred way to run and debug tests. When you open a test source file like the example's, there will be green arrows next to each TEST_F
macro. Clicking a double green arrow runs a test suite, while clicking single green arrow runs one unit test. Right clicking either arrow will open a prompt with a debug test option. When running a test via the debug option, we can set breakpoints and step through our code line by line to resolve issues.
This convenient testing frontend is thank's to the TestMate extension.
Warning: Large failing tests can crash VSCode. If this happens, either lower the size of the tests (ex. reduce the number of iterations) or run the test binary directly.
"},{"location":"current/network_systems/overview/#run-test-binaries","title":"Run Test Binaries","text":"Test binaries for each module found under projects can be found under /workspaces/sailbot_workspace/build/network_systems/projects/{module_name}/test_{module_name}
.
For example:
/workspaces/sailbot_workspace/build/network_systems/projects/example/test_example\n
"},{"location":"current/sailbot_workspace/overview/","title":"Overview","text":"Source code
The Sailbot Workspace README has been copied below.
"},{"location":"current/sailbot_workspace/overview/#sailbot-workspace","title":"Sailbot Workspace","text":"This repository will get you set up to develop UBCSailbot's software on VS Code. It is based on athackst's vscode_ros2_workspace.
"},{"location":"current/sailbot_workspace/overview/#features","title":"Features","text":"An overview of Sailbot Workspace's features can be found below. See our docs site for how to use these features.
"},{"location":"current/sailbot_workspace/overview/#style","title":"Style","text":"C++ and Python linters and formatters are integrated into Sailbot Workspace:
The ament linters are configured to be consistent with the ROS style guide.
"},{"location":"current/sailbot_workspace/overview/#dev-container","title":"Dev Container","text":"Dev Containers enable us to use a Docker container as a fully-featured development environment containing all our configuration and dependencies. Our Dev Container configuration can be found in .devcontainer/
.
Workspaces are VS Code instances that contain one or more folders. Our workspace configuration file can be found at sailbot.code-workspace
.
Our software spans many repositories: software team repositories. Multi-root workspaces make it easy to work with multiple repositories at the same time. Our roots are defined in the folders
section of our workspace file.
Launch configurations have been created to debug our software. They are defined in the launch
section of our workspace file.
Tasks provide an alternative to memorizing the multitude of CLI commands we use to setup, build, lint, test, and run our software. They are defined in tasks
section of our workspace file.
Actions were used to build our Docker containers and lint and test our code the same way it is done locally in Sailbot Workspace on GitHub. We use a reusable workflow to create a single source of truth for our tests across all our repositories. Our CI can be found in .github/workflows/
.
This repository supports user-specific configuration files. To set this up, see How to use your dotfiles.
"},{"location":"current/sailbot_workspace/overview/#run-rayes-software","title":"Run Raye's Software","text":"Raye was our previous project. Her software can be run in the raye
branch following the instructions in How to run Raye's software. The initial differences between the main
and raye
branches are summarized in this PR.
Further documentation, including setup and run instructions, can be found on our Docs website.
"},{"location":"current/sailbot_workspace/overview/#tutorial","title":"Tutorial","text":"Disclaimer
This tutorial was done a while ago, so some parts may no longer be relevant. For the most up to date information, consult the docs pages and the software leads.
"},{"location":"current/sailbot_workspace/scripts/","title":"Scripts","text":"Source code
Our scripts can be found in scripts
. Its README has been copied below.
All scripts in this directory should be able to be run with ./path/to/script
(excluding arguments). For this to work, the script will need to have a shebang and be executable. For more details, see this tutorial.
ament-lint.sh
","text":"Script to lint source code in all ROS packages.
"},{"location":"current/sailbot_workspace/scripts/#buildsh","title":"build.sh
","text":"Script to build all ROS packages in the Sailbot Workspace.
"},{"location":"current/sailbot_workspace/scripts/#clang-tidysh","title":"clang-tidy.sh
","text":"Script to run Clang-Tidy using ament_clang_tidy.py
.
run_virtual_iridium.sh
","text":"./run_virtual_iridium.sh <(optional) webhook server url> <(optional) virtual iridium http server port>\n
Creates a pair of socat sockets $LOCAL_TRANSCEIVER_TEST_PORT
and $VIRTUAL_IRIDIUM_PORT
and binds the latter to a virtual iridium server running on localhost:8080, which substitutes the Rockblock HTTP server used in deployment. Allows testing of satellite code without needing physical hardware.
Optional argument - webhook server url:
http://127.0.0.1:8081
, which assumes fully local testing.Optional argument - virtual iridium server port
$LOCAL_TRANSCEIVER_TEST_PORT
acts as the serial port for AT commands. For example, to test via CLI:
./run_virtual_iridium.sh
$LOCAL_TRANSCEIVER_TEST_PORT
without extra debug messages, in a new terminal run cat $LOCAL_TRANSCEIVER_TEST_PORT
. What you see output from this command will be what the Local Transceiver reads and sends.stty 19200 < $LOCAL_TRANSCEIVER_TEST_PORT
to set the baud rate.printf \"at+sbdix\\r\" > $LOCAL_TRANSCEIVER_TEST_PORT
. This command queries the (currently empty) mailbox.curl -X POST -F \"test=1234\" http://localhost:8080
(this is garbage data - it doesn't mean anything). You should see the original terminal print that it received a POST request.printf \"at+sbdix\\r\" > $LOCAL_TRANSCEIVER_TEST_PORT
to view the mailbox again. It will now indicate that it has the data.Other relevant commands include (but are not limited to):
at+sbdwb=<msg_length>\\r
: Setup the port to receive binary data of length msg_length
on next input.at+sbdrb\\r
: Read binary content in the mailbox.at+sbdd2\\r
: Clear all buffers.run-tests.sh
","text":"Script to setup, build, and test all ROS packages.
"},{"location":"current/sailbot_workspace/scripts/#run_softwaresh","title":"run_software.sh
","text":"Script to setup, build, and run all ROS packages.
"},{"location":"current/sailbot_workspace/scripts/#setupsh","title":"setup.sh
","text":"Script to handle ROS setup.
"},{"location":"current/sailbot_workspace/scripts/#testsh","title":"test.sh
","text":"Script to run tests in all ROS packages.
"},{"location":"current/sailbot_workspace/reference/deployment/","title":"Deployment","text":"Source code
The source code for deployment can be found in scripts/deployment
. Its README has been copied below.
Deploying our software to our autonomous sailboat's main computer.
"},{"location":"current/sailbot_workspace/reference/deployment/#scripts","title":"Scripts","text":""},{"location":"current/sailbot_workspace/reference/deployment/#setup_bootsh","title":"setup_boot.sh
","text":"Configures programs and scripts that need to run when the main computer boots. Only needs to be run once unless the script is updated. Does not need to be rerun if any scripts or programs it targets are updated, with the exception of renaming or moving the file.
Usage:
sudo ./setup_boot.sh
start_containers.sh
","text":"Runs our Docker Compose files. You may have to install commands like wget
. Would recommend running this script in its own clone of sailbot_workspace (not the one you open in VS Code).
Usage:
./start_containers.sh
--website
argument to additionally run the website container--interactive
argument to manually run commands in the sailbot workspace container--help
argument to see all available argumentsA table detailing the Docker images used to create the Dev Container can be found below. Click on an image to learn more about its features and how to update it.
Image Parent Image Source Code Why it is Rebuilt Where it is Builtpre-base
Ubuntu 22.04 base-dev.Dockerfile
To install ROS or OMPL Personal computer base
pre-base
base-dev.Dockerfile
To install core dependencies Workflow dispatch local-base
base
base-dev.Dockerfile
To install core dev dependencies Workflow dispatch dev
local-base
base-dev.Dockerfile
To install dev dependencies Workflow dispatch Dev Container dev
Dockerfile
To configure the Dev Container VS Code docs
mkdocs-material
docs.Dockerfile
To install and run docs site VS Code (optional) website
javascript-node
website.Dockerfile
To install and run website VS Code (optional)"},{"location":"current/sailbot_workspace/reference/docs_site/","title":"Docs Site","text":"UBCSailbot software team's documentation site. It is meant to be developed in Sailbot Workspace in conjunction with our other software, but doesn't have to be. There are instructions for both cases below.
"},{"location":"current/sailbot_workspace/reference/docs_site/#setup","title":"Setup","text":""},{"location":"current/sailbot_workspace/reference/docs_site/#setup-in-sailbot-workspace","title":"Setup in Sailbot Workspace","text":"docs/docker-compose.docs.yml
in .devcontainer/devcontainer.json
8000:8000
in .devcontainer/docker-compose.yml
Refer to How to work with containerized applications for more details.
"},{"location":"current/sailbot_workspace/reference/docs_site/#setup-standalone","title":"Setup Standalone","text":"Manually install social plugin OS dependencies
Install Python dependencies
pip install --upgrade pip pip install -Ur docs/requirements.txt
After setup, the Docs site should be running on port 8000.
Refer to How to work with containerized applications for more details.
"},{"location":"current/sailbot_workspace/reference/docs_site/#run-standalone","title":"Run Standalone","text":"mkdocs serve\n
"},{"location":"current/sailbot_workspace/reference/docs_site/#update-dependencies","title":"Update Dependencies","text":"This site is built using the latest versions of dependencies in docs/requirements.txt
at the time of the most recent commit to the main branch. To see exactly how the site will look when deployed, ensure your local dependencies are up to date.
Rebuild the Dev Container.
"},{"location":"current/sailbot_workspace/reference/docs_site/#update-dependencies-by-itself","title":"Update Dependencies By Itself","text":"pip install -Ur docs/requirements.txt\n
"},{"location":"current/sailbot_workspace/reference/docs_site/#maintain","title":"Maintain","text":""},{"location":"current/sailbot_workspace/reference/docs_site/#contribute-to-this-site","title":"Contribute to This Site","text":"Read our Markdown Reference Page for the syntax supported by this site.
"},{"location":"current/sailbot_workspace/reference/docs_site/#delete-docs-versions","title":"Delete Docs Versions","text":"A version of the docs site is created when a PR is open, and is deleted when it is merged or closed. However, the CI that does this is very finicky, so if 2 PR's are trying to update the site at the exact same time one might fail.
This is especially annoying if this happens to be one that deletes a version, because this means that there is a version still open for a merged/closed PR. To manually clean up these PR's, run the following commands in the docs container (in Docker Desktop, the exec tab):
git config user.name <your github username>\ngit config user.email <your github email>\nmike delete --push pr-<number>\n
If you get an error that your local copy of the gh-pages
branch has diverged from the remote, you can delete it with git branch -D gh-pages
and rerun the mike delete
command above.
It will probably ask you to login to GitHub: enter your username then a GitHub access token with write permission.
"},{"location":"current/sailbot_workspace/reference/launch_files/","title":"ROS Launch Files in Sailbot Workspace","text":"ROS 2 Launch files allow us to programatically start up and configure multiple ROS nodes.1 Within Sailbot Workspace, ROS launch files are used to start up our ROS packages with ease. Additionally, we take advantage of the hierarchical properties of launch files by defining a global entry point that invokes the launch files of all ROS packages in the system.
"},{"location":"current/sailbot_workspace/reference/launch_files/#tutorial","title":"Tutorial","text":""},{"location":"current/sailbot_workspace/reference/launch_files/#launch-file-architecture","title":"Launch File Architecture","text":"There are two launch processes that we utilize: namely the Package Launch Process and the Global launch process.
"},{"location":"current/sailbot_workspace/reference/launch_files/#the-package-launch-process","title":"The Package Launch Process","text":"The package launch process is intended to start up a specific ROS package by directly using the package launch file. The process is as follows:
Some packages rely on the data produced by other packages in the system. This may cause only partial functionality of the ROS node(s) that are running inside the launched package. Therefore, it may be necessary to launch multiple packages manually to get the desired functionality.
"},{"location":"current/sailbot_workspace/reference/launch_files/#the-global-launch-process","title":"The Global Launch Process","text":"The global launch process is intended to start up the entire system (both the development and production environments). This process invokes the package launch files for each ROS package used in the system through a global launch file. The process is as follows:
Entering Ctrl+C in the terminal where the launch file was invoked will stop all associated ROS packages from running.
Use Cmd+C for Mac OS
"},{"location":"current/sailbot_workspace/reference/launch_files/#package-launch","title":"Package Launch","text":"At the bare minimum, the following packages need to be built with the Build
or Build All
VS Code task before launching:
custom_interfaces
Packages only need to be rebuilt either when the workspace is first set up, or if any changes are made to the ROS package. Once built, the package launch file can be invoked either in the CLI or using a VS Code command:
CLI VS CodeEither the package and launch file name, or the path to the launch file can be used:
ros2 launch <package> <launch file>
. This method can only be used when a launch file is part of a built ROS package.ros2 launch <path to launch file>
. This method can be used regardless if a launch file is in a ROS package or not.Launch via CLI Examples
Let's launch local pathfinding using both CLI methods:
Method 1
ros2 launch local_pathfinding main_launch.py\n
Method 2
ros2 launch $ROS_WORKSPACE/src/local_pathfinding/launch/main_launch.py\n
Run the following VS Code command from the Run and Debug tab: ROS: Launch (workspace)
There will be a prompt to select which launch file to run. Select the desired launch file.
"},{"location":"current/sailbot_workspace/reference/launch_files/#global-launch","title":"Global Launch","text":"Before running the system, be sure to run the Build All
VS Code task to build all ROS packages. If the ROS launch debug configuration is being used, then this step is not necessary as the Build All
task is ran automatically before launch.
Run the entire system with the following CLI command:
ros2 launch $ROS_WORKSPACE/src/global_launch/main_launch.py\n
Run the following VS Code command from the Run and Debug tab: ROS: Launch (workspace)
There will be a prompt to select which launch file to run. Select the desired launch file.
Remember to that you need to potentially reload the window if the nodes are not being detected by VS Code. This usually happens when somebody build for the first time. Also, note that the global launch file is not part of a ROS package, so the path to the global launch file always must be provided. This is not always the case when a launch file is contained within a ROS package.
"},{"location":"current/sailbot_workspace/reference/launch_files/#using-cli-arguments","title":"Using CLI Arguments","text":"Invoking the launch files as is will provide the system with the default CLI arguments. As an example, the following command will launch local pathfinding while setting the log level to \"debug\":
ros2 launch local_pathfinding main_launch.py log_level:=debug\n
It can also be ran with the VS Code command named ROS: Launch.
Passing arguments takes the form of <arg name>:=<arg value>
. To list the arguments that a launch file takes, simply add the -s
flag at the end of the launch command.
-s
flag in a launch command Let's add the -s
flag after the global launch command to see the list of arguments:
ros2 launch $ROS_WORKSPACE/src/global_launch/main_launch.py -s\n
The following output is observed in the terminal (as of September 2023):
Arguments (pass arguments as '<name>:=<value>'):\n\n'config':\n Path to ROS parameter config file. Controls ROS parameters passed into ROS nodes\n (default: '/workspaces/sailbot_workspace/src/global_launch/config/globals.yaml')\n\n'log_level':\n Logging severity level. A logger will only process log messages with severity levels at or higher than the\n specified severity. Valid choices are: ['debug', 'info', 'warn', 'error', 'fatal']\n (default: 'info')\n\n'mode':\n System mode. Decides whether the system is ran with development or production interfaces. Valid choices are:\n ['production', 'development']\n (default: 'development')\n
Example using multiple CLI arguments ros2 launch local_pathfinding main_launch.py log_level:=debug mode:=production\n
Example passing local launch arguments to the global launch file As long as an argument is valid inside one of the package launch files, it may be passed to the global launch file without generating any errors. This is valid even though the argument doesn't show up in the argument list for the global launch file. For example, the following will run:
ros2 launch $ROS_WORKSPACE/src/global_launch/main_launch.py enable_sim_multithreading:=true\n
Compare the argument list between the global launch file and the package launch file for the boat_simulator
package. It will be observed that the argument enable_sim_multithreading
shows up in the boat_simulator
package argument list, but not for the global launch file.
All launch files in Sailbot Workspace accept a configuration file, which controls the ROS parameters that the ROS nodes in the system have access to. This makes our system highly configurable and customizable during development and testing. See more about ROS parameters.
ROS Launch File Documentation \u21a9
Source code
The source code for Notebooks can be found in notebooks
. Its README has been copied below.
UBC Sailbot's Jupyter notebooks for researching and exporing implementations.
"},{"location":"current/sailbot_workspace/reference/notebooks/#standards","title":"Standards","text":"Source code
Our ROS parameters can be found in src/global_launch/config
. Its README has been copied below.
The description of each parameter contained in globals.yaml
are described in this README. Descriptions of parameters for each node are included. These parameters can be changed dynamically as well via the command line interface. To learn more, see the ROS 2 documentation on ROS 2 Parameters.
Each parameter is specified in the following format:
[]
denotes inclusive boundaries, while ()
denotes non-inclusive boundaries. For strings, the acceptable values are listed.Additional information may be included when necessary.
[!IMPORTANT] This document should be updated when any changes occur to the ROS parameters specified in globals.yaml
.
ROS parameters common across all ROS nodes in the network.
pub_period_sec
double
(0.0, MAX_DOUBLE)
ROS parameters specific to the nodes in the local_pathfinding package.
"},{"location":"current/sailbot_workspace/reference/parameters/#mgp_main","title":"mgp_main
","text":"global_path_filepath
string
interval_spacing
double
(0.0, MAX_DOUBLE)
write
boolean
true
, false
gps_threshold
double
(1.0, MAX_DOUBLE)
force
boolean
true
, false
navigate_main
","text":"path_planner
string
\"bitstar\"
, \"bfmtstar\"
, \"fmtstar\"
, \"informedrrtstar\"
, \"lazylbtrrt\"
, \"lazyprmstar\"
, \"lbtrrt\"
, \"prmstar\"
, \"rrtconnect\"
, \"rrtsharp\"
, \"rrtstar\"
, \"rrtxstatic\"
, \"sorrtstar\"
ROS parameters specific to the nodes in the Controller.
"},{"location":"current/sailbot_workspace/reference/parameters/#wingsail_ctrl_node","title":"wingsail_ctrl_node","text":"reynolds_number
double
(0.0, MAX_DOUBLE)
angle_of_attack
double
(-180.0, 180.0]
ROS parameters specific to the nodes in the boat simulator.
"},{"location":"current/sailbot_workspace/reference/parameters/#low_level_control_node","title":"low_level_control_node
","text":"info_log_throttle_period_sec
double
(0.0, MAX_DOUBLE)
logging_throttle_period_sec
double
(0.0, MAX_DOUBLE)
qos_depth
int
[1, MAX_INT)
rudder.actuation_execution_period_sec
double
(0.0, MAX_DOUBLE)
rudder.disable_actuation
boolean
true
, false
rudder.fixed_angle_deg
rudder.disable_actuation
is true.double
[-45.0, 45.0]
rudder.pid.buffer_size
int
[1, MAX_INT)
rudder.pid.kd
rudder.disable_actuation
is false.double
[0.0, MAX_DOUBLE)
rudder.pid.ki
rudder.disable_actuation
is false.double
[0.0, MAX_DOUBLE)
rudder.pid.kp
rudder.disable_actuation
is false.double
[0.0, MAX_DOUBLE)
wingsail.actuation_execution_period_sec
double
(0.0, MAX_DOUBLE)
wingsail.actuation_speed_deg_per_sec
double
(0.0, MAX_DOUBLE)
wingsail.disable_actuation
boolean
true
, false
wingsail.fixed_angle_degree
wingsail.disable_actuation
is true.double
[-180.0, 180.0)
physics_engine_node
","text":"action_send_goal_timeout_sec
double
(0.0, MAX_DOUBLE)
info_log_throttle_period_sec
double
(0.0, MAX_DOUBLE)
logging_throttle_period_sec
double
(0.0, MAX_DOUBLE)
qos_depth
int
[1, MAX_INT)
rudder.actuation_request_period_sec
double
(0.0, MAX_DOUBLE)
wingsail.actuation_request_period_sec
double
(0.0, MAX_DOUBLE)
wind_sensor.constant_params.value
x
and y
components of the velocity. Only used if wind_sensor.generator_type
is constant
.double
array, length 2(MIN_DOUBLE, MAX_DOUBLE)
wind_sensor.gaussian_params.corr_xy
wind_sensor.generator_type
is gaussian
.double
[-1.0, 1.0]
wind_sensor.gaussian_params.mean
x
and y
components of the velocity. Only used if wind_sensor.generator_type
is gaussian
.double
array, length 2(MIN_DOUBLE, MAX_DOUBLE)
wind_sensor.gaussian_params.std_dev
x
component, and one for the y
component. Only used if wind_sensor.generator_type
is gaussian
.double
array, length 2(0.0, MAX_DOUBLE)
wind_sensor.generator_type
string
gaussian
, constant
wind_generation.mvgaussian_params.mean
double
array, length 2(0.0, MAX_DOUBLE)
wind_generation.mvgaussian_params.cov
double
array, since ROS parameters do not support native 2D array types.string
(0.0, MAX_DOUBLE)
current_generation.mvgaussian_params.mean
double
array, length 2(0.0, MAX_DOUBLE)
current_generation.mvgaussian_params.cov
double
array, since ROS parameters do not support native 2D array types.string
(0.0, MAX_DOUBLE)
data_collection_node
","text":"file_name
string
qos_depth
int
[1, MAX_INT)
topics
['topic_name_1', 'topic_type_1', ...]
.string
array with an even lengthbag
boolean
true
, false
json
boolean
true
, false
write_period_sec
double
(0.0, MAX_DOUBLE)
If you are not satisfied with the performance of Sailbot Workspace, here are some things you can try:
-q
argument takes about a minute. If your computer takes longer than, or you want to free up memory and disk space, you can setup Sailbot Workspace in a GitHub CodespaceIf you are having some trouble running our software, here are some things you can try:
"},{"location":"current/sailbot_workspace/usage/help/#sailbot-workspace-troubleshooting","title":"Sailbot Workspace Troubleshooting","text":"setup
task to update package dependenciesclean
task to delete C++ generated filespurge
task to delete ROS generated filesBuild All
task to rebuildDev Containers: Rebuild Container
VS Code commandDeveloper: Reload Window
VS Code commandHelp: Start Extension Bisect
VS Code commandwsl --shutdown
in PowerShellDelete Docker files
Running Docker CLI commands on WindowsOn Windows, Docker CLI commands should be run in the Ubuntu terminal while Docker Desktop is running.
docker system prune
to remove all unused containers, networks, and dangling and unreferenced images--all
to additionally remove unused images (don't have a container associated with them)--volumes
to additionally remove volumes (makes Bash history and ROS logs persist across containers)docker rmi -f $(docker images -aq)
to remove all imagesAfter using Docker and Ubuntu for a while, you may notice that the vdisks are very large. As of May 2024, they are located at C:\\Users\\<user>\\AppData\\Local\\Docker\\wsl\\data\\ext4.vhdx
and C:\\Users\\<user>\\AppData\\Local\\Packages\\CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc\\LocalState\\ext4.vhdx
, respectively.
The problem is that these vdisks can automatically grow but not shrink, so if you download large files (like Docker images) and delete them once they're not needed the space is not freed. You can shrink vdisk using these commands.
"},{"location":"current/sailbot_workspace/usage/how_to/","title":"How-To's","text":""},{"location":"current/sailbot_workspace/usage/how_to/#run-vs-code-commands-tasks-and-launch-configurations","title":"Run VS Code commands, tasks, and launch configurations","text":"MacOS keyboard shortcuts
For keyboard shortcuts on MacOS, substitute Ctrl with Cmd.
VS Code commands can be run in the Command Palette. Open the Command Palette from the View
menu or with Ctrl+Shift+P.
Tasks can be run using the Tasks: Run Task
VS Code command. Build tasks can be run with Ctrl+Shift+B.
Launch configurations can be run from the Run and Debug view.
You can also run VS Code commands, tasks, launch configurations, and much more by typing their prefixes into an empty Command Palette. Open an empty Command Palette with Ctrl+P or by clicking the box in the center of the title bar. See the list below for some prefixes and their functions. For prefixes that are words, you will have to append a space to them to bring up their functions.
>
: VS Code commandstask
: tasksdebug
: launch configurations?
: list all prefixes and their functionsWe have containerized the following applications for a variety of reasons:
In the first section of dockerComposeFile
of .devcontainer/devcontainer.json
, there is a list of files: each file contains the configuration for one or more applications.
The ones that are commented out are not run. To run them:
.devcontainer/docker-compose.yml
Dev Containers: Rebuild Container
VS Code command to restart Sailbot WorkspaceTo stop running them:
.devcontainer/devcontainer.json
and port mapping in .devcontainer/docker-compose.yml
Connect the MongoDB VS Code extension to the running database: Create a Connection for Deployment
mongodb://localhost:27017
Docs runs on port 8000 and Website 3005. You can see them in your browser at localhost:<port>
. To open them using VS Code:
Ports: Focus on Ports View
VS Code commandTurn off auto saving
Changes made to their files are loaded when they are saved, so if Auto Save is on, turn it off so that the Docs/Website servers aren't continuously reloading. Auto Save is on by default in GitHub Codespaces
"},{"location":"current/sailbot_workspace/usage/how_to/#managing-containerized-applications","title":"Managing containerized applications","text":"Each application runs in a Docker container. Containers can be managed using Docker Desktop or CLI commands:
View Sailbot Workspace containers
Docker Desktop CLI Commandsdocker ps -a\n
sailbot_workspace_devcontainer-<application>-<number>
STATUS
column shows whether a container is running or notView a container's logs, the output of the container (including errors that caused it to stop)
Docker Desktop CLI Commandsdocker logs <container>\n
Start a container that is not running
Docker Desktop CLI Commandsdocker start <container>\n
Stop a container that is running
Docker Desktop CLI Commandsdocker stop <container>\n
Why can't I just install the dependencies myself in the command line interface with pip
or apt
?
Although this will temporarily work, installing apt and/or Python dependencies directly in sailbot workspace using the commandline interface will not persist between container instances. The dependencies will need to be manually installed every single time you create a new instance of sailbot workspace, which is not feasible when we start to use many dependencies at once.
Of course, one could also install dependencies inside the sailbot workspace Docker images to allow such dependencies to persist across container instances. However, putting dependencies inside package.xml
distinguishes between what dependencies are needed for ROS packages and what dependencies are needed for infrastructure purposes.
If running your ROS packages requires external dependencies from an apt repository or python package, one of the following tags should be added to the package.xml
file in the root directory of the ROS package:
<depend>ROSDEP_KEY</depend>\n<build_depend>ROSDEP_KEY</build_depend>\n<build_export_depend>ROSDEP_KEY</build_export_depend>\n<exec_depend>ROSDEP_KEY</exec_depend>\n<test_depend>ROSDEP_KEY</test_depend>\n
Learn what each tag is used for here.
Replace ROSDEP_KEY
with the rosdep key for the dependency, which can be found online.
package.xml
python3-
(python-
is usually for Python 2)If there isn't rosdep key for the dependency, you can add your own to custom-rosdep.yaml
in the root directory of the ROS package
After completing these steps, run the setup
task and the desired dependencies should be installed. ROS uses a dependency management utility, rosdep, to handle the installation of dependencies. In addition to runtime dependencies, rosdep also handles dependencies for build time, dependencies for testing, sharing dependencies between ROS packages, and more. See the ROS documentation on rosdep to learn more.
There are a couple cases where you would want to add dependencies to a Docker image instead of ROS package:
To verify your changes, you can add them to .devcontainer/Dockerfile
then run the Dev Containers: Rebuild Container
VS Code command. Once verified, migrate the changes to one of the upstream images: base
, local-base
, dev
, or pre-base
.
GitHub Copilot is an AI paired programming tool that can help you accelerate your development by providing suggestions for whole lines or entire functions inside your editor.1 To enable GitHub Copilot:
Apply to GitHub Global Campus as a student to use GitHub Copilot and get other student benefits for free. It may take a few days for your student status to be verified. In the meantime, you can still continue with the next steps. However, you will need to use the GitHub Copilot free trial until your account is verified.
Sign up for GitHub Copilot for your personal account. If it offers a free trial, then take it. You should see a page telling you that you can use GitHub Copilot for free (if you have a verified student account).
Uncomment the github.copilot
extension in .devcontainer/devcontainer.json
and run the Dev Containers: Rebuild Container
VS Code command
Sign into your GitHub account in VS Code. The GitHub Copilot extension should automatically prompt you to sign into your account if you are not already.
VS Code is not prompting me to sign into my accountYou may already be signed in into your GitHub account. You can check by clicking on the Accounts icon in the bottom-left corner in VS Code and verify that you see your GitHub account.
If you do not see your account, you can get the sign in prompt by trying:
Developer: Reload Window
Dev Containers: Rebuild Container
If all the previous steps were done correctly, you should see the GitHub Copilot icon in the bottom-right corner of VS Code without any error messages. For more information on how to use Copilot and a tutorial, refer to:
Dotfiles are configuration files for various programs.2
More about dotfiles.
)ls
command, specify the -a
argument: ls -a
Dotfiles that are commonly modified include:
~/.bashrc
~/.gitconfig
~/.vimrc
To use your dotfiles:
base
, local-base
, or dev
image installs the programs that the dotfiles correspond toCopy the dotfiles to the .devcontainer/config/
directory. If a dotfile is located in a child directory, you will have to created it. For example, if a dotfile's path is ~/.config/ex_dotfile
, you will need to copy it to .devcontainer/config/.config/ex_dotfile
Special cases
~/.gitconfig
: there is no need copy your Git dotfile, as Dev Containers do this automatically~/.bashrc
: don't copy your Bash dotfile, as it would override the one created in the dev
image. Instead, add your bash configuration .aliases.bash
or .functions.bash
in the config directory, as these are sourced by the created Bash dotfile.Run the Dev Containers: Rebuild Container
VS Code command
Raye was our previous project. Her software can be run in the raye
branch:
raye
branch: git switch raye
Dev Containers: Rebuild Container
VS Code commandraye
branch disclaimers
raye
(and Raye's codebase in general) is not in active development, it may not be 100% functional or contain all the features in main
raye
is more memory intensive than main
because the parent image of its Dev Container is much larger; this may lead to worse performanceTo build Raye's ROS packages, run the following commands:
roscd\ncatkin_make\n
"},{"location":"current/sailbot_workspace/usage/how_to/#run-packages-from-different-workspaces","title":"Run packages from different workspaces","text":"The raye
branch has two ROS workspaces: one for Raye and one for the new project. To run ROS packages, you will have to source the overlay of the workspace that it is in:
srcnew\n
srcraye\n
Then you can run launch files or package-specific executables in that workspace with:
New ProjectRayeros2 launch ...
or ros2 run ...
, respectively.
roslaunch ...
or rosrun ...
, respectively.
Run commands for Raye packages are very slow
On non-Ubuntu-based Linux operating systems, Run commands for Raye packages may take a long time to start-up. This is because the system has trouble resolving the local hostname.
To resolve this bug, run the commands below in the Dev Container:
echo 'export ROS_HOSTNAME=localhost' >> ~/.bashrc\necho 'export ROS_MASTER_URI=http://localhost:11311' >> ~/.bashrc\n
GitHub Copilot Quickstart Guide \u21a9
Dotfiles \u2013 What is a Dotfile and How to Create it in Mac and Linux \u21a9
Sailbot Workspace can be run on Windows, Linux, or macOS, but is the easiest to set up and performs the best on Ubuntu and its derivatives. The workspace may not perform well on Windows computers with 8GB of memory or less; in this case, please check out our recommendations in the Performance Issues section.
"},{"location":"current/sailbot_workspace/usage/setup/#1-setup-prerequisites","title":"1. Setup prerequisites","text":""},{"location":"current/sailbot_workspace/usage/setup/#docker","title":"Docker","text":"Docker is a platform that uses OS-level virtualization1 to develop, ship, and run applications.2 We use it to separate our applications from our infrastructure2 so that we can update and version control our infrastructure for every use case (software members, CI, deployment) in one place: this repository.
Docker Engine is a software used to run Docker. However, it can only be installed on Linux. Docker Desktop is a software used to run Docker in a VM,3 allowing it to be installed on Windows and macOS in addition to Linux.
Windows macOS LinuxSet up prerequisites, WSL and Ubuntu:
In PowerShell, run wsl --install Ubuntu
, then exit
, wsl --update
, and wsl --set-default Ubuntu
If Ubuntu is already installed, check that it is the right WSL version:
wsl -l -v
VERSION
is 1, upgrade it to WSL 2 with wsl --set-version Ubuntu 2
Open the Ubuntu app to set up or verify its configuration:
Run whoami
to verify that it returns your Ubuntu username
whoami
returns root
If whoami
returns root
:
ubuntu config --default-user <username>
in PowerShell, replacing <username>
with the name of the newly-created userwhoami
after closing and reopening Ubuntu, verifying that it returns your Ubuntu usernameInstall Docker Desktop with the WSL 2 backend
Docker Desktop - Unexpected WSL ErrorIf the above error shows when trying to start Docker Desktop on your laptop:
C:\\Users\\user_name
and delete the .Docker folderIf Ubuntu can't start up and WSL hangs when restarting:
netsh winsock reset
More potential solutions can be found here: Link
Install Docker Desktop for your computer's CPU.
Visual Studio Code is a powerful and customizable code editor for Windows, Linux, and macOS. We strongly recommend that you use this editor to develop our software so that you can use all the features of Sailbot Workspace.
Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.4
git --version
(on Windows, run command in PowerShell)Login to GitHub
Windows macOS / LinuxRun the git config
command for your Git version in Git Credential Manager setup (run command in Ubuntu)
Which Git to check
Git is installed seperately in Windows and Ubuntu, so they could be at different versions. We want to check the version of Git on Windows, not Ubuntu: run git --version
in PowerShell and not Ubuntu. However, the git config
command itself is run in Ubuntu.
gh auth login
and select the first option for all choicesVerify that you have successfully logged in to GitHub by cloning a private GitHub repository (run command in Ubuntu)
git clone https://github.com/UBCSailbot/raye-ais.git
rm -rf raye-ais
X11 forwarding is a mechanism that enables Sailbot Workspace to run GUI applications.
You can skip this step since we currently aren't running any GUI applications
Setup instructions for X11 forwardingVerify that echo $DISPLAY
returns something like :0
echo $DISPLAY
doesn't return anything If echo $DISPLAY
doesn't return anything, set it to :0
on shell initialization:
echo $SHELL
~/.bashrc
~/.zshrc
echo 'export DISPLAY=:0' >> <rc file path>
, replacing <rc file path>
with the path to your shell's rc fileecho $DISPLAY
after closing and reopening your terminal, verifying it returns something like :0
Install a X11 server
Windows macOS LinuxWSL includes a X11 server.
cp /opt/X11/etc/X11/xinit/xinitrc ~/.xinitrc
xhost +localhost
to ~/.xinitrc
after its first lineAs of February 2023, almost all Linux distributions include a X11 server, Xorg. This may change in the future as Wayland matures.
sudo pacman -S xorg-xhost
cp /etc/X11/xinit/xinitrc ~/.xinitrc
xhost +local:docker
to ~/.xinitrc
after its first lineVerify that X11 forwarding works:
Install x11-apps
In Ubuntu, sudo apt install x11-apps
.
XQuartz includes x11-apps
. Ensure that XQuartz is running.
Install x11-apps
using your desired package manager.
Verify that running xcalc
opens a calculator and that you can use it
Where to clone on Windows
Run the command below in the Ubuntu app to clone it in the Ubuntu file system, otherwise sailbot workspace will not work. Windows has a native file system as well as file systems for each WSL distribution.
git clone https://github.com/UBCSailbot/sailbot_workspace.git\n
"},{"location":"current/sailbot_workspace/usage/setup/#4-open-sailbot-workspace-in-vs-code","title":"4. Open Sailbot Workspace in VS Code","text":"Install code
command in PATH
The code
command is installed by default.
See launching from the command line.
The code
command is installed by default.
Open the sailbot_workspace/
directory in VS Code: run code <relative path to sailbot workspace>
code sailbot_workspace
Click the popup to Open Workspace
. If there isn't a popup:
sailbot.code-workspace
in VS CodeOpen Workspace
Reopen in Container
. If there isn't a popup, run the Dev Containers: Reopen in Container
VS Code commandBuild All
task","text":"Wait before running
Ensure that the postCreateCommand from devcontainer.json
has completed before running this task.
The Build All
task builds all the ROS packages.
Delete all open terminals and run the Developer: Reload Window
VS Code command to detect the files that were generated from building.
Run the entire system to verify everything is working using the following command in the VS Code terminal:
ros2 launch $ROS_WORKSPACE/src/global_launch/main_launch.py\n
Use Ctrl+C in the terminal to stop the system.
"},{"location":"current/sailbot_workspace/usage/setup/#setup-sailbot-workspace-in-a-github-codespace","title":"Setup Sailbot Workspace in a GitHub Codespace","text":"A codespace is a development environment that's hosted in the cloud.5 Since Sailbot Workspace is resource intensive, it has high hardware requirements and power consumption, which aren't ideal for development on laptops. GitHub Codespaces provide a seamless experience to work on repositories off-device, especially if they specify a Dev Container like Sailbot Workspace. Codespaces can run in VS Code or even in a browser for times when you aren't on your programming computer.
Once you have a codespace set up:
Codespaces: Stop Current Codespace
VS Code commandKnown limitations of running Sailbot Workspace in a GitHub Codespace
Wikipedia Docker page \u21a9
Get Docker \u21a9\u21a9
What is the difference between Docker Desktop for Linux and Docker Engine \u21a9
Git SCM \u21a9
GitHub Codespaces overview \u21a9
Once you have set up Sailbot Workspace, you can open it by opening a new VS Code window and selecting:
File > Open Recent > /workspaces/sailbot_workspace/.devcontainer/config/sailbot_workspace (Workspace) [Dev Container: Sailbot Workspace]\n
Another way to open Sailbot Workspace on Windows sailbot_workspace (Workspace) [Dev Container]
Then you can open Sailbot Workspace by selecting it from the \"Pinned\" section of the VS Code taskbar icon's right-click menu.
"},{"location":"current/sailbot_workspace/usage/workflow/#2-update-sailbot-workspace","title":"2. Update Sailbot Workspace","text":"Sailbot Workspace is still in active development, check out its recent releases and commit history. If there are new features or bug fixes that you want to try, you will need to update your local version of Sailbot Workspace:
Switch Sailbot Workspace to the main branch if you aren't in it already
If you running Git commands in the CLI, make sure that you are in the correct repositorySailbot Workspace contains other repositories in the src/
directory, so if you are in one of its subdirectories you may be in the wrong repository.
To check which repository you are in, run git remote -v
; if its output contains sailbot_workspace
, you are good to go. If not, you can navigate the root directory of the Sailbot Workspace repository with cd $ROS_WORKSPACE
, or open a new terminal in its root directory with Ctrl+Shift+` then Enter.
Pull the latest changes
If prompted, rebuild the Dev Container
When does the Dev Container need to be rebuilt?To apply the modifications to its configuration files in .devcontainer/
that occurred since it was last built.
VS Code will prompt you to rebuild when devcontainer.json
, Dockerfile
, or docker-compose*.yml
. These file may be modified if you:
.devcontainer/
yourselfHowever, there may be changes to the Dev Container that VS Code can't detect. To rebuild it yourself, run the Dev Containers: Rebuild Container
VS Code command.
If you want to run our docs or website, see How to work with containerized applications
We make changes to our software following our GitHub development workflow. Of particular relevance is the Developing on Branches page.
Git interfaces
One way to interface with Git is through CLI commands. However, you may find it faster to use VS Code's interface, especially when working with multiple repositories.
Things to note when making changes:
In general, changes need to be built before they can be run. You can skip this step if you only modified Python source or test files (in python_package/python_package/
or python_package/test
, respectively), or are running a launch type launch configuration.
Build All
or Build Package
taskclang-tidy
, use the -q
build argument (default) for quicker build timesIf you want to run GUI applications on macOS, ensure that XQuartz is running.
"},{"location":"current/sailbot_workspace/usage/workflow/#lint-and-test","title":"Lint and Test","text":"Run lint and test tasks to make sure you changes will pass our CI:
ament lint
clang-tidy
test
In addition to VS Code tasks, the Testing tab on the VS Code primary sidebar contains individual tests. One can run specific unit tests by clicking the Run Test icon beside the test name.
"},{"location":"current/sailbot_workspace/usage/workflow/#run-a-package","title":"Run a Package","text":"To verify that your changes do what you expect, you may want to run the package you modified. The run commands for each package should be documented in their READMEs, but in general they can be run using a CLI or VS Code command:
CLI VS Coderos2 launch <package> <launch file>
ros2 launch <path to launch file>
ros2 run <package> <executable>
There are many commands that can be autocompleted in the terminal. Take advantage of this so that you run commands faster and memorize less syntax. If there is only one possibility, pressing tab once will complete it. If there is more than one possibility, pressing tab again will list them out.
Some tab completion use cases:
View available commands: lists all ros2
commands
$ ros2 <tab><tab>\naction extension_points multicast security\nbag extensions node service\n...\n
Complete commands: runs ros2 launch local_pathfinding main_launch.py
$ ros2<tab>la<tab>loc<tab>m<tab>\n
Navigate to directories: runs cd .devcontainer/config
from the root directory of Sailbot Workspace
$ cd .d<tab>c<tab>\n
Furthermore, navigate past commands with Up and Down and search through them with Ctrl+R.
ROS: Run a ROS launch file (roslaunch)
ROS: Run a ROS executable (rosrun)
For more information on launch file use in our system, see this page.
"},{"location":"current/sailbot_workspace/usage/workflow/#run-the-system","title":"Run the System","text":"To verify that you didn't break anything, you may want to run the entire system. See Invoking Launch Files for more information on running the system.
"},{"location":"current/sailbot_workspace/usage/workflow/#debugging","title":"Debugging","text":"Debug your changes if they aren't behaving how you expect by setting breakpoints and running one of our launch configurations in the Run and Debug tab on the VS Code primary sidebar. The launch configuration types are:
ROS: Launch
C++ (GDB): Launch
ROS: Attach
Source code
The source code for Website can be found in src/website
. Its README has been copied below.
In the website development timeline, we are currently evaluating the folllowing software stack: Next.js website (this repository), Typescript, React + Redux, and the MongoDB database. The easiest way to evaluate these potential solutions for our purposes is in sailbot_workspace.
"},{"location":"current/website/overview/#database","title":"Database","text":"MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era. If you want to learn more about MongoDB, visit their docs site: MongoDB Documentation.
"},{"location":"current/website/overview/#setup","title":"Setup","text":""},{"location":"current/website/overview/#environment-variables","title":"Environment variables","text":"We have two separate configurations: one for development .env.development
, the other for production .env.production
. The values may vary, but the environment variables are the same. See below:
MONGODB_URI
: Your MongoDB connection string. Use mongodb://localhost:27017/<DB_NAME>
to establish a connection with the local database.NEXT_PUBLIC_SERVER_HOST
: The host URL of the website.NEXT_PUBLIC_SERVER_PORT
: The port number of the website.NEXT_PUBLIC_POLLING_TIME_MS
: The time interval for polling the database in milliseconds.The following command installs all required dependencies listed in the package.json
file:
npm install\n
Once the installation is complete, you should see a node_modules
directory in the project's root. This directory contains all installed packages.
When installing a new package to the website, please follow the steps below:
Access the terminal of the website container on Docker.
Run the command npm install <package-name>
. Replace <package-name>
with the actual name of the package you want to add.
Should you encounter errors related to resolving peer dependencies, please re-run the command with the header --legacy-peer-deps
. Do not to use --force
unless you're well aware of the potential consequences.
Review the package.json
file to ensure the new package and its version have been added to the dependencies section.
package-lock.json
has also been updated. This file holds specific version information to ensure consistent installations across different environments.package.json
and package-lock.json
. These files are essential for version controlling the dependencies that have been added.Using Sailbot Workspace, the website should be up and running on http://localhost:3005.
Otherwise, you execute the following commands to run it in development mode:
npm run dev\n
"},{"location":"current/website/overview/#linters","title":"Linters","text":"Before merging in new changes to the repository, please execute the following commands in order:
npm run format\n
This command runs Prettier to automatically format the code according to the rules defined in the configuration file .prettierrc
.
npm run lint\n
This command runs ESLint to analyze the code for potential errors and enforce coding style based on the rules defined in the configuration file .eslintrc
.
Docker is a platform that uses OS-level virtualization1 to develop, ship, and run applications.2
"},{"location":"reference/docker/#tutorial","title":"Tutorial","text":"Wikipedia Docker page \u21a9
Get Docker \u21a9
Markdown is a lightweight markup language that you can use to add formatting elements to plaintext text documents.1 You can do anything with Markdown, from creating websites to PDF documents, all in a clean format that is easy to learn. Many of your favorite services use Markdown, so it would be useful to pick it up to write technical documentation.
Markdown is not standardized across services. Many services that support Markdown have their own \"flavour\" of Markdown. Be sure to know the Markdown features of the service you are using so that your Markdown renders properly.
"},{"location":"reference/markdown/#getting-started","title":"Getting Started","text":"We recommend markdownguide.org to be your first point of reference if\\ you are learning Markdown for the first time. It covers topics like what Markdown is, its syntax, advanced tips, and the different services that support Markdown. Flavours of Markdown specific to a service build on top of these basics.
"},{"location":"reference/markdown/#sailbot-and-markdown","title":"Sailbot and Markdown","text":"We write Markdown for GitHub and Material for MkDocs. The following sections detail how Markdown is used in these services.
"},{"location":"reference/markdown/#github","title":"GitHub","text":"We use Markdown in GitHub for technical documentation and collaboration. This includes:
README.md
filesAlmost all places where text is written in GitHub support Markdown. GitHub also allows you to preview your Markdown before you submit any comments.
Before RenderingAfter RenderingThe image above shows an example of a \"write\" and a \"preview\" tab for writing a comment on an issue. It might look different depending on where you are writing, but there usually exists a preview option!
GitHub-Flavoured Markdown
GitHub uses its own \"flavour\" of Markdown. Certain features, like using HTML, are excluded for security reasons. Visit the official GitHub Markdown guide for more information on the available features.
"},{"location":"reference/markdown/#material-for-mkdocs","title":"Material for MkDocs","text":"We use Markdown in Material for MkDocs to create this website! Since it is written in Markdown, no frontend experience is required to contribute to our docs.
Material for MkDocs supports powerful features purpose-built to take technical documentation to the next level. Feel free to browse this site to see how we use these features, exploring their syntax in the source code. Since GitHub renders Markdown files automatically you will need to click the \"Raw\" button to view their contents.
Material-Flavoured Markdown
Material for MkDocs' flavour of Markdown extends upon vanilla Markdown, adding features such as admonitions (like this note) and content tabs. Refer to the official Material for MkDocs reference page for more information on the available features.
"},{"location":"reference/markdown/#rendering-markdown","title":"Rendering Markdown","text":"You have a few choices to render Markdown on your computer. Be advised that if you are using an extended version of Markdown, you will need to consult the documentation from the service provider to render their flavour of Markdown properly. The following resources are good for rendering Markdown:
Vanilla Github Material for MkDocsOther resources exist to render Markdown like browser extensions that render Markdown as HTML and GitHub repositories that contain source code to render your Markdown. Feel free to browse around for the solution that suits your needs.
"},{"location":"reference/markdown/#linting","title":"Linting","text":"We lint our Markdown files to reduce errors and increase readability. In particular, we use two tools:
markdownlint is used to enforce a style guide. Its configuration file for this repository is .markdownlint.json
. If you use VS Code, there is a markdownlint extension.
markdown-link-check is used to check for broken links. Its configuration file for this repository is .markdown-link-check.json
.
https://www.markdownguide.org/getting-started/ \u21a9
Robot Operating System (ROS) is a set of software libraries and tools for building robot applications.1 It provides functionality for hardware abstraction, device drivers, communication between processes over multiple machines, tools for testing and visualization, and much more.2
We use ROS because it is open-source, language-agnostic, and built with cross-collaboration in mind. It enables our sub-teams to work independently on well-defined components of our software system without having to worry about the hardware it runs on or the implementation of other components.
The official ROS 2 documentation contains everything you need to get started using ROS. From it we have hand-picked the resources that are most relevant to our current and expected future usage of ROS assuming that you use our preconfigured workspace. To run our software on your device without our workspace, you would have to install ROS and the dependencies that are in our Docker images yourself.
"},{"location":"reference/ros/#tutorial","title":"Tutorial","text":""},{"location":"reference/ros/#workspace-configuration","title":"Workspace Configuration","text":"To get our workspace configuration running on your computer:
.devcontainer/Dockerfile
, then run the \"Dev Containers: Rebuild Container\" VS Code command, to install the tutorials' dependencieshumble
branch), py_pubsub_ex, and cpp_pubsub_ex, then run the setup
VS Code task to install their dependenciesOur workspace configuration contains easier methods of accomplishing some of the tutorial steps, or eliminates the need for them altogether.
Tutorial step Sailbot Workspace configuration Install a package All packages used in the tutorials are already installed (step 2 above) Clone a sample repo (ros_tutorials) ros_tutorials is already cloned (step 3 above) Resolve dependencies Run the \"install dependencies\" VS Code task Build the workspace Run the \"Build\" VS Code task, AKA Ctrl+Shift+B Source the overlay Run thesrcnew
terminal command Create a package with a node Run the \"new ament_(python|cmake) package with a node\" VS Code task"},{"location":"reference/ros/#tutorials","title":"Tutorials","text":"We encourage all software members to work through the ROS tutorials that are listed below in order. For tutorials that have both C++ and Python versions, NET members should do the C++ version while CTRL and PATH members should do the Python version.
turtlesim
and rqt
rqt_console
to view logsros2doctor
to identify issuesWe encourage all software members to read the following documentation on key ROS concepts:
There are two major versions of ROS, aptly named ROS 1 and ROS 2. Our previous project, Raye, uses ROS 1 because it was the only version available during her design process. Our new project will use ROS 2, a complete re-design of the framework that tackles the shortcomings of ROS 1 to bring it up to industry needs and standards.3 If you are curious about the changes made in ROS 2 compared to 1, this article is a worthwhile read.
ROS 2 includes the ROS 1 Bridge, a collection of packages that can be installed alongside ROS 1 to help migrate code from ROS 1 to ROS 2. As we will be reusing parts of Raye's codebase, it is essential to know how to use these packages. Until we are completely done with Raye, our preconfigured workspace will have ROS 1, ROS 1 Bridge, and ROS 2 installed.
We encourage all software members work through the ROS 1 Bridge README. For PATH members, the Migrating launch files from ROS 1 to ROS 2 page will be a helpful reference when we do so.
https://docs.ros.org/en/humble/index.html \u21a9
https://www.toptal.com/robotics/introduction-to-robot-operating-system \u21a9
https://ubuntu.com/robotics/what-is-ros \u21a9
For most use cases, you can think of C++ as a superset of C. While this is not technically true, more often than not you are able to write standard C code for a C++ program without issues. However, doing so ignores a lot of the benefits and reasons to use C++.
"},{"location":"reference/cpp/differences/#classes-and-structs","title":"Classes and Structs","text":"In C structs can only contain member variables, but in C++ structs are basically classes but with a default member visibility of public instead of private.
ExampleThe following code blocks are equivalent.
struct foo {\nprivate:\n int x;\n void helper(void);\npublic:\n foo(int y);\n}\n
class foo {\nprivate:\n int x;\n void helper(void);\npublic:\n foo(int y);\n}\n
"},{"location":"reference/cpp/differences/#namespaces","title":"Namespaces","text":"One problem that is prevalent in C concerns the scoping of names. For example, let there be two files A.h
and B.h
and a program ighxy.c
, and let them both contain a float x
and int bar(void)
.
Our program cannot compile because the linker cannot distinguish which bar()
function we want to use! One way to fix this in a C program would be to rename them a_bar()
and b_bar()
. Although this fix seems trivial for this example, applying it to a file that has potentially 100 functions can be a lot more difficult, especially if two files just happen to share the same prefix for their functions!
C++ introduces namespaces to tackle this problem. With namespaces, we can deal with naming conflicts much more easily. Though be aware that namespaces are not necessary everywhere. See the following code snippet to see how they work.
Example CC++ A.hfloat x;\nint bar(void);\n
B.hfloat x;\nint bar(void);\n
ighxy.c#include \"A.h\"\n#include \"B.h\"\n\nint main(void) {\n int a = bar();\n ...\n}\n/* Error, does not compile*/\n
A.hnamespace a {\nfloat x;\nint bar(void);\n}\n
B.hnamespace b {\nfloat x;\nint bar(void);\n}\n
ighxy.cpp#include \"A.h\"\n#include \"B.h\"\n\nint main(void) {\n int a = a::bar();\n int b = b::bar();\n float xa = a::x;\n float xb = b::x;\n /* No problem! */\n ...\n}\n
Warning You may come across something like:
example.cppusing namespace std;\nnamespace io = std::filesystem;\n\nint main(int argc, char* argv[]) {\n bool isDirectory = io::is_directory(argv[1]); // Equivalent to std::filesystem::is_directory(argv[1])\n cout << isDirectory << endl;\n return 0;\n}\n
There are two things going on here.
First, using namespace std
makes all functions and types defined within the standard namespace and included via #include
directives visible to example.cpp
. If you are familiar with Python, the Python equivalent of this would be import std as *
. However, it is considered bad practice to do this as it eliminates the point of using namespaces.
class string {\n // Insert implementation here\n }\n\n int main(void) {\n string ourString = \"Our own string implementation\";\n std::string stdString = \"Standard Library string implementation\";\n ...\n }\n
using namespace std;\n\n // ERROR - multiple definitions of type string\n class string {\n\n }\n
The compiler cannot infer which implementation we want.
Secondly, namespace io = std::filesystem
is basically an alias for the std::filesystem
namespace. This practice is acceptable for long namespace identifiers, but be careful as it can still run into namespace conflicts if your alias is the same as another namespace or alias.
In C, if we want to declare a constant or a function/expression that we want to be evaluated at compile time, we need to use #define
statements. One of the problems with #define
statements is that they perform a simple copy paste wherever they're used. For example:
#define PI 3.14F\n#define AREA_OF_CIRCLE(radius) ((PI) * (radius) * (radius))\n\nint main(void) {\n float area = AREA_OF_CIRCLE(2.5F);\n ...\n}\n
int main(void) {\n float area = ((3.14F) * (2.5F) * (2.5F));\n ...\n}\n
Note
AREA_OF_CIRCLE
is a macro with arguments. If you are confused by it, this resource has a detailed explanation on how they work.
Because of this copy-pasting, you need to be very careful with syntax, sometimes necessitating an ugly do {} while(0)
wrapper. Moreover, symbols declared with #define
are always globally visible, ignoring namespaces!
In C++, the use of constant expressions are preferred.
constexpr float pi = 3.14F;\nconstexpr float area_of_circle(float radius) {\n return pi * radius * radius;\n}\n
Constant expressions do not get copy pasted, and are instead placed in program memory just like a normal variable or function. They also respect namespaces and function scopes, meaning the following code compiles.
Constant Expression Scopingvoid foo(void) {\n constexpr float rand = 123.456;\n ...\n}\n\nvoid bar (void) {\n constexpr float rand = 789.123;\n ...\n}\n
"},{"location":"reference/cpp/differences/#lambdas","title":"Lambdas","text":"Lambdas are primarily useful when you need to register a callback function one time and don't feel it's necessary to write out a full function. They are in no way required though, so do not worry about learning them. However, it's necessary to know that they exist such that you don't get confused when reading code. For more information, go here for Microsoft's explanation.
"},{"location":"reference/cpp/differences/#misc","title":"Misc","text":""},{"location":"reference/cpp/differences/#arrays","title":"Arrays","text":"Using the C++ implementation of arrays is preferred over C arrays. It is simply easier and safer to work with than a standard C array without any performance costs.
ExamplePassing an array to a function an iterating over it
CC++#include \"stdio.h\"\n\nvoid print_contents(int *arr, int size) {\n for (int i = 0; i < size; i++) {\n printf(\"%d\\n\", *arr);\n }\n}\n\nint main(void) {\n int arr[5] = {0, 1, 2, 3, 4};\n foo(arr, 5);\n return 0;\n}\n
We can't even guarantee that the integer pointer arr
is an array! C++ 20 makes passing arrays around a lot simpler. Do not worry about understanding the code shown below. It uses some fairly advanced concepts and exists to illustrate how different such a simple operation can be.
#include <iostream>\n#include <array>\n#include <span>\n\nvoid print_contents(std::span<int> container) {\n for (const auto &e : container) {\n std::cout << e << std::endl;\n }\n}\n\nint main(void) {\n std::array<int, 5> arr = {0, 1, 2, 3, 4};\n foo(arr);\n return 0;\n}\n
The advantages of the C++ version are:
UBC Sailbot's Network Systems team uses C++ for its software. If you know already know C, then you already know the bare minimum to write C++. This is a good starting point, but the additional features C++ provides allow for safer programming practices.
"},{"location":"reference/cpp/start/#for-cc-beginners","title":"For C/C++ Beginners","text":"If you just need to know how C++ is different from C, then see the Differences Between C and C++. You should also look at it if you go through and finish this section.
If you are new to C and C++, then this the best place to start. The tutorials provided in this section will help you learn the fundamentals of the language. Do not feel pressured to do all the tutorials! Just get comfortable with the syntax and the mechanisms of the language.
Note
The hardest part about this will likely be pointers and dynamic memory, so pay close attention to tutorials concerning them! Additionally, dynamic memory requires the usage of pointers, but pointers do not require dynamic memory!
Tip
Dynamic memory is much more prone to error than statically allocated memory, so try to use static allocation whenever possible
Resource Description w3schools Tutorial A structured tutorial that goes through basic concepts in C++. It's good to do up to the section on Classes. YouTube Tutorial If you prefer video tutorial, then this is a comprehensive 4 hour video covering similar concepts to the one above. It is 4 hours long though. Dynamic Memory Overview A page going over how dynamic memory works in C++.Feel free to add other resources other than the ones listed above if you find any that you like!
"},{"location":"reference/cpp/tools/","title":"Tools","text":"A lot goes into making a well structured C++ project, much more than any one team should have to do.
"},{"location":"reference/cpp/tools/#cmake","title":"CMake","text":"CMake is a powerfull build automation tool that makes compiling code for large projects with a lot of interoperating files a lot easier. Steps 1-3 of the official tutorial are great for understanding the basics.
"},{"location":"reference/cpp/tools/#gdb","title":"GDB","text":"The GNU Project Debugger is the most commonly debugger for the C language family. VSCode also has a degree of integration with GDB that allows an easy to use GUI. This GDB cheat sheet has all the GDB comands you will need to know. Be aware the VSCode has GUI buttons for some of these commands that are easier to use.
"},{"location":"reference/cpp/tools/#googletest","title":"GoogleTest","text":"GoogleTest is the C++ unit testing framework we will be using. The GoogleTest Primer is a good place to start.
Example Cached Fibonacci ProgramTest Cached Fibonacci Program cached_fib.h#include <vector>\nclass CachedFib {\npublic:\n void CachedFib(int n);\n int getFib(int n);\nprivate:\n std::vector<int> cache;\n}\n
cached_fib.cpp#include <iostream>\n#include <vector>\n#include \"cached_fib.h\"\n\nvoid CachedFib::CachedFib(int n) {\n cache.push_back(0);\n cache.push_back(1);\n for (int i = 2; i < n; i++) {\n cache.push_back(cache[i - 1] + cache[i - 2]);\n }\n}\n\nint CachedFib::getFib(int n) {\n if (cache.size() < n) {\n for (int i = cache.size(); i < n; i++) {\n cache.push_back(cache[i-1] + cache[i-2]);\n }\n }\n std::cout << cache[n - 1] << std::endl;\n}\n
test_cached_fib.cpp#include \"cached_fib.h\"\n#include \"gtest/gtest.h\"\n\nCachedFib::testFib;\n\nclass TestFib : public ::testing::Test {\nprotected:\n void Setup override {\n // Every time a test is started, testFib is reinitialized with a constructor parameter of 5\n testFib = CachedFib(5);\n }\n}\n\nTEST_F(TestFib, TestBasic) {\n ASSERT_EQ(getFib(5), 3) << \"5th fibonacci number must be 3!\";\n}\n\n// more tests\n
"},{"location":"reference/cpp/tools/#google-protocol-buffer","title":"Google Protocol Buffer","text":"Google Protocol Buffer (Protobuf) is a portable data serialization method. We use it over other methods like JSON and XML because it produces smaller binaries, an important consideration when sending data across an ocean. Unfortunately, there does not seem to be a easy to follow tutorial for using them, but here are the C++ basics. The page is quite dense and can be hard to follow, so do not worry if you do not understand it.
"},{"location":"reference/cpp/tools/#clang","title":"Clang","text":"In its most basic form, Clang is a compiler for the C language family. Clang has multiple benefits like easier portability compared to, for example, GCC. Clang is actually \"half\" the compiler, the other half being LLVM. Without going into unnecessary detail, Clang compiles C++ code to a generic language before LLVM compiles it to machine specific language.
"},{"location":"reference/cpp/tools/#clangd","title":"Clangd","text":"Clangd is the Clang language server. It provides a much more powerful intellisense than the default one used in VSCode's C/C++ extension.
"},{"location":"reference/cpp/tools/#clang-tidy","title":"Clang-Tidy","text":"Clang-Tidy is a linting tool, who's main purpose is to catch potential programming errors caused by bad programming style/practices using just static analysis.
"},{"location":"reference/cpp/tools/#clang-format","title":"Clang Format","text":"An autoformatting tool that makes enforcing style guidelines much easier. When se tup, it corrects formatting as soon as you hit save.
"},{"location":"reference/cpp/tools/#llvm-cov","title":"llvm-cov","text":"We will use llvm-cov to evaluate our test coverage. When used with genhtml, we can generate HTML reports that that show our line, function, and branch coverage line-by-line.
"},{"location":"reference/github/advanced_git/","title":"Advanced Git","text":""},{"location":"reference/github/advanced_git/#tutorial","title":"Tutorial","text":""},{"location":"reference/github/github_actions/","title":"GitHub Actions","text":""},{"location":"reference/github/github_actions/#tutorial","title":"Tutorial","text":""},{"location":"reference/github/workflow/branches/","title":"Developing on Branches","text":"We use branching to work on issues without modifying the main line. This ensures that the main line only contains functional code and handles merge conflicts that arise when multiple people are developing at the same time. For a quick rundown on branching in git, consult the official git documentation.
"},{"location":"reference/github/workflow/branches/#creating-a-branch","title":"Creating a branch","text":"When starting a new issue, you will want to create a new branch for it:
Caution
When creating branches locally, it uses your local copy to create the new branch. Remember to do a git pull
if you intend on using the latest changes from the remote branch you are creating from.
# Switch to main\ngit switch main\n\n# Update your local copy\ngit pull\n\n# Clone a new branch from main\ngit switch -c <branch_name>\n
IMPORTANT: When creating a new branch for an issue, you must create the branch from main
.
When working on a new issue, you will want to create a branch to work on it. We have the following branch naming convention:
<github_username>/<issue_number>-<issue_description>\n
Example
If Jill (GitHub Username: jill99) is going to take on an issue titled \"Fix bug on pathfinding software\" and the issue number is 39, then the branch named can be named something like user/jill99/39-fix-pathfinding-bug
.
If the branch that you are creating is not tied to an issue, then you do not need to put an issue number. A descriptive title will suffice.
"},{"location":"reference/github/workflow/branches/#tracking-and-committing-changes","title":"Tracking and committing changes","text":"All files where new changes have been made must first be \"staged\" in order to make commits:
git add <FILES>\n
Files that are staged will be part of your next commit. Once you are confident in your changes and you are ready to finalize them, then you should commit your changes:
git commit -m \"<commit_message>\"\n
Be sure to add a commit message that is descriptive of the changes that you made. It is encouraged that you make commits often so you can keep track of your changes more easily and avoid overwhelmingly large commits when you look back on your version history.
When you are ready to move your local changes to a remote branch, you want to push to the correct branch and potentially set the upstream if it does not yet exist:
git push -u origin <current_branch_name>\n
"},{"location":"reference/github/workflow/branches/#merging-branches","title":"Merging branches","text":"There may be times where you want to merge two branches together, whether you diverged on some ideas and finally want to synthesize them, or you just want to update your issue's branch with the main branch. In any case, merging branches will be inevitable as part of the development process, so it is essential to understand how to merge branches.
Merge Local BranchMerge Remote Branch# Checkout to destination branch\ngit checkout <dest_branch>\n\n# Merge with local copy of other branch\ngit merge <other_branch>\n
# Checkout to destination branch\ngit checkout <dest_branch>\n\n# Fetch from remote\ngit fetch\n\n# Merge remote copy of other branch\ngit merge origin/<other_branch>\n
Info
Merging a remote branch into its local counterpart using the method above is essentially the same operation as git pull
.
Once the merge operation is complete, your destination branch should have updates both from itself and the other branch that you merge. If you do a git log
, you will also see a new commit that indicates that the merge happened.
Merging two branches is not always easy since the commit history for both branches could look quite different, and therefore conflicting changes can easily be made. If you run into a scenario like this, you may get something like this:
Upon inspecting bar.txt
, we see the following:
Resolving merge conflicts is not always a trivial task, but there are many ways to resolve them which include:
Tip
If you cannot resolve a merge conflict on your own, reach out to your lead for help!
"},{"location":"reference/github/workflow/issues/","title":"Creating Issues","text":"GitHub issues lets us plan and track our work on GitHub.
"},{"location":"reference/github/workflow/issues/#getting-started-with-issue-templates","title":"Getting started with issue templates","text":"An issue is associated with a specific repository. To open the issues page for a given repository, click on the issues tab in the repository navigation bar.
You will see a list of current issues (if any) for the repository. To create a new issue, click on the New issue
button in the upper right corner.
When creating a new issue, you will see a few issue templates. Since issues can be created for a variety of reasons, issues may therefore be structured differently and contain different kinds of information. Issue templates were introduced to give us a quick and structured way to writing issues.
Note
GitHub issues are written using GitHub-flavoured markdown. To add a little spice to your issues, refer to the official GitHub documentation for some quick tips and tricks on how to write awesome markdown!
Click on the Get started
button to open the issue template. For this example, let's go with the New Feature
issue template. Upon opening the issue template, you should see a page like the one below:
At this point, you should give a succinct title and describe the issue in the textbox. You will also see some templated sections to fill out. Try to give only the necessary details to make a clear and concise issue. If you are unsure on how to construct your issue, take a look at current or past issues and ask the software leads for further guidance if necessary.
Finally, feel free to make suggestions on new templates or changing current templates!
Tip
We understand that some issues may need extra sections to describe the issue further, or some of the templated sections might not be relevant at all! Add or remove sections as necessary to get your point across. The goal of the issue templates is to provide guidance, not police your documentation methodologies!
"},{"location":"reference/github/workflow/issues/#adding-issues-to-a-project","title":"Adding issues to a project","text":"We use projects to plan and track the status of our issues and pull requests. To add an issue to an existing project, click on the gear icon in the Projects
section and add it to your desired project. You will almost always want to add your issue to the Software organization project.
To verify that your issue has been added to your desired project, go to the UBC Sailbot organization, go to the Projects
tab on the organization banner, and select the project that it is added to. When added to a project, it should show up under the General
tab (depending on the project, this might not always be the case).
We use milestones to track progress on groups of issues or pull requests that we want to complete by a certain date. Since our projects span over many years, it is important to work incrementally with small, yet achievable goals. If your issue should belong to a milestone, simply add it to a milestone by clicking on the gear icon in the Milestone
section and add it to your desired milestone.
Note
Unlike projects, milestones are strictly associated with a repository.
"},{"location":"reference/github/workflow/issues/#labelling-issues","title":"Labelling issues","text":"GitHub allows us to label our issues so that we can categorize them. It helps us identify at first glance what kind of a problem that an issue aims to solve and which issues are more important. To add a label to your issue, click on the gear icon in the Labels
section and add your desired label(s).
The issue templates will already have labels assigned to them, but you should add or remove labels as you see fit to make them as relevant as possible.
Note
Each repository might have different labels available, so be sure to check out all of the labels at least once in the repository that you are working in. Feel free to suggest additional labels as well!
"},{"location":"reference/github/workflow/issues/#adding-assignees","title":"Adding assignees","text":"Every issue should be assigned to at least one person to work on it. If you are not sure who should be assigned the issue initially, then don't worry about it for now since you can assign someone to the issue later on. To assign someone an issue, click on the gear icon in the Assignees
section and add the desired people.
Once you are finished writing your issue, click on the Submit new issue
button. You should now see your issue in the issues list and in the UBC Sailbot software project.
graph LR\n B[Problem Conception] --> C{Small Fix?};\n C --> |Yes| E[Development];\n C --> |No| D[Issue Creation];\n D --> E;\n E --> F[Pull Request];\n F --> G{Approved?};\n G --> |No| E;\n G --> |Yes| H[Merge PR into Main];
A good development workflow is essential to maintain a robust codebase and stay organized. The above diagram is a high level overview of how our development process works, and parts of this process are explained in subsequent sections.
"},{"location":"reference/github/workflow/overview/#tutorial","title":"Tutorial","text":""},{"location":"reference/github/workflow/overview/#version-control-git","title":"Version control: Git","text":"We use git to help us keep track of the version history of our codebase. Git is a free and open source distributed version control system, and it is commonly used by many developers to keep track of changes to their code over time. As a member of the software team on UBC Sailbot, it is absolutely necessary that you know git. If you are unfamiliar with git, here are a few resources to help you get started:
Resource Description Beginners Tutorial A 30 minute video on git for beginners. Good if you want to learn git quickly and nail all the fundamentals. Pro Git book A textbook on using git. Good if you are a completionist and want to deep dive into how git works (and if you have some time on your hands). Common Git Commands A condensed summary of some common git commands. Good to refer to once you are familiar with the fundamentals of git."},{"location":"reference/github/workflow/overview/#remote-server-github","title":"Remote server: GitHub","text":"We use GitHub as our remote server where we store our codebase. In addition to using it for storage, we also leverage many of GitHub's features to make for a smoother development process. Some examples of features that we use are:
Pull requests are used to verify code functionality and quality of a development branch before merging into the main branch, accomplished through CI and code reviews.
Note
Pull requests are much like issues where we can do many of the same things. This goes for creating comments in markdown, assigning reviewers, adding labels, adding projects, or adding milestones. Sometimes we skip writing an issue when the change is relatively small.
"},{"location":"reference/github/workflow/pr/#creating-a-pull-request","title":"Creating a pull request","text":"To create a pull request in a repository, to go the Pull requests
tab and then click New pull request
:
On the next screen, you need to select the base branch that you are merging into, and the branch that you are comparing. For the most part, the base branch will be the main branch, and the branch that you are comparing will be the issue branch.
Once you have decided on your base and compare branches, click on Create pull request
. You should see the page below (looking in the dropdown menu, you can open the pull request as a draft to avoid notifying reviewers until you are ready):
Notice how this is remarkably similar to the page of an issue. To link a pull request to an issue, simply add <KEYWORD> #<ISSUE NUMBER>
to the initial comment in the pull request. A list of valid keywords can be found here.
Example
\"This issue resolves #49. Please review my pull request!\"
Observe that the right-hand side banner contains the following:
Field Description Reviewers Assign reviewers to review your pull request. Always try to assign at least one reviewer. Assignees Assign the people who worked on the issue. Labels Assign labels to categorize pull requests. Projects Assign a pull request to a project. Milestone Assign a pull request to a milestone.Attention
If you linked the pull request to an issue, you should not add the pull request to a project or a milestone to avoid duplicate cards.
"},{"location":"reference/github/workflow/pr/#merging-into-main","title":"Merging into main","text":"Once the pull request and code reviews are complete, it is time to merge the changes in the pull request into the main branch! However, this can only be done when the following conditions are met:
If all of these conditions are met, confirm that the merge is good to go by clicking Squash and merge
:
A common activity that you will participate in is reviewing pull requests to give your feedback on other's code. You will be notified when you have been requested to review a pull request and should promptly review it as soon as time permits.
In particular, you will most likely be doing the following in a pull request:
At UBC Sailbot, we follow standards in how we code to maintain a clean and comprehensible codebase. This page addresses what conventions we use specifically when programming in Python and the tools to help us maintain these conventions.
"},{"location":"reference/python/conventions/#style-guide","title":"Style guide","text":""},{"location":"reference/python/conventions/#linting","title":"Linting","text":"To ensure that the codebase stays clean, we use flake8, which is a tool for style guide enforcement mostly based off pep8. To automate most of this process, we use autopep8, which is a tool that resolves most style issues. However, there will be some issues that must be resolved by you!
Refer to this guide on how to write readable code in python with the pep8 style guide.
Note
Our CI automatically checks that your code follows the pep8 standard. If it does not, your pull requests will be blocked from being merged until those issues are resolved!
"},{"location":"reference/python/conventions/#type-hinting","title":"Type hinting","text":"Even though Python is a dynamically typed language, newer versions support type hinting. Type hinting catches errors, documents code, improves IDEs and linters, and helps build and maintain a clean software architecture.1 Expanding on how it catches errors, a static type checker such as mypy
can be used.
There is some syntax to get familiar in order to use type checking. We recommend the following resources:
Below are a few examples of using type hinting:
Return the sum of a sequencefrom typing import Sequence, Union\n\n\nNumber = Union[int, float]\n\n\ndef sumseq(seq : Sequence[Number]) -> Number:\n return sum(seq)\n
Function with optional parameters and default values from typing import Optional\n\n\ndef printArgs(a : str, b : str=\"World\", c : Optional[str]=None) -> None:\n print(f\"Value of a: {a}\")\n print(f\"Value of b: {b}\")\n if c is not None:\n print(f\"Value of c: {c}\")\n
Function with custom class class MyClass:\n def __init__(self) -> None:\n pass\n\n\ndef foo(a : MyClass) -> None:\n print(a)\n
Forward referencing a class With __future__
Without __future__
from __future__ import annotations\n\n\ndef foo(a : MyClass) -> None:\n print(a)\n\n\nclass MyClass:\n def __init__(self) -> None:\n pass\n
def foo(a : 'MyClass') -> None:\n print(a)\n\n\nclass MyClass:\n def __init__(self) -> None:\n pass\n
Function that never returns from typing import NoReturn\n\n\ndef bar() -> NoReturn:\n while True:\n print(\"Hello World!\")\n
"},{"location":"reference/python/conventions/#documentation","title":"Documentation","text":"Code is written once and read a thousand times, so it is important to provide good documentation for current and future members of the software team. The major things that we document in our code are:
Ideally, the third point should be avoided as much as possible since we would want our code to be self explanatory. It should be done only when absolutely necessary.
"},{"location":"reference/python/conventions/#generating-docstrings","title":"Generating docstrings","text":"We use a vscode extension called autoDocstring which autogenerates docstrings that we use to document our code. To install this extension, go to the Extensions
tab in vscode and search autoDocstring
in the marketplace.
To generate docstrings, type \"\"\"
at the beginning of the function that you want to document and the template will be generated for you! If you use type hinting, this extention will autofill some of the documentation for you!
Note
The autoDocstring extension only works for functions. It does not work for classes and objects, so documenting these will have to be done manually. Be sure to follow the same format used by functions.
"},{"location":"reference/python/conventions/#example-on-documentation","title":"Example on documentation","text":"It's hard to imagine what good documentation looks like. We provide a few examples below of documenting code using the autoDocstring extension. The extension uses Google style docstrings by default.
Documentation example on a functionfrom typing import List\ndef inner_product(v1 : List[float], v2 : List[float]) -> float:\n \"\"\"\n Computes the inner product between two 1D real vectors. Input vectors should have the\n same dimensions.\n\n Args:\n v1 (List[float]): The first vector of real numbers.\n v2 (List[float]): The second vector of real numbers.\n\n Returns:\n float : The inner product between v1 and v2\n \"\"\"\n assert (len(v1) == len(v2)), \"Input lists must have same length\"\n\n # Iterate through elementwise pairs\n summation = 0\n for e1, e2 in zip(v1, v2):\n summation += (e1 * e2)\n return float(summation)\n
Documentation example with a stack from typing import Any\nclass Stack:\n\n \"\"\"\n This class represents a stack, which is an abstract data type that serves as a collection of\n elements. The stack is a LIFO datastructure defined by two main operations: Push and Pop.\n\n Attributes:\n __stack (List[Any]): A list containing the elements on the stack.\n \"\"\"\n\n def __init__(self):\n \"\"\"\n Initializes the Stack object.\n \"\"\"\n self.__stack = []\n\n def push(self, element : Any) -> Any:\n \"\"\"\n Pushes an element to the top of the stack.\n\n Args:\n element (Any): The element to be pushed on to the stack.\n \"\"\"\n self.__stack.append(element)\n\n def pop(self) -> Any:\n \"\"\"\n Removes the element at the top of the stack and returns it. If the stack is empty,\n then None is returned.\n\n Returns:\n Any, NoneType: The element at the top of the stack.\n \"\"\"\n if self.is_empty():\n return None\n else:\n return self.__stack.pop()\n\n def is_empty(self) -> bool:\n \"\"\"\n Determines whether the stack is empty or not.\n\n Returns:\n bool: Returns True if the stack is empty, and False otherwise.\n \"\"\"\n empty = (len(self.__stack) == 0)\n return empty\n\n def __len__(self) -> int:\n \"\"\"\n Gets the number of elements on the stack.\n\n Returns:\n int: The number of elements on the stack.\n \"\"\"\n length = len(self.__stack)\n return length\n
For more examples, see Example Google Style Python Docstrings.
https://realpython.com/lessons/pros-and-cons-type-hints/ \u21a9
We use Python 3 to write the majority of our software at UBC Sailbot. Pathfinding and Controls mainly use Python 3, so it is critical that you are familiar with the language if you are on one of these sub-teams.
"},{"location":"reference/python/start/#python-tutorials","title":"Python tutorials","text":"We understand that not everyone who joins Sailbot has Python in their toolkit, nor do we expect it either! Whether you are learning Python for the first time or you just want to brush up, we have provided some resources below. You may not learn absolutely everything from the resources below, but it is a good starting point. You will mostly learn through doing, as you would with most technical skills!
Resource Description The Python Tutorial The official python tutorial. Good if you have some time on your hands and you are a completionist. Sections 1 - 5 and 9 are the most relevant. w3schools Tutorial Good if you want a more brief introduction to Python. It breaks down a lot of concepts into sections. Everything up to Python Classes/Objects is relevant. YouTube Tutorial If you like video tutorials, then we recommend this tutorial. This video is about 5 hours long, but it pretty much covers everything that you'll need to know for Python and there are some hands on projects. Shorter YouTube Tutorial A shorter alternative YouTube tutorial condensed into 1 hour. It covers less material but still covers many of the essentials. CodingBat Practice Good resource to put your Python skills to practice on some simple coding problems. Note that this resource does not teach you python.Feel free to add other resources other than the ones listed above if you find any that you like!
"},{"location":"reference/python/virtual-environments/","title":"Virtual Environments","text":"The Python virtual environment is a tool for dependency management and project isolation. They solve many common issues, including:
Dependency Resolution: A project might want a package with version A while another project might want a package with version B. With a virtual environment, you can separate which packages that you want to use for a given project.
Project Isolation: The environment for your project is self-contained and reproducible by capturing all dependencies in a configuration file.
Housekeeping: Virtual environments allow you to keep your global workspace tidy.
There are two main methods of creating virtual environments: virtualenv and Anaconda. Each have their own benefits and drawbacks. Here are some differences between the two:
Virtualenv Anaconda Environment files are local. Environment files are available globally. Must activate environment by giving the path. Can activate the environment without knowing the path, but only the name. Can only usepip
to install packages. Can either use pip
or built-in conda
package manager. Installation is very simple. Installation takes more effort. Can only install python packages. In addition to packages, you can download many data science tools. We recommend virtualenv over Anaconda because of its simplicity. However, feel free to appeal to your preferences.
"},{"location":"reference/python/virtual-environments/#installation","title":"Installation","text":"Virtualenv AnacondaIf you already have python and the pip package manager installed, just execute the following:
Using pip to install virtualenvpip install virtualenv\n
Go to the official Anaconda website and follow the installation instructions for your operating system.
"},{"location":"reference/python/virtual-environments/#using-virtual-environments","title":"Using virtual environments","text":"The name of a virtual environment is configurable. For the purposes of this site, we will use env
as the environment name unless specified otherwise.
Since virtualenv creates the environment directory in a specific location, make sure that you are in the located in the project that you want to work on.
Create virtual environment with virtualenv# Go to desired location\ncd <PATH TO DIRECTORY>\n\n# Create the environment with the name env\npython3 -m venv env\n
Verify that your environment is created by examining your current directory and look for the directory that matches the name of your virtual environment.
Since the environment will be available globally, there is no need to go to a specific location to create it.
Create virtual environment with Anaconda# Create environment with name env and python version\nconda env create -n env python=<PYTHON VERSION NUM>\n
If you don't specify a python version, the default is the version you used when you downloaded and installed Anaconda. Verify that your environment is created by executing conda env list
.
To use the virtual environment, you must activate it.
Virtualenv Anaconda Windows macOS Linux Activation for Windowsenv\\Scripts\\activate\n
Activation for macOSsource env/bin/activate\n
Activation for Linuxsource env/bin/activate\n
Activation for Anacondaconda activate env\n
After activating your virtual environment, you might see (env)
on your terminal before or after your current line. Now you are in your virtual environment!
Any dependencies that you install while your virtual environment is activated are only available in your virtual environment. If you deactivate your environment and try to use those dependencies, you will find that you will get errors because they will not be found unless you install those dependencies in the other environment!
Virtualenv AnacondaUse the pip
package manager to install python dependencies. Before installing any Python dependencies, it is good practice to upgrade pip
:
pip install --upgrade pip\n
Now, install any Python dependencies pip
:
pip install <PACKAGE>\n
Option 1: pipOption 2: conda Use the pip
package manager to install python dependencies.
# Install pip using conda\nconda install pip\n\n# Install python packages using pip\npip install <PACKAGE>\n
Use the built-in conda
package manager to install python dependencies.
conda install -c <CHANNEL> <PACKAGE>\n
Sometimes, installing a package like this simply won't work because you are not installing from the correct channel. You usually will have to google the command to use in order to install your package correctly because it usually comes from a specific channel that you don't know about. Some common channels to try are:
When you are finished using your virtual environment, you will need to deactivate it.
Virtualenv Anaconda Deactivate virtualenv environmentdeactivate\n
Deactivate anaconda environmentconda deactivate\n
"},{"location":"reference/python/virtual-environments/#reproducing-your-virtual-environment","title":"Reproducing your virtual environment","text":"When you want to share your code with others, it is important for others to be able to reproduce the environment that you worked in. We discuss two topics in this section: exporting your environment and reproducing the environment.
"},{"location":"reference/python/virtual-environments/#exporting-your-virtual-environment","title":"Exporting your virtual environment","text":"In order to reproduce your virtual environment, you need to export some information about your environment. Be sure to follow the instructions below while your environment is activated.
Virtualenv AnacondaYou will create a requirements.txt
file, which essentially lists all of your python dependencies in one file:
pip freeze > requirements.txt\n
The pip freeze
command prints all of your pip dependencies, and > requirements.txt
redirects the output to a text file.
Anaconda uses configuration files to recreate an environment.
Windows macOS LinuxExecute the following command to create a file called environment.yml
:
conda env export > environment.yml\n
Then, open the environment.yml
file and delete the line with prefix:
.
Execute the following command to create a file called environment.yml
:
conda env export | grep -v \"^prefix: \" > environment.yml\n
Execute the following command to create a file called environment.yml
:
conda env export | grep -v \"^prefix: \" > environment.yml\n
"},{"location":"reference/python/virtual-environments/#reproducing-the-environment","title":"Reproducing the environment","text":"You can reproduce your virtual environment when given the information about it. The steps above tell you how to extract the information, and now we will use that information to recreate the virtual environment. Remember to deactivate the current environment before making a new environment.
Virtualenv AnacondaWe use the requirements.txt
file that we generated earlier to recreate the environment.
# Create the new environment\npython -m venv <NEW ENV NAME>\n\n# Activate the environment\nsource <NEW ENV NAME>/bin/activate\n\n# Install dependencies\npip install -r <PATH TO requirements.txt file>\n
We use the environment.yml
file that we generated earlier to recreate the environment.
# Create the new environment with the dependencies\nconda env create -f <PATH TO environment.yml> -n <ENV NAME>\n
"},{"location":"reference/python/virtual-environments/#official-references","title":"Official references","text":"In this section, we summarized what virtual environments are, why they are used, and how to use them. We did not cover all of the functions of virtual environments, but feel free to consult the official references to learn about virtual environments more in depth.
This section explains the most unfamiliar fields that we receive from the AIS.
"},{"location":"reference/sailing/ais_terms/#mmsi-aka-id","title":"MMSI a.k.a ID","text":"A 9-digit, unique identification number for the ship.
"},{"location":"reference/sailing/ais_terms/#cog-course-over-ground","title":"COG: Course over Ground","text":"The direction the boat is travelling, relative to the sea floor. This is the direction of the rate of change of the Track Made Good.
This is measured with the navigational angle convention, where 0\u00b0 is towards the North, and angles increase in the clockwise direction. If we make the slight simplification of neglecting the effect of the wind, then
The speed the boat is travelling at, relative to the sea floor. This is the magnitude of the rate of change of the Track Made Good.
\\(\\begin{align*} \\text{SoG} &= \\left|\\frac{d}{dt} \\overrightarrow{(\\text{Track Made Good})} \\right|\\\\ \\end{align*}\\)
If we make the slight simplification of neglecting the effect of the wind, then
The angular velocity of the boat (how fast it's turning), measured in degrees per minute.
"},{"location":"reference/sailing/boat_parts/","title":"Parts of a Sailboat","text":"This page names some important parts of a sailboat, and explains what the part is for. Read the descriptions of the parts below, and refer to the image to see where the part fits in.
"},{"location":"reference/sailing/boat_parts/#hull","title":"Hull","text":"The Hull is the \"boat\" part of the boat, which displaces water to create buoyancy. The following parts of the boat are attached to the hull:
It is also helpful to know the names of the following \"regions\" of the hull:
The image below shows a birds-eye view of the outline of a hull of a sailboat, where the \"regions\" of the hull are labeled.
"},{"location":"reference/sailing/boat_parts/#jib","title":"Jib","text":"The Jib is the sail located near the bow, and is the smaller of the two sails.
The Mast is the long vertical pole which connects to hull. It holds up the sails and some instruments.
The following instruments are at the top of the mast:
The mast is held upright by three lines:
The Main Sail is the larger of the two sails, and is located aft of the mast. Most of the boat's propulsion comes from the main sail.
Hopefully this section helped you gain familiarity with some common sailing terms. It likely feels like this section contains a lot of new information. It's unrealistic to remember it all perfectly, but make an effort to remember the terms which are Bolded and Italicized.
"},{"location":"reference/sailing/boat_parts/#keywords-on-this-page","title":"Keywords on this Page","text":"This section covers some other useful information.
"},{"location":"reference/sailing/miscellaneous/#wind-direction-convention","title":"Wind Direction Convention","text":"Generally speaking, there are two ways to use an angle to describe the wind direction.
In sailing, we normally talk about \"where the wind is coming from\". Somehow this ends up being more intuitive when talking about maneuvers or sail angle adjustments.
However, when describing the wind as a vector, it can make more sense for the vector to represent the actual speed and direction the air is flowing. Make sure to document which convention you are using in your work when its applicable, and don't be afraid to ask someone to clarify which convention they are using in their work.
"},{"location":"reference/sailing/miscellaneous/#navigation-terms","title":"Navigation Terms","text":""},{"location":"reference/sailing/miscellaneous/#heading","title":"Heading","text":"In navigation generally (outside of Sailbot), the Heading is the direction the bow of the boat is pointing towards. Headings are typically (but not always at Sailbot) measured relative to true North in the clockwise direction.
"},{"location":"reference/sailing/miscellaneous/#bearing","title":"Bearing","text":"A Bearing is used to describe one point in relation to another: the Bearing of point \"A\" from point \"B\" is the direction you would would look towards if you wanted to see point \"A\" while standing at point \"B\". A Range is the distance between points \"A\" and \"B\", so that a Bearing and Range together can locate point \"A\" relative to point \"B\" in polar co-ordinates. There are two main ways of measuring bearings:
In the example below, the boat \"B\" has a Heading (H) of 30\u00b0. The True Bearing (\\(B_t\\)) of the Lighthouse \"A\" from the boat is 90\u00b0. The Relative Bearing (\\(B_r\\)) of the lighthouse from the boat is 60\u00b0.
"},{"location":"reference/sailing/miscellaneous/#track-made-good","title":"Track Made Good","text":"Boats do not necessarily travel in the same direction as their Heading, due to the effects of ocean current and wind. The path the boat has traveled relative to the sea floor is called the Track Made Good. This is the same as if you measured motion compared to land or with a GPS.
"},{"location":"reference/sailing/miscellaneous/#heading-and-bearing-in-raye-project","title":"Heading and Bearing in Raye Project","text":"In Sailbot's Raye project, Heading and Bearing are used to refer to different conventions for describing which way the boat is pointing. The following 3 pieces of information are needed to unambiguously define an angle measuring convention:
Some common examples of angle measuring conventions which we use are:
The specific angle conventions which we call Heading and Bearing can be ambiguous, and may be subject to change, so they are deliberately omitted here. Refer to the applicable source code to determine what the angle conventions are.
"},{"location":"reference/sailing/miscellaneous/#true-apparent-and-boat-wind","title":"True, Apparent, and Boat Wind","text":"In the example below, suppose the wind is blowing from the North at 4 m/s, and suppose the boat is moving towards the East at 3 m/s.
In the Types of Turn page, we discussed how a Tack is a type of turn. Weirdly, the word \"tack\" actually has two more distinct meanings in sailing. The word \"Tack\" can refer to:
In order to make high-quality contributions to Sailbot's Software teams, it is extremely helpful to have some understanding of sailing. This section introduces important parts of a sailboat, explains the 4 types of turns, discusses upwind and downwind sailing, and covers some other helpful knowledge.
In this section, terms which are Bolded and Italicized are the most important terms to know. These terms are listed at the bottom of each page. Terms that are only Italicized are other helpful sailing terms. Words that are bolded are meant to be emphasized, but are not necessarily considered important vocabulary.
"},{"location":"reference/sailing/overview/#tutorial","title":"Tutorial","text":""},{"location":"reference/sailing/points_of_sail/","title":"Points of Sail","text":"In sailing, we sometimes talk about different angles that we can sail on with respect to the wind. Ranges of angles which are close together have special names. These ranges are called points of sail. The discussion below coveres the most important points of sail for software members to understand.
Notice how for higher points of sail (points of sail closer to straight into the wind), the sail is pulled tightly in to the boat. If the boat is on a lower point of sail, the sails should be let further out of the boat. For any point of sail, there is an optimum angle that the sail should be adjusted to. If the sails are adjusted too far in or too far out, the boat will not go as fast as it could if the sails were adjusted correctly.
"},{"location":"reference/sailing/points_of_sail/#irons","title":"Irons","text":"The range of angles where the boat is roughly pointing straight into the wind are called Irons, or the No-Go Zone. If the boat is pointing in these directions, the sails will be flapping regardless of how the sheets are adjusted. When the sails are flapping, they are not catching the wind in a way that can propell the boat forwards. When the boat looses propulsion, water stops flowing over the rudder, and the boat loses steering. This is why we want our sailbots to avoid being stuck in irons.
"},{"location":"reference/sailing/points_of_sail/#upwind-sailing","title":"Upwind Sailing","text":"If we want to sail to a destination that is not on too high or low of an angle upwind or downwind from our starting position, we can just point our boat in that direction, adjust our sails, and go there.
However, sometimes we want to sail to a destination that is straight upwind of our starting position. To get there, we will need to do upwind sailing. Since we can't point our boat directly into the wind, we need to sail on an angle on the edge of irons. We will need to tack back and forth every now and then if we want to go directly upwind. The point of sail on the edge of Irons is called Close Hauled.
"},{"location":"reference/sailing/points_of_sail/#downwind-sailing","title":"Downwind Sailing","text":"Raye also avoids sailing straight downwind. This means that to reach a goal downwind of the starting position, we need to gybe back and forth in a zig-zag pattern. The point of sail straight downwind is called a run, and the next point of sail higher than a run is called a broad reach.
"},{"location":"reference/sailing/points_of_sail/#keywords-on-this-page","title":"Keywords on this Page","text":"In sailing, there are 4 distinct types of turns. Read the descriptions below, and observe how they fit into the diagrams.
Note that any of these types of turn can be done in either the clockwise or counter-clockwise directions.
"},{"location":"reference/sailing/turning/#classifying-types-of-turns-summary","title":"Classifying Types Of Turns Summary","text":"The following flowchart summarizes how to distinguish between different types of turns. Note:
graph LR\n B[Classify a Turn] --> C{Does the sail change<br/>sides during the turn?};\n C --> |Yes| E{Which end of<br/>the boat is upwind<br/>during the turn?};\n C --> |No| D{Does the<br/>boat point higher<br/>or lower at the end<br/>of the turn?};\n D --> |Higher| F[Heading Up];\n D --> |Lower| G[Bearing Off];\n E --> |Bow| H[Tack];\n E --> |Stern| I[Gybe];
The diagrams in this section show outlines of the hull of a boat and its main sail going through turns. As is common in these types of diagrams, assume that the wind is blowing down from the top of the screen unless there is an arrow that indicates otherwise.
"},{"location":"reference/sailing/turning/#heading-up","title":"Heading Up","text":"When the boat makes any turn as follows, it is called Heading Up:
Unlike some of the other turns listed here, heading up can be a large turn or a small course adjustment of just a few degrees.
The image below shows a boat heading up. Notice how the sail stays on the starboard side of the boat.
"},{"location":"reference/sailing/turning/#bearing-off","title":"Bearing Off","text":"When the boat makes any turn as follows, it is called Bearing Off:
Like heading up, bearing off can be a small course adjustment.
"},{"location":"reference/sailing/turning/#tacking","title":"Tacking","text":"When the boat makes any turn as follows, it is called a Tack or Tacking:
Notice how at some point throughout this turn, the boat will be pointing straight into the wind. While the boat points nearly straight into the wind, the sails don't generate any forward propulsion. This means that a tack must be a large (at least ~90\u00b0) turn all at once, so that the boat's momentum carries it through the range of angles where it does not get propulsion.
"},{"location":"reference/sailing/turning/#gybing","title":"Gybing","text":"When the boat makes any turn as follows, it is called a Gybe or Gybing.
When sailing on most angles relative to the wind, the sail is always blown to the downwind side of the boat. However, sailing nearly straight downwind, both sides of the boat are equally \"downwind\" relative to eachother. This means that the sail can be on either side of the boat.
The sail propells the boat throughout a gybe, so it is possible to conduct the turn more gradually than a tack. However, because the sail can be on either side, the sails can switch sides in an uncontrolled way as the boat moves in the waves. For this reason, Raye avoids sailing on angles close to straight downwind, and gybes by doing a quick ~60\u00b0 turn.
Note that \"gybe\" is the spelling used in Canadian and British english, whereas in American english it is spelled \"Jibe\"
"},{"location":"reference/sailing/turning/#combinations-of-turns","title":"Combinations of Turns","text":"Of course, it is possible to do two or more of these types of turns in one continuous motion. What two types of turns does the boat do in the image below?
Answer: In the turn shown by the first arrow, the sail stays on the port side of the boat while it steers to point further downwind. This means that the first part of the maneuver is bearing off. In the next part of the maneuver, the sail changes sides and the stern of the boat is upwind of the bow. This part of the maneuver is a gybe.
"},{"location":"reference/sailing/turning/#keywords-on-this-page","title":"Keywords on this Page","text":"