Skip to main content

Starting with Protobufs


Last updated: 15-04-2026

On this page

1) What are protobufs (and why we use them)

Protocol Buffers (protobufs) are a way to define structured messages (data packets) in a language-neutral, versionable schema format (.proto).

The value proposition is simple: we write the message format once, and then generate code in C. So every component agrees on what the bytes mean.

Protobufs are the shared language they use to exchange status, commands and telemetry without hand-written packet formats slowly evolving into folklore.

2) Where protobufs exist

The canonical home for message definitions is: ERC-Protobufs.

Repo description: “The official protobuffers embedded, control & software use for communication”.

Embedded firmware that consumes these messages lives in: RoboTeamTwente/ERC-Embedded/ERC-Protobuffs (mostly C).

3) The mental model: schema → code → bytes

  1. Schema: you define messages/enums in .proto.
  2. Generated code: a compiler (protoc) generates language-specific code. (SOFTWARE DOES THIS, MOST OF THE TIME, embedded uses nanopb)
  3. Runtime: your program fills in fields → serializes to bytes → sends bytes over some transport (UART/CAN/UDP/etc.).
  4. Receiver: reads bytes → deserializes using the same schema → gets the structured message back.

4) Rules for editing .proto files

Field numbers are the real API

In protobuf, the integer tags (field numbers) are what the wire format cares about.

Renaming a field usually does nothing on the wire; changing a field number changes everything.

Never renumber fields in an existing message unless you’re intentionally breaking compatibility and coordinating the change across all consumers.

Preferred change types

  • Add a new optional field with a new, unused number.
  • Add new enum values (don’t reorder existing ones if your tooling is sensitive).
  • Deprecate fields instead of deleting them immediately.

Changes that need extra care

  • Changing a field type (e.g. int32string)
  • Changing semantics (“this is now meters not millimeters”)

5) Typical workflow in RoboTeam

  1. Pick the message you need to change/add in ERC-Protobufs.
  2. Edit the .proto file(s) with a clear goal..
  3. Update colleagues (embedded/control/software) if they need to use new fields.
  4. Test end-to-end: serialize → send → deserialize on the other side.
  5. Push or create pull request in ERC-Protobufs:
    • what changed (fields + numbers)
    • why it changed
    • compatibility notes (“old firmware can still parse this” or “requires coordinated update”)

6) Compatibility: how to not break everyone

Protobuf is designed for forwards/backwards compatibility if you follow the rules. The main idea:

  • Old code should be able to read new messages (it ignores unknown fields).
  • New code should be able to read old messages (missing fields take default values).
  • PLEASE INFORM SOFTWARE, THEY USUALLY GET REALLY PARANOID WHEN THINGS MESS UP!!
    • DON'T WORRY, EMBEDDED OWNS PROTOBUFS☮️

Breaking changes: Reusing a field number for a different meaning is a fast path to silent corruption. The code compiles.

Deletions

If you must remove a field, prefer: stop using it + reserve the field number (so it can’t be reused). The exact syntax depends on protobuf version/style used in the repo.

7) Embedded extra notes (Protobufs Submodules)

Embedded projects are resource-constrained.

  • Payload size: fewer fields and smaller types can matter a lot.

Note: the exact embedded protobuf implementation (nanopb / protobuf-c / custom generator) depends on the current repo setup. Follow the build scripts and existing patterns in ERC-Embedded.

8) Debugging & troubleshooting

“My message doesn’t parse”

  • Confirm both sides are using the same .proto version (or compatible versions).
  • Check field numbers: did someone accidentally reuse one?
  • Validate transport framing: protobuf gives bytes; you still need a correct length/prefix/CRC strategy.

“It parses but values are nonsense”

  • Check units/semantics (mm vs m, degrees vs radians).
  • Confirm end-to-end: are you sending the message type you think you’re sending?
  • Look for stale generated code (someone updated .proto but didn’t regen).

In the end of the day, the only issues embedded will face is incorrect imports or issues with nanopb. Software issues ARE NOT YOUR CONCERN!

Protobufs are boring on purpose: boring schemas prevent exciting debugging sessions. Keep changes small, pinned, reviewed, and tested.