# PBEnvelope

## What is the PBEnvelope?

<span style="white-space: pre-wrap;">The </span>`<span class="editor-theme-code">PBEnvelope</span>`<span style="white-space: pre-wrap;"> is a wrapper message defined in </span>`<span class="editor-theme-code">components/common/envelope.proto</span>`<span style="white-space: pre-wrap;"> in the ERC-Protobufs repository. Every protobuf message sent over UDP on this rover — whether from the Basestation, the Jetson, or a hardware microcontroller — is wrapped inside a </span>`<span class="editor-theme-code">PBEnvelope</span>`<span style="white-space: pre-wrap;"> before transmission.</span>

<span style="white-space: pre-wrap;">When a raw UDP datagram arrives, the receiver has no way of knowing what type of message is inside without some kind of type identifier. The PBEnvelope solves this by using proto3's </span>`<span class="editor-theme-code">oneof</span>`<span style="white-space: pre-wrap;"> field, which encodes the message type directly into the serialized bytes. The receiver calls </span>`<span class="editor-theme-code">payload_case()</span>`<span style="white-space: pre-wrap;"> on the deserialized envelope to determine the message type before extracting and deserializing the actual payload.</span>

## Structure

<span style="white-space: pre-wrap;">The PBEnvelope uses a </span>`<span class="editor-theme-code">oneof payload</span>`<span style="white-space: pre-wrap;"> block where each field corresponds to one registered message type. Only one field can be set at a time — that is the nature of </span>`<span class="editor-theme-code">oneof</span>`<span style="white-space: pre-wrap;">. When serialized, proto3 encodes which field is set, allowing the receiver to call </span>`<span class="editor-theme-code">envelope.payload_case()</span>`<span style="white-space: pre-wrap;"> and get back an enum value like </span>`<span class="editor-theme-code">PBEnvelope::kImuInfo</span>`<span style="white-space: pre-wrap;"> or </span>`<span class="editor-theme-code">PBEnvelope::kControlMode</span>`.

## Registered Message Types

Below is the full table of currently registered payload cases, their field numbers, and their communication direction:

<table class="align-center" id="bkmrk-field-numbermessage-"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr><th>Field Number

</th><th>Message Type

</th><th>Direction

</th></tr><tr><td>1

</td><td>SensorBoardPHInfo

</td><td>Hardware → ROS2

</td></tr><tr><td>2

</td><td>ArmBoardControlSignals

</td><td>ROS2 → Hardware

</td></tr><tr><td>3

</td><td>ArmBoardDiagnostics

</td><td>Hardware → ROS2

</td></tr><tr><td>4

</td><td>ArmBoardMovementFeedback

</td><td>Hardware → ROS2

</td></tr><tr><td>5

</td><td>ArmBoardActualPositions

</td><td>Hardware → ROS2

</td></tr><tr><td>6

</td><td>ArmBoardTargetMovement

</td><td>ROS2 → Hardware

</td></tr><tr><td>7

</td><td>ArmBoardObstructions

</td><td>Hardware → ROS2

</td></tr><tr><td>8

</td><td>DrivingBoardDiagnostics

</td><td>Hardware → ROS2

</td></tr><tr><td>9

</td><td>DrivingBoardMotorMessage

</td><td>ROS2 → Hardware

</td></tr><tr><td>10

</td><td>DrivingBoardMotorPeriodicProgress

</td><td>Hardware → ROS2

</td></tr><tr><td>11

</td><td>SensorBoardDiagnostics

</td><td>Hardware → ROS2

</td></tr><tr><td>12

</td><td>SensorBoardGPSInfo

</td><td>Hardware → ROS2

</td></tr><tr><td>13

</td><td>SensorBoardIMUInfo

</td><td>Hardware → ROS2

</td></tr><tr><td>14

</td><td>SensorBoardLoadCellInfo

</td><td>Hardware → ROS2

</td></tr><tr><td>15

</td><td>SensorBoardPressureInfo

</td><td>Hardware → ROS2

</td></tr><tr><td>16

</td><td>BasestationControlMode

</td><td>BS → ROS2

</td></tr><tr><td>17

</td><td>BasestationDetectedObject

</td><td>ROS2 → BS

</td></tr><tr><td>18

</td><td>BasestationObjectSelection

</td><td>BS → ROS2

</td></tr><tr><td>19

</td><td>BasestationRockMeasureRequest

</td><td>BS → ROS2

</td></tr><tr><td>20

</td><td>BasestationRockMeasureResult

</td><td class="align-center">ROS2 → BS

</td></tr><tr><td>21

</td><td>BasestationRoverLocalization

</td><td class="align-center">ROS2 → BS

</td></tr></tbody></table>

**Important:**<span style="white-space: pre-wrap;"> Field numbers in a </span>`<span class="editor-theme-code">oneof</span>`<span style="white-space: pre-wrap;"> block are permanent. Once a field number is assigned to a message type, it must never be reused for a different type — even if the original message is removed. This would break deserialization for any system still using an older version of the envelope. Always use the next available field number when adding a new entry.</span>

## <span style="white-space: pre-wrap;">A note on </span>`<span class="editor-theme-code">BasestationDetectedObject</span>`

<span style="white-space: pre-wrap;">Unlike most messages which carry a complete snapshot of state, </span>`<span class="editor-theme-code">BasestationDetectedObject</span>`<span style="white-space: pre-wrap;"> sends </span>**one detected object per message**<span style="white-space: pre-wrap;">. This is because Embedded requires fixed-size protobuf messages and cannot handle </span>`<span class="editor-theme-code">repeated</span>`<span style="white-space: pre-wrap;"> fields (which are dynamically sized). The Basestation reconstructs the full frame by collecting all messages sharing the same </span>`<span class="editor-theme-code">frame_id</span>`<span style="white-space: pre-wrap;"> until it has received </span>`<span class="editor-theme-code">total_count</span>`<span style="white-space: pre-wrap;"> of them. See </span>`<span class="editor-theme-code">components/basestation/detected_object.proto</span>`<span style="white-space: pre-wrap;"> for the full definition.</span>

## <span style="white-space: pre-wrap;">A note on </span>`<span class="editor-theme-code">message_types.proto</span>`

<p class="callout warning">TLDR: I don't remember what we were doing with this file.</p>

<span style="white-space: pre-wrap;">The ERC-Protobufs repo contains a file called </span>`<span class="editor-theme-code">message_types.proto</span>`<span style="white-space: pre-wrap;"> which defines a </span>`<span class="editor-theme-code">PBMessageType</span>`<span style="white-space: pre-wrap;"> enum. This file is a leftover from an earlier architecture where a manual type ID system was planned. It is explicitly excluded from the build in </span>`<span class="editor-theme-code">CMakeLists.txt</span>`<span style="white-space: pre-wrap;"> because its enum values collide with message names in the global proto3 namespace. It is unused, do not reference it or add new entries to it.</span>

## Trailing Zero Bytes

<span style="white-space: pre-wrap;">The </span>`<span class="editor-theme-code">envelope.proto</span>`<span style="white-space: pre-wrap;"> file includes an important note: all PBEnvelopes sent over the network must have trailing zero bytes removed before transmission. Proto3 serializes unset fields as zero bytes, and stripping them reduces network traffic. The receiver must pad the received datagram back to the full PBEnvelope size before deserializing. This is handled by the protobuf library's </span>`<span class="editor-theme-code">SerializeToString</span>`<span style="white-space: pre-wrap;"> and </span>`<span class="editor-theme-code">ParseFromArray</span>`<span style="white-space: pre-wrap;"> functions when used correctly.</span>

## Adding a New Message Type

<span style="white-space: pre-wrap;">To add a new message type to the PBEnvelope, see the dedicated </span>[Adding a new message](https://bookstack.roboteamtwente.nl/books/jonny-boi/page/adding-a-new-message "Adding a new message")<span style="white-space: pre-wrap;"> page for the full step-by-step procedure.</span>