Platform

Documentation for each platform module in the main NUbots codebase
Updated 23 Mar 2026

Hardware Simulator

Description

This module simulates the CM740 subcontroller and connected sensors from the NUgus' real hardware.

Usage

CM740 Hardware I/O connects at startup to the CM740 controller located on /dev/CM740. If this does not succeed an exception is thrown and startup is aborted.

This module reads the current status of the CM740 90 times per second and emits it as a message::platform::RawSensors object. This includes the CM740 error code, LED panel, head and eye LED colour, buttons, voltage, accelerometer, gyroscope, left and right force-sensing resistors and each servo.

To change the colour of the NUgus' head or eye LEDs, emit a message::platform::RawSensors::EyeLED or message::platform::RawSensors::HeadLED containing the colour you wish to set them to.

To control the NUgus' servos, use message::actuation::ServoTarget. You may emit these commands individually or emit several at once in a message::actuation::ServoTargets.

Consumes

  • message::platform::RawSensors::EyeLED requesting a change to eye LED colour
  • message::platform::RawSensors::HeadLED requesting a change to head LED colour
  • message::actuation::ServoTarget requesting a single servo command be performed
  • message::actuation::ServoTargets requesting a batch of servo commands be performed

Emits

  • message::platform::RawSensors containing the current status of the NUgus

NUSense HardwareIO

Description

This module is responsible for communicating with the NUgus robot's NUSense controller.

Usage

NUSense handles reading and writing to the Dynamixel devices, and reads its own accelerometer and gyroscope (IMU). This module sends target requests for Dynamixel devices and receive the NUSense data on Dynamixel device states and IMU state.

This module is built when the subcontroller CMake flag is set to NUSense. Using platform::${SUBCONTROLLER}::HardwareIO will use this module if the subcontroller CMake flag is set to NUSense.

Consumes

  • message::actuation::ServoTarget requesting a single servo command be performed
  • message::actuation::ServoTargets requesting a batch of servo commands be performed

Emits

  • message::platform::NUSense with a DIRECT scope so that the message is picked up locally in this module to be converted to RawSensors.
  • message::input::RawSensors containing the current NUgus sensor data from the NUSense device.

Notes

There are 2 ways to generate nanopb messages for NUSense. The generated files must then go into the NUSense NUController repo before building the binaries onto the board. This will be a temporary solution until a ./b install pipeline for NUSense is set up. The guides below will assume that the OS is some linux based distro.

b script

For example, if a user wants to generate nanopb messages and specify that certain properties of messages must have max counts, the command below should put the generated files in the recordings directory.

./b nusense generate_nanopb_message recordings/ServoTarget.proto \
--selections ServoTargets:targets:max_count:20 \
SubcontrollerServoTargets:targets:max_count:20

The recordings directory is convenient as it is symlinked to the docker container. It is also imperative to specify maximum counts for repeated fields as encoding a message without it takes significantly longer and introduces a lot of overhead that is undesired in terms of performance.

Manual (and lazy)

This way achieves the same outcome as the first one, but is objectively more tedious

cd ~
git clone https://github.com/nanopb/nanopb.git
cd nanopb/generator
cp ~/NUbots/shared/message/actuation/ServoTarget.proto .

Then parsing the .options file as required

cat << EOF > ServoTarget.options
message.actuation.ServoTargets.targets max_count:20
message.actuation.SubcontrollerServoTargets.targets max_count:20
EOF

Assuming that the guide was followed, the current working directory should be in ~/nanopb/generator. To generate the files, run

python3 nanopb_generator.py ServoTarget.proto

The generated files should be in the same directory. Put these within NUcontroller/NUSense/Core/Src/usb/protobuf and replace the old files as required. The same logic goes with new messages.

See https://jpa.kapsi.fi/nanopb/docs/reference.html#defining-the-options-in-a-.options-file for more available options.

OpenCR HardwareIO

Description

This module is responsible for communicating with the NUgus robot's OpenCR controller.

Usage

OpenCR Hardware I/O connects at startup to the OpenCR controller and sets up the starting state of the device.

The module runs a continuous loop where it

  • Sends a servo syncwrite instruction to all servos with updated instructions, if there are any new instructions
  • Requests to read the servo's current state
  • Processes the read data from each of the 20 servos
  • Sends a OpenCR write instruction to the controller if there are any new instructions
  • Requests to read the OpenCR's current state
  • Processes the OpenCR read data

These are done in order on a loop and if we fail to get a return message when we expect to get one, the module attempts a reconnect the OpenCR device and requests to read the servos.

Once every loop, a RawSensors message is constructed with the current data recorded from the controller.

Consumes

  • message::platform::RawSensors::EyeLED requesting a change to eye LED colour
  • message::platform::RawSensors::HeadLED requesting a change to head LED colour
  • message::platform::RawSensors::LEDPanel requesting a change to LED panel colour
  • message::actuation::ServoTarget requesting a single servo command be performed
  • message::actuation::ServoTargets requesting a batch of servo commands be performed
  • message::platform::StatusReturn used locally in the module to capture data input from the controller and process it in a separate reaction with Sync.

Emits

  • message::platform::RawSensors containing the current status of the NUgus
  • message::platform::StatusReturn used locally in the module to capture data input from the controller and process it in a separate reaction with Sync.

Dependencies

  • The USB TTY communication relies on Linux-specific system calls

Webots

Description

A module to connect to Webots controllers and exchange protobuf messages with them.

Usage

Add the ip for the computer running Webots, and the port the controller is listening on. For Robocup the port determines which player this robot is.

You'll need to build this codebase (NUbots), and build the controller you're running in the NUWebots repository.

Start the world in webots, then do ./b run webots, ./b run webots_keyboard, or another associated role from this repositiory. If you disconnect or need to restart the world, stop the role running with ctrl + c, then refresh the world in webots and run the role with the same ./b command as above.

Emits

  • platform::RawSensors
  • output::CompressedImage
Modules
Planning
Modules
Purpose
NUbots acknowledges the traditional custodians of the lands within our footprint areas: Awabakal, Darkinjung, Biripai, Worimi, Wonnarua, and Eora Nations. We acknowledge that our laboratory is situated on unceded Pambalong land. We pay respect to the wisdom of our Elders past and present.
Copyright © 2026 NUbots - CC-BY-4.0
Deploys by Netlify