# Protobuffers

# Starting with Protobufs

## What are protobufs?

[Protocol Buffers](https://protobuf.dev/programming-guides/proto3/)<span style="white-space: pre-wrap;"> (protobufs) are a way to define structured messages in </span>`<span class="editor-theme-code">.proto</span>`<span style="white-space: pre-wrap;"> files.</span>

The point is simple: define the message format once, generate code for your language, and now everyone agrees what the bytes mean (without inventing a new packet format every semester).

## Where they live

<span style="white-space: pre-wrap;">The source of truth for RoboTeam message definitions is: </span>[RoboTeamTwente/ERC-Protobufs](https://github.com/RoboTeamTwente/ERC-Protobufs).

<span style="white-space: pre-wrap;">Other repositories (embedded, software, tooling) should </span>**consume**<span style="white-space: pre-wrap;"> these definitions (often via a git submodule) instead of copy-pasting </span>`<span class="editor-theme-code">.proto</span>`<span style="white-space: pre-wrap;"> files around.</span>

## Editing rules (the important part)

### Field numbers are the real API

<span style="white-space: pre-wrap;">In protobuf, the </span>**field number**<span style="white-space: pre-wrap;"> is what goes on the wire. Renaming a field is usually harmless; changing its number is usually the problem.</span>

**Never renumber an existing field**<span style="white-space: pre-wrap;"> unless you are intentionally breaking compatibility and coordinating the update across all consumers.</span>

### Safe changes (usually)

- <span style="white-space: pre-wrap;">Add a new field with a </span>**new**<span style="white-space: pre-wrap;"> unused number.</span>
- Add new enum values (don’t reuse old numeric values for new meanings).
- Stop using a field before deleting it, and reserve its number if your style guide does that.

### Changes that need extra care

- <span style="white-space: pre-wrap;">Changing a field type (e.g. </span>`<span class="editor-theme-code">int32</span>`<span style="white-space: pre-wrap;"> → </span>`<span class="editor-theme-code">string</span>`).
- Changing semantics/units (mm vs m, degrees vs radians).

## Typical workflow

1. <span style="white-space: pre-wrap;">Edit / add </span>`<span class="editor-theme-code">.proto</span>`<span style="white-space: pre-wrap;"> files in </span>`<span class="editor-theme-code">ERC-Protobufs</span>`.
2. Generate / update code as required by your project (this step is repo-specific).
3. Update consumers to use the new fields (and handle missing fields safely).
4. Test at least one real send/receive path.
5. Open a PR that lists: what changed, field numbers, and compatibility expectations.

## Troubleshooting

### “My message doesn’t parse”

- <span style="white-space: pre-wrap;">Confirm both sides use the same (or compatible) </span>`<span class="editor-theme-code">.proto</span>`<span style="white-space: pre-wrap;"> definitions.</span>
- Check field numbers: no reuse, no renumbering.
- Check transport framing (length prefix / delimiter / CRC). Protobuf gives bytes; transport still matters.

### “It parses, but values are nonsense”

- Check units and semantics (the most common “it’s wrong but not broken” bug).
- Make sure generated code is up to date (stale generated files cause creative failures).

<p class="callout info">Protobufs are boring on purpose. Boring schemas prevent exciting debugging sessions. Keep changes small, reviewable, and compatible.</p>

# Design

This page explains rules that apply to all protobuffers, and a bit on how we use them.

## PBEnvelope

<span style="white-space: pre-wrap;">All protobuffers are wrapped in the </span>`<span class="editor-theme-code">PBEnvelope</span>`<span style="white-space: pre-wrap;"> message, which contains metadata we need in all protobufs.</span>

## Lost packets &amp; throttling

<span style="white-space: pre-wrap;">In every line of communications, the packets must be sent periodically. The frequency of sent packets is indicated in their </span>`<span class="editor-theme-code">PBEnvelope</span>`. If the receiver does not get a packet within given timeout, it means the packet was lost. In most cases this means that the brakes should be engaged for safety.

# Arm Board Protobuffers

***This page:** *each arm\_board protobuffer explained.**

<p class="callout success"><span style="white-space: pre-wrap;">The protobuffers for the arm\_board are passed between software, control and embedded. </span></p>

---

##### Movement\_software\_target.proto

**Software -&gt; control**

This file contains two protobuffers detailing the source of a movement.

**ArmBoardTargetMovement** contains the target coordinates for a movement. This gets sent to control, they use this information to calculate motor angles.

**ArmBoardObstructions**<span style="background-color: rgb(251, 238, 184); white-space: pre-wrap;"> is a placeholder for now</span>. The idea is that software would be able to pass a list of coordinates of physical obstructions to control, around which they would manoeuvre the movement of the arm.

---

##### Movement\_control\_in.pb.h

**Control -&gt; Embedded**

<span style="white-space: pre-wrap;">After control calculates the angles using the information from the previous protobuf, it sends the control signals back to us (embedded) with the </span><span style="background-color: rgb(248, 202, 198); white-space: pre-wrap;">absolute </span>angles and frequency for the motors.<span style="background-color: rgb(251, 238, 184); white-space: pre-wrap;"> So, this is the information embedded uses to actuate the motors.</span>

**ArmboardControlSignals**<span style="background-color: rgb(248, 202, 198); white-space: pre-wrap;"> contains all the angles the motors need to be turned to</span>. We then use this information to set the PWM pins.

---

##### Movement\_software\_feedback.proto

**Embedded -&gt; Software**

After the movement happens (or fails), embedded will send feedback to software for them to calculate the next movement.

**ArmBoardMovementFeedback** sends an error code to software.

Possible error codes are:

- Point\_not\_in\_range
- Obstruction
- Calibration
- Motor\_malfunction
- All\_ok

**ArmBoardActualPositions** <span style="white-space: pre-wrap;">sends back the angle of each motor of the arm. Software will use this to display a 3D model of the arm position. </span><span style="background-color: rgb(248, 202, 198);">(Allegedly)</span>

---

##### Motor\_diagnostics.proto

**Arm board -&gt; Debugging board**

This protobuf gets periodically sent to the debugging board to indicate the status.

**ArmBoardDiagnostics** <span style="white-space: pre-wrap;">the </span>`<span class="editor-theme-code">MotorInformation</span>`<span style="white-space: pre-wrap;"> for each motor and the state of the </span>**entire** <span style="white-space: pre-wrap;">board. </span>

Possible states are:

- Idle
- Operating
- Calibrating
- Errored

<p class="callout info">**MotorInformation** is a common protobuf shared between all boards that use motors (this and driving board). MotorInformation contains the state (same as above), motor\_id, rpm, voltage and encoder\_angle for a single motor.</p>

# Sensor Board Protobuf

***This page:** *Complete protobuf message definitions for the sensor\_board component.**

<p class="callout success">The protobuffers for the sensor\_board are passed between embedded, the network, and other boards for diagnostics and data collection. This page documents the actual message definitions from the ERC-Protobufs repository.</p>

---

## Common Definitions (sensor.proto)

**Location: ERC-Protobufs/components/sensor\_board/sensor.proto**

### SensorState Enum

Shared across all sensor types - indicates the current operational state of a sensor.

```protobuf
enum SensorState {
  SENSOR_IDLE = 0;           // Sensor is idle/not currently sampling
  SENSOR_OPERATING = 1;      // Sensor is actively sampling/operating normally
  SENSOR_CALIBRATING = 2;    // Sensor is in calibration mode
  SENSOR_ERROR = 3;          // Sensor has encountered an error
}
```

---

## GPS Sensor (gps\_sensor.proto)

**Location: ERC-Protobufs/components/sensor\_board/gps\_sensor.proto**

**Direction: Sensor Board → Navigation/Localization Systems**

### GPSFixQuality Enum

Indicates the type and quality of GPS fix obtained.

```protobuf
enum GPSFixQuality {
  NO_FIX = 0;       // No fix available
  GPS_FIX = 1;      // Standard GPS fix
  DGPS_FIX = 2;     // Differential GPS fix
  PPS_FIX = 3;      // PPS (Pulse Per Second) fix
  RTK_FIX = 4;      // Real-Time Kinematic fix
  RTK_FLOAT = 5;    // RTK float solution
}
```

### GPSErrorCode Enum

Detailed error codes for GPS/GNSS sensor failures.

```protobuf
enum GPSErrorCode {
  GPS_NO_ERROR = 0;
  GPS_COMMUNICATION_FAILURE = 1;   // UART connection lost
  GPS_INVALID_DATA = 2;             // Data parsing or validation failed
  GPS_ANTENNA_FAULT = 3;            // GPS antenna disconnected or faulty
  GPS_LOW_SIGNAL_QUALITY = 4;       // Signal strength too weak for fix
}
```

### SensorBoardGPSInfo Message

Complete GPS positioning and velocity information.

```protobuf
message SensorBoardGPSInfo {
  // GPS coordinates
  double latitude = 1;           // Degrees (positive = North, negative = South)
  double longitude = 2;          // Degrees (positive = East, negative = West)
  float altitude = 3;            // Meters above sea level
  
  // Velocity data
  float speed = 4;               // Speed in meters per second
  float heading = 5;             // Course over ground in degrees (0-360)
  
  // Position accuracy and quality
  float hdop = 6;                // Horizontal dilution of precision (lower is better)
  float vdop = 7;                // Vertical dilution of precision (lower is better)
  int32 satellites = 8;          // Number of satellites in view (up to 16)
  
  GPSFixQuality fix_quality = 9;
  
  SensorState state = 10;
  GPSErrorCode error_code = 11;  // Error code if state is SENSOR_ERROR
  
  // Timestamp from GPS
  int64 utc_timestamp = 12;      // Unix timestamp in milliseconds
}
```

---

## IMU Sensor (imu\_sensor.proto)

**Location: ERC-Protobufs/components/sensor\_board/imu\_sensor.proto**

**Direction: Sensor Board → Motion Control/Attitude Systems**

### IMUErrorCode Enum

Detailed error codes for IMU sensor failures.

```protobuf
enum IMUErrorCode {
  IMU_NO_ERROR = 0;
  IMU_COMMUNICATION_FAILURE = 1;      // I2C/SPI connection lost
  IMU_CALIBRATION_REQUIRED = 2;       // Sensor needs calibration
  IMU_CALIBRATION_FAILED = 3;         // Calibration procedure failed
  IMU_INVALID_DATA = 4;               // Data out of valid range
  IMU_SENSOR_FAULT = 5;               // Hardware fault detected
  IMU_GYROSCOPE_ERROR = 6;            // Gyroscope component failure
  IMU_MAGNETOMETER_ERROR = 7;         // Magnetometer component failure
  IMU_ACCELEROMETER_ERROR = 8;        // Accelerometer component failure
}
```

### SensorBoardIMUInfo Message

3-axis inertial measurement data (acceleration, angular velocity, magnetic field).

```protobuf
message SensorBoardIMUInfo {
  // 3-Axis Accelerometer data
  float accel_x = 1;             // X-axis acceleration
  float accel_y = 2;             // Y-axis acceleration
  float accel_z = 3;             // Z-axis acceleration
  
  // 3-Axis Gyroscope data
  float gyro_x = 4;              // X-axis angular velocity
  float gyro_y = 5;              // Y-axis angular velocity
  float gyro_z = 6;              // Z-axis angular velocity
  
  // 3-Axis Magnetometer data (9-axis IMU only)
  float mag_x = 7;               // X-axis magnetic field
  float mag_y = 8;               // Y-axis magnetic field
  float mag_z = 9;               // Z-axis magnetic field

  bool is_calibrated = 13;       // True if IMU has been calibrated on level surface
  
  SensorState state = 14;
  IMUErrorCode error_code = 15;  // Error code if state is SENSOR_ERROR
}
```

---

## pH Sensor (ph\_sensor.proto)

**Location: ERC-Protobufs/components/sensor\_board/ph\_sensor.proto**

**Direction: Sensor Board → Environmental Monitoring Systems**

### PHErrorCode Enum

Detailed error codes for pH sensor failures.

```protobuf
enum PHErrorCode {
  PH_NO_ERROR = 0;
  PH_COMMUNICATION_FAILURE = 1;       // ADC connection lost
  PH_OUT_OF_RANGE = 2;                // Reading outside 0-14 range
  PH_CALIBRATION_REQUIRED = 3;        // Sensor needs calibration
  PH_INVALID_DATA = 4;                // Data validation failed
  PH_PROBE_FAULT = 5;                 // Electrode fault detected
  PH_TEMPERATURE_SENSOR_ERROR = 6;    // Temperature compensation sensor failed
}
```

### SensorBoardPHInfo Message

Water quality measurement with temperature compensation.

```protobuf
message SensorBoardPHInfo {
  float ph_value = 1;            // Raw pH measurement (0-14 scale, 7 is neutral)
  float voltage = 2;             // Voltage reading from pH sensor in millivolts
  float temperature = 3;         // Temperature reading in Celsius (if external sensor available)
  
  SensorState state = 4;         // Current state of the pH sensor
  PHErrorCode error_code = 5;    // Error code if state is SENSOR_ERROR
}
```

**Notes:**

- pH value is derived from voltage via linear calibration equation
- 40-sample moving average applied internally to reduce ADC noise
- Temperature used for automatic compensation (default ~25°C)

---

## Load Cell Sensor (load\_cell.proto)

**Location: ERC-Protobufs/components/sensor\_board/load\_cell.proto**

**Direction: Sensor Board → Arm Control/Gripper Systems**

### LoadCellErrorCode Enum

Detailed error codes for load cell sensor failures.

```protobuf
enum LoadCellErrorCode {
  LOAD_CELL_NO_ERROR = 0;
  LOAD_CELL_COMMUNICATION_FAILURE = 1;   // ADC connection lost
  LOAD_CELL_OUT_OF_RANGE = 2;            // Force measurement exceeds limits
  LOAD_CELL_CALIBRATION_REQUIRED = 3;    // Sensor needs calibration
  LOAD_CELL_INVALID_DATA = 4;            // Data validation failed
  LOAD_CELL_SENSOR_FAULT = 5;            // Hardware fault detected
}
```

### SensorBoardLoadCellInfo Message

Force measurement for robotic gripper control and load monitoring.

```protobuf
message SensorBoardLoadCellInfo {
  uint32 sensor_index = 1;               // 0-based index of the load cell (0 or 1)
  float force_newtons = 2;               // Force in Newtons
  float mass_grams = 3;                  // Mass in grams (derived from force)
  int32 raw_counts = 4;                  // Raw ADC counts (for debugging)

  // Calibration status and parameters
  bool is_calibrated = 5;                // True if calibration parameters are valid
  float scale_newtons_per_count = 6;     // Conversion factor (N/count)
  int32 tare_offset_counts = 7;          // Zero-load ADC offset

  SensorState state = 8;
  LoadCellErrorCode error_code = 9;      // Error code if state is SENSOR_ERROR
}
```

**Dual Sensor Support:**

- Up to 2 independent load cells (sensor\_index 0 and 1)
- Typically used on dual-pad grippers for load distribution feedback
- Each sensor maintains independent calibration parameters
- Enables slip detection via load imbalance analysis

---

## Pressure Sensor (pressure\_sensor.proto)

**Location: ERC-Protobufs/components/sensor\_board/pressure\_sensor.proto**

**Direction: Sensor Board → Arm Control/Gripper Systems / Environmental Monitoring**

### PressureErrorCode Enum

Detailed error codes for pressure sensor failures.

```protobuf
enum PressureErrorCode {
  PRESSURE_NO_ERROR = 0;
  PRESSURE_COMMUNICATION_FAILURE = 1;    // I2C/ADC connection lost
  PRESSURE_OUT_OF_RANGE = 2;             // Reading exceeds sensor limits
  PRESSURE_CALIBRATION_REQUIRED = 3;     // Sensor needs calibration
  PRESSURE_INVALID_DATA = 4;             // Data validation failed
  PRESSURE_SENSOR_FAULT = 5;             // Hardware fault detected
}
```

### SensorBoardPressureInfo Message

Pressure measurement for robotic gripper control and environmental sensing.

```protobuf
message SensorBoardPressureInfo {
  uint32 sensor_index = 1;               // 0-based index of the pressure sensor (0 or 1)

  // Pressure data
  float pressure_kpa = 2;                // Pressure in kilopascals
  float temperature_c = 3;               // Temperature in Celsius (if available)
  float voltage = 4;                     // Sensor output voltage (if available)

  // Calibration status
  bool is_calibrated = 5;                // True if calibration parameters are valid

  SensorState state = 6;
  PressureErrorCode error_code = 7;      // Error code if state is SENSOR_ERROR
}
```

**Dual Sensor Support:**

- Up to 2 independent pressure sensors (sensor\_index 0 and 1)
- Primary use: gripper pad force feedback for PID control
- Enables real-time grip force regulation and slip detection
- Secondary uses: depth sensing, altitude sensing, system pressure monitoring

---

## Board Diagnostics (diagnostics.proto)

**Location: ERC-Protobufs/components/sensor\_board/diagnostics.proto**

**Direction: Sensor Board → Debugging Board / Health Monitoring Systems**

### SensorBoardDiagnostics Message

Complete system health and status snapshot sent periodically (5 second default).

```protobuf
message SensorBoardDiagnostics {
  enum State {
    IDLE = 0;
    OPERATING = 1;
    CALIBRATING = 2;
    ERROR = 3;
  }

  State state = 1;                       // Overall board state
  SensorBoardPHInfo ph_sensor = 2;       // pH sensor status
  SensorBoardIMUInfo imu_sensor = 3;     // IMU sensor status

  // Overall sensor board health
  float board_temperature = 4;           // Board temperature in Celsius
  float board_voltage = 5;               // System voltage (3.3V supply)
  
  SensorBoardGPSInfo gps_sensor_1 = 6;   // GPS sensor status
}
```

**Board States:**

- **IDLE (0)**<span style="white-space: pre-wrap;"> - Board initialized but not actively polling sensors</span>
- **OPERATING (1)**<span style="white-space: pre-wrap;"> - All sensors functioning normally, data being collected</span>
- **CALIBRATING (2)**<span style="white-space: pre-wrap;"> - Board or sensors in calibration mode</span>
- **ERROR (3)**<span style="white-space: pre-wrap;"> - Critical system failure detected</span>

**Health Indicators:**

- **board\_temperature**<span style="white-space: pre-wrap;"> - STM32H753 die temperature; normal range 25-75°C</span>
- **board\_voltage**<span style="white-space: pre-wrap;"> - 3.3V supply input; should be 3.0-3.6V</span>
- **Embedded sensor states**<span style="white-space: pre-wrap;"> - Each sensor's current SensorState (IDLE/OPERATING/CALIBRATING/ERROR)</span>

---

## Error Code Pattern

All sensor error codes follow a consistent pattern:

```protobuf
enum XXXErrorCode {
  XXX_NO_ERROR = 0;                      // No error
  XXX_COMMUNICATION_FAILURE = 1;         // Hardware interface (I2C/SPI/UART/ADC) failure
  XXX_OUT_OF_RANGE = 2;                  // Reading outside valid sensor range
  XXX_CALIBRATION_REQUIRED = 3;          // Sensor needs calibration
  XXX_INVALID_DATA = 4;                  // Data validation/filtering failed
  XXX_SENSOR_FAULT = 5;                  // Hardware fault or component failure
  // Additional sensor-specific errors...
}
```

**Integration into application:**

```c
if (gps_result.error_code == GPS_COMMUNICATION_FAILURE) {
    LOG_ERROR("GPS UART connection lost");
    diagnostics.gps_sensor_1.state = SENSOR_ERROR;
} else if (gps_result.error_code == GPS_NO_ERROR) {
    LOG_INFO("GPS position: %f, %f", gps_result.latitude, gps_result.longitude);
}
```

---

## Network Transmission

**Main Sensor Data:**

- Sent via individual sensor messages
- Packaged into SensorBoardState (sensor.proto)
- UDP broadcast to 192.168.0.255:7 (configurable)
- Interval: 5 seconds default (configurable)
- Encoding: Nanopb (lightweight protobuf for embedded)

**Diagnostics Data:**

- Sent via SensorBoardDiagnostics message
- UDP broadcast to 192.168.0.255:7 (same port)
- Interval: 5 seconds (synced with main loop)
- Contains snapshot of all sensor states + health metrics

---

## Message Composition

The SensorBoardDiagnostics message is composed of individual sensor message types:

```
SensorBoardDiagnostics
├── state (Board state)
├── SensorBoardPHInfo
│   ├── ph_value
│   ├── voltage
│   ├── temperature
│   ├── state (SensorState)
│   └── error_code (PHErrorCode)
├── SensorBoardIMUInfo
│   ├── accel_x, accel_y, accel_z
│   ├── gyro_x, gyro_y, gyro_z
│   ├── mag_x, mag_y, mag_z
│   ├── is_calibrated
│   ├── state (SensorState)
│   └── error_code (IMUErrorCode)
├── board_temperature
├── board_voltage
└── SensorBoardGPSInfo
    ├── latitude, longitude, altitude
    ├── speed, heading
    ├── hdop, vdop, satellites
    ├── fix_quality
    ├── state (SensorState)
    ├── error_code (GPSErrorCode)
    └── utc_timestamp
```

**Note:**<span style="white-space: pre-wrap;"> Not all proto files define load cells and pressure sensors in diagnostics.proto yet - they are sent as separate messages when available.</span>

# Driving Board Protobuffers

***This page:** *each driving\_board protobuffer explained.**

<p class="callout success"><span style="white-space: pre-wrap;">The protobuffers for the driving\_board are passed between software, control and embedded. </span></p>

<span style="white-space: pre-wrap;">DrivingBoardDiagnostics.proto </span>

<span style="white-space: pre-wrap;">Embedded → Software / Debugging </span>

<span style="white-space: pre-wrap;">This file contains the full diagnostic state of the driving board and all attached motors. </span>

<span style="white-space: pre-wrap;">DrivingBoardDiagnostics is the main status message used to report the system state and motor-level health information. </span>

##### <span style="white-space: pre-wrap;">DrivingBoardDiagnostics </span>

<span style="white-space: pre-wrap;">This message contains: </span>

- <span style="white-space: pre-wrap;">Overall board state (IDLE, OPERATING, CALIBRATING, ERROR) </span>
- <span style="white-space: pre-wrap;">Motor information for all driving and steering motors </span>

<span style="white-space: pre-wrap;">The board state is used to indicate the current operating mode of the driving board. </span>

**MotorInformation fields:**

<span style="white-space: pre-wrap;">Each motor is reported using the MotorInformation protobuf, which includes: </span>

- <span style="white-space: pre-wrap;">motor state </span>
- <span style="white-space: pre-wrap;">motor ID </span>
- <span style="white-space: pre-wrap;">RPM </span>
- <span style="white-space: pre-wrap;">voltage </span>
- encoder angle

<span style="white-space: pre-wrap;">Motors included The diagnostics message explicitly contains 10 motors: front\_left\_motor middle\_left\_motor back\_left\_motor front\_right\_motor middle\_right\_motor back\_right\_motor steering\_front\_left\_motor steering\_back\_left\_motor steering\_front\_right\_motor steering\_back\_right\_motor </span>

<p class="callout info"><span style="white-space: pre-wrap;">Notes: This structure is currently fixed-size, meaning all motors are explicitly defined instead of using a repeated field. </span></p>

##### <span style="white-space: pre-wrap;">DrivingBoardMotorMessage.proto </span>

<span style="white-space: pre-wrap;">Software → Embedded </span>

<span style="white-space: pre-wrap;">This message is used to send motion commands to the driving board. </span>

<span style="white-space: pre-wrap;">DrivingBoardMotorMessage Contains high-level movement instructions: </span>

- <span style="white-space: pre-wrap;">distance\_to\_go → target travel distance </span>
- <span style="white-space: pre-wrap;">turning\_radius </span>

<span style="white-space: pre-wrap;">Purpose: This message defines a movement request from software. The embedded system uses it as input to compute values on the control code. </span>

##### <span style="white-space: pre-wrap;">DrivingBoardMotorPeriodicProgress.proto </span>

<span style="white-space: pre-wrap;">Embedded → Software </span>

<span style="white-space: pre-wrap;">This message provides runtime feedback during movement execution. DrivingBoardMotorPeriodicProgress </span>

<span style="white-space: pre-wrap;">Contains: </span>

- <span style="white-space: pre-wrap;">distance\_left → remaining distance to target </span>

Purpose This message allows software to track progress of an ongoing movement command in real time. It is typically sent periodically while a movement is being executed.