Skip to content

Cyclone-Robosub/sys-arch-2026

Repository files navigation

Systems Architecture 2026

The new and improved codebase for 2026 (and hopefully beyond)!

This will contain the ROS nodes, topics, etc. developed by the Systems Architecture subteam of UC Davis Cyclone Robosub. It will also contain C code auto-generated by Matlab to be used in the robot control system.


Quickstart

  1. Clone the repository:
git clone https://github.com/Cyclone-Robosub/sys-arch-2026.git && cd sys-arch-2026
  1. Build by running:
colcon build
  1. Start tmux session: You may look inside start_tmux_session.sh and comment/uncomment components as needed.
chmod +x start_tmux_session.sh
./start_tmux_session.sh

Running unit tests

  1. Run colcon build
  2. Run colcon test --parallel-workers 1

This argument is needed to prevent node tests from interfering with each other: if different tests create publishers and subscribers on the same topic, this can create unexpected behaviour!

  1. If there are any errors, view them with colcon test-result --verbose | less

How to use launch files

Launch files are a alternative to bash script for runnign ROS nodes

  1. Run colcon build in the workspace
  2. Run source install/setup.bash
  3. Run ros2 launch $pkg_name $launch_file_name wher the pkg_name is the name of the package and launch_file_name is the name fo the launch file.
  4. For example, the command for the pwm_ci package would be ros2 launch pwm_cli cli_launch.py (presuming you have done step 1 and 2)
.
├── onboard
│   └── src
│       ├── cli
│       │   ├── cli
│       │   │   ├── __init__.py
│       │   │   └── cli.py
│       │   ├── launch
│       │   │   └── cli_launch.py

For information on nodes, topics, etc. check the README.md files within the packages themselves.

How to Run the Robot with Manual Control Mode

Overview

At a high level, running the robot manually requires remotely connecting to the Pi 5 through ssh, starting up the necessary ROS nodes, and connecting a gamepad. The processes you'll need running include the following:

  • thrust_interface: sends PWM signals to the thrusters via a Raspberry Pi Pico
  • soft_mux: chooses whether to listen to the Matlab controls code or to the command line tool (CLI) for thruster data
  • mux_controller: provides a simple interface to switch between the soft_mux inputs
  • inertial_sense: provides IMU (sensor) data to the Matlab code
  • index.html: the webpage that connects to the gamepad
  • rosbridge_server: connects the gamepad data to the Matlab code
  • simple_joystick_controller: interprets gamepad inputs and converts them to thruster power values

The "Background" section provides some context on Linux and using the terminal. Feel free to skip past bits that aren't interesting or relevant. They are helpful for understanding the commands you're typing, but if you'd rather just blindly paste them in then you can skip ahead to the "Running the Robot" section.

There is also a script that you can run that starts up all the robot components automatically. If it works properly, your work is greatly simplified: you have to do little more than ssh to the Pi 5 and run the script! If it doesn't work properly, you'll need to follow the step by step instructions in this guide under "Running the Robot Manually (If Script Fails)".

Running the Robot

How to Connect to the Pi 5

Steps

Type the following into the terminal, followed by Enter:

  1. ssh pi5

Expected Output

Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-1044-raspi aarch64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Suport:         https://ubuntu.com/pro

 System information as of Fri Jan 30 17:14:11 PST 2026

  System load:  1.71                Temperature:            56.1 C
  Usage of /:   29.3% of 116.68GB   Processes:              188
  Memory usage: 4%                  Users logged in:        0
  Swap usage:   0%                  IPv4 address for wlan0: 100.126.159.3

 * Stricly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s just raised the bar for easy, resilient and secure K8s cluster deployment.

 https://ubuntu.com/engage/secure-kubernetes-at-the-edge

Expanded Security Maintenance for Applications is not enabled.

502 updates can be applied immediately.
To see these additional updates run: apt list --upgradable

67 additional security updates can be applied with ESM Apps.
Learn more about enablign ESM Apps service at https://ubuntu.com/esm

Last login: Fri Jan 30 17:07:04 2026 from 169.254.178.230
propulsion@cyclonepropulsion:~$ 

Explanation

Connecting to the Pi 5 is done through ssh. First, make sure that the robot is powered on and the Pi 5 has a green LED on near the power port. Open a terminal on the local machine, and type ssh pi5. If you get the message

ssh: Could not resolve hostname cyclonepropulsion.local: Name or service not known

then ssh was unable to connect to the Pi 5. Check the Ethernet connection between the robot and the local machine: there should be LEDs turned on on the local machine's Ethernet port. If the robot was only recently turned on, the Pi 5 might just need a little bit longer to boot up.

If you are successful, you should get a message similar to the expected output above.This means that are you are connected to the Pi 5. Any commands that you run from this terminal tab will run on the Pi 5 rather than the local machine.

If you open a new terminal tab or window, you will need to reconnect to the Pi 5 in that tab or window. Again, you can verify that you are on the correct machine by checking the hostname (see "Understanding Local Machine vs Pi 5").

Running the Robot with the Bash Script (Preferred)

Steps

Type the following into the terminal, followed by Enter:

  1. ssh Pi5
  2. cd ~/sys-arch-2026
  3. git pull
  4. colcon build
  5. ./start_tmux_session.sh
  6. 1

Expected output

When you type git pull, you should expect to see either a long list of changes, or a short message saying that it was already up to date.

When you type colcon build, you should see a list of nodes being built. Don't worry if you see something like:

WARNING:colcon.colcon_cmake.task.cmake.build:Could not run installation step for package 'InertialSenseSDK' because it has no 'install' target

and/or:

RESOLVED_ROS_DIR="/home/william/Repos/sys-arch-2026/onboard/src/imu/ros2_ws/src/inertial-sense-sdk/ROS/ros2"

ABSOLUTE_SCRIPT_PATH="/home/william/Repos/sys-arch-2026/onboard/src/imu/ros2_ws/src/inertial-sense-sdk/scripts/build_is_sdk.sh"

These messages are totally fine, and don't indicate an issue.

After typing ./start_tmux_session.sh, the screen should open with four panes. In the top-left should be thrust_interface: it might have a few warning messages about not connecting to the soft_mux, although if not that is also fine. In the top-right should be the soft_mux, which will probably be repeatedly listing a notice about not being able to hear a heartbeat from Matlab. If it says that it can't hear a heartbeat from cli, then type 1 again and press Enter. In the bottom-left should be the mux_controller, which should provide a short list of prompts and a text entry field. In the bottom-right should be a terminal-based task manager program called btop.

Explanation

colcon build is the command to compile all the components for the robot. You only need to run this once, because once the code is compiled as long as no code changes are made, the compiled code is still correct.

source install/setup.bash is a bash script. A bash script is a file that contains a list of terminal commands for the computer to follow. When you run the bash script, it will execute the commands in order, allowing the automation of complicated or repetitive processes. This bash script is automatically generated by ROS after you run colcon build, and configures your terminal environment for running ROS nodes. If you miss this step, you might get error messages abut unknown message types when you try to run the nodes.

start_tmux_session.sh is another bash script, but one that we wrote (rather than generated by ROS). It launches a tmux session with all the necessary robot nodes started.

To run the script, first make sure you're ssh'd to the Pi 5. Then, move to the sys-arch-2026 folder by typing cd ~/sys-arch-2026. The terminal prompt should now be updated to:

cyclone@cyclonepropulsion:~/sys-arch-2026$

From there, type ./start_tmux_session.sh. This will launch a new tmux session, splitting your terminal window into multiple panes, each running a component of the robot code. You will need to switch the focus to the mux_controller pane (the one with some text at the top indicating the current robot control mode, probably cli at first) and switch it to Matlab mode by typing 1 into the prompt and pressing Enter. You should see the mode at the top change to matlab (ctrl).

That's all that you need to do on the robot side! You still have to run the joystick processes, but these should be done on the local machine rather than the Pi 5.

Running the Robot Manually (If Script Fails)

Steps

Type the following into the terminal, followed by Enter:

  1. ssh pi5
  2. cd ~/sys-arch-2026
  3. git pull
  4. colcon build
  5. source install/setup.bash
  6. ros2 run thrust_interface thrust_interface

Then open a new terminal tab, and type:

  1. ssh pi5
  2. cd ~/sys-arch-2026
  3. source install/setup.bash
  4. ros2 run soft_mux soft_mux

Then open a new terminal tab, and type:

  1. ssh pi5
  2. cd ~/sys-arch-2026
  3. source install/setup.bash
  4. ros2 run mux_interface mux_interface
  5. 1

Then open a new terminal tab, and type:

  1. ssh pi5
  2. cd ~/sys-arch-2026
  3. source install/setup.bash
  4. ros2 run inertial_sense_ros2 inertial_sense_ros2_node

Expected Output

The first tab should be running thrust_interface: it might have a few warning messages about not connecting to the soft_mux, although if not that is also fine.

The second tab should be running the soft_mux, which will probably be repeatedly listing a notice about not being able to hear a heartbeat from Matlab. If it says that it can't hear a heartbeat from cli, then type 1 again on the mux_interface tab and press Enter.

In the third tab should be the mux_controller, which should provide a short list of prompts and a text entry field.

In the fourth tab should be a constant stream of data from the IMU. If not, the IMU may not be properly connected to the robot.

Explanation

The first collection of steps starts the thrust_interface node. This node connects to the Pi Pico (the small microcontroller next to the Pi 5), which actually sends the signals that control the thrusters.

The second collection of steps starts the soft_mux node, which manages whether the robot is listening to the Matlab/controls code or the command line tool.

The third collection of steps starts the mux_interface node, which provides a basic user interface to switch which mode the mux is in. By then typing 1, you switch it to listen to the Matlab control code rather than the CLI (which doesn't currently exist).

The fourth collection of steps starts the intertial_sense node, which listens to the IMU and reports its data back over ROS.

Running Gamepad Processes

Unfortunately, there is no script for this one: the commands must be typed manually. Fortunately, it's not too difficult compared to the robot commands.

It is important that simple_joystick_controller is run from the local machine rather than the Pi 5.

Steps

On the local machine, type the following into the terminal, followed by Enter:

  1. cd ~/sys-arch-2026
  2. git pull
  3. colcon build
  4. source install/setup.bash
  5. ros2 run simple_joystick_controller Simple_Joystick_Controller

Then open a new terminal tab, and type:

  1. cd ~/sys-arch-2026
  2. source install/setup.bash
  3. ros2 launch ros2bridge_server rosbridge_websocket_launch.xml

Then open a new terminal tab, and type:

  1. cd ~/sys-arch-2026
  2. source install/setup.bash
  3. google-chrome remote_control_webpage/index.html

Expected Output

First collection of steps:

[INFO] [1770477697.091728063] [Simple_Joystick_Controller]: ** Starting the model "Simple_Joystick_Controller" **

Second collection of steps:

[INFO] [launch]: All log files can be found below /home/cyclone/.ros/log/2026-02-02-18-46-02-622720-Cyclone-General-5911
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [rosbridge_websocket-1]: process started with PID [5915]
[INFO] [rosapi_node-2]: process started with pid [5916]
[rosbridge_websocket-1] [INFO] [17008673.579764488] [rosbridge_websocket]: Rosbridge WebSocket server started on port 9090

Third collection of steps:

Created TensorFlow Lite XNNPACK delegate for CPU.
[9016:9045:0207/072633.322088:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT

Explanation

The first collection of steps starts up the Matlab code-generated node that sends thruster commands based on joystick input.

The second collection of steps starts up the rosbridge connection, which connects the webpage to the Matlab code.

The third collection of steps starts up the webpage that connects to the joystick and sends that data to Matlab.


Background

Understanding Linux/The Terminal

Why the terminal?

The terminal provides you a convenient, reproducible way to interact with your computer. At the end of the day, the goal of using a computer is to manipulate files and data, and a graphical interface merely provides a familiar way of understanding what's really going on in your computer through the abstraction of a desktop. This is fine for regular users, but when you want to run specific programs and develop software, it's much more convenient to do so by entering the specific commands that you want the computer to do.

Understanding the terminal

When you open the terminal, you will be greeted with a single prompt a the top. It will look something like this:

cyclone@cyclone-general:~$

Let's disect this. The first word, cyclone, is your username. The second phrase, cyclone-general is the hostname (the name of the computer). The tilde (~) is the current directory (more on that in a bit), which is the folder that you're currently in. Finally, the $ sign signifies the start of the prompt where you can type your commands. The overall breakdown therefore looks like this:

[username]@[hostname]:[current_directory]$

When you type a command into the terminal, you are telling the computer to run a specific program or execute a specific tool. These can be programs that already exist on your computer, or programs that you wrote yourself. For example, to run Chrome, you could type:

cyclone@cyclone-general:~$ google-chrome

This works because Chrome is installed in a globally-accessible way on the computer (i.e. not just accessible from a single directory). If you want to run a local program, you'd have to put ./ in front of it (i.e. ./local_program).

To run a command that you've previously run, you can use the up arrow, which will cycle through them. To go back to your most recent command, you can use the down arrow.

Understanding Unix Filesystems

Linux is a Unix-like system, meaning that it follows most of the same rules as the Unix standard. MacOS is also a Unix system, but Windows is not. The following only applies to Unix systems, so don't try to apply this knowledge to Windows. Also note that the word "directory" and "folder" are used interchangeably.

The filsystem can be thought of as a large, inverted tree. The root is at the top, and the branches grow downwards. The root directory is represented by /: that's the full name of the directory. / contains a number of other folders, including dev, home, etc, sys, usr, and more. The path to any of these directories is therefore /dev, /home, etc. /home is where the home directories of the users live, i.e. /home/cyclone is the path to the home directory for the cyclone user. Inside this directory are the directories that you interact with on a daily basis and have more familiar names, including Documents, Downloads, Desktop, etc. The full path to these is therefore /home/cyclone/Documents. Because the home directory is used so much, Unix has a shorcut for it: the ~ symbol (tilde). If you're the cyclone user, then ~ means /home/cyclone. Here's a diagram to help:



/
├── bin
├── boot
├── dev
│    └── serial
│           └── by-id
│                 └── usb-MicroPython_Board_...
├── etc
├── home
│    └── cyclone
├── lib     ├── Desktop
├── mnt     ├── Documents
├── proc    ├── Downloads
├── sys     ├── Music
├── tmp     ├── Pictures
├── usr     ├── sys-arch-2026
└── var     └── Videos

In Unix, everything is a file, even things that aren't really files. For example, the Pi Pico that's connected to the Pi 5 shows up as a file under the path /dev/serial/by-id/, because /dev contains the devices on the system.

There are also two special directories that live inside every directory. . and .. represent the current directory and the parent directory, respectively. If you're in /home/cyclone, then . is /home/cyclone and .. is /home. This is why to run a local progam, you type ./ in front of it: in doing so, you specify that the program lives in the current directory.

Navigating the filesystem through the terminal

There are a few basic commands that will be critical to navigating the terminal.

  • ls: This lists all the files and folders in your current location, excluding hidden files.
    • To see hidden files (those that begin with a dot, like .gitignore), you can run ls -A
  • cd {path}: This means to change directory to the directory specified in {path}. Path can be either a "relative" path or an "absolute" path.
    • A relative path is a path defined from your current location. If you're used to a graphical file explorer, you can think of this as all the folders and files that you can see from within whatever folder you're currently in. For example, if you're in /home/cyclone, then the following is a relative path: Documents/my_document.txt. Note the lack of / at the start of the path: this signifies that it is relative rather than absolute.
    • An absolute path is a path defined from the filesystem root (i.e. /home/cyclone/Documents/my_document.txt).
    • You can cd into the special ., .., and / directories just like any other directory.

Understanding Local Machine vs Pi 5

Throughout these instructions, you will be running multiple terminal sessions to run each of these processes. Some of them should run on the Pi 5, and some should run on the local machine (team laptop). If they should run on the Pi 5, you will need to be connected (through ssh) to the Pi before running the commands to start them up.

To check whether your terminal is connected to the local machine, you can check the hostname at the start of the terminal prompt. If it looks like this:

cyclone@cyclone-general:~$

then you're on the local machine. If it looks like this:

cyclone@cyclonepropulsion:~$

then you're on the Pi 5. Most processes have to run on the Pi 5, some can be run on the local machine or the Pi 5, and some have to run on the local machine.

Using tmux

tmux is a terminal multiplexer. It allows splitting a single terminal session into multiple panes. This is particularly convenient for a few reasons: if you launch a tmux session on the Pi 5, you can open multiple panes without having to re-ssh to the Pi every time, and you can view multiple panes at once (miniature windows within the big main window) without having to continually switch tabs between different robot processes.

The main command that you care about for Robosub is ctrl + b ("control B") followed by an arrow key. This is how you move between panes: if you want to move to a pane on the left, type ctrl + b then the left arrow key. Clicking on the pane won't switch focus to it: you have to use this method instead!

You may also need to switch between different windows within tmux. This is like switching tabs within the terminal, except that it's all within one tmux session. This can be accomplished with ctrl + b followed by the window number, which is displayed on the green bar on the bottom of the screen (starting from 0). For example, to switch to window 2, you would type ctrl + b, then 2.

If you'd like to split a pane into some sub-panes, you can do so with % and ". To split vertically, type ctrl + b then %, and to split horizontally type ctrl + b then ".

To close down the tmux session, the easiest way is to close whatever process is running, and then type ctrl + d into the empty terminal prompt for each open pane. Be careful: if you type ctrl + d after exiting tmux, it will instead close the ssh connection or the terminal instance itself (depending on whether you're ssh'd or not).

Stopping a program

To stop a program that is running in the terminal, type ctrl + c. This will attempt to end the process. If it doesn't end within a few seconds, try pressing it a few more times. If it still doesn't end, you may need to forcefully kill the process. This can be done most easily through btop.

To kill a process with btop, open a new terminal window, tab, or tmux pane on the machine which is running the process you wish to kill, then type btop into the terminal and press Enter. You should be greeted with a text-based task manager program. Use the arrow keys to scroll the programs list on the right until you find the process you want to kill. Then, while hovering over the process (by careful, the processes move around frequently!) and press k. Confirm that the popup has the correct process listed, then press Enter. To exit btop, type q.

About

The new and improved codebase for 2026 (and hopefully beyond)!

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors