Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions docs-source/_static/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,52 @@
.two-col-diagram-grid .mermaid-container {
width: 100%;
}

/* For diagrams rendered with useMaxWidth: false (native size instead of
shrink-to-fit-column) — scroll instead of overflowing the page if it's
wider than the column. */
.wide-mermaid pre.mermaid,
.wide-mermaid .mermaid-container {
overflow-x: auto;
}

/* Scale the whole rendered diagram up, text included. Mermaid's own
actorFontSize/messageFontSize/noteFontSize sequence config keys don't
reach the rendered <text> elements in the pinned mermaid version — they
stay hardcoded at 16px regardless. `zoom` (not `transform: scale`)
correctly reflows the layout box, so it doesn't overlap the content
below it.

sphinxcontrib-mermaid's own CSS (pre.mermaid > svg, specificity 0,1,2)
forces every diagram's SVG to a fixed height (mermaid_height, default
500px). For most diagrams that's load-bearing — it's what keeps a large
flowchart's raw viewBox from rendering at full intrinsic height, via
letterboxing (preserveAspectRatio: xMidYMid meet). It only becomes a
problem here because useMaxWidth:false + zoom already size these
diagrams from their own content, so the fixed-height letterbox just adds
blank bars on top. Scoped to wide-mermaid only — applying this globally
regressed other diagrams that rely on the fixed-height cap. */
.wide-mermaid pre.mermaid > svg {
height: auto;
zoom: 2;
}

/* Same letterbox fix as above (see comment), without the zoom bump — for
flowcharts whose aspect ratio is wide/flat enough that the fixed-height
box wastes a lot of it as blank top/bottom bars, but don't need bigger
text. Only apply to diagrams confirmed wide via their rendered viewBox
(mermaid-cli) — a portrait diagram would instead grow uncontrolled
without the fixed-height cap, since width:100% + auto height scales
height up from the full container width. */
.no-letterbox-mermaid pre.mermaid > svg {
height: auto;
}

/* furo's generic `.container` class (applied to every MyST {container} block,
including this one) adds fixed margin/padding that doesn't scale with the
diagram — a bigger fraction of a short diagram's height than a tall one, so
it reads as excess whitespace above/below on shorter sequence diagrams. */
.wide-mermaid {
margin: 0;
padding: 0;
}
11 changes: 11 additions & 0 deletions docs-source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
DUAL_THEME_DIAGRAMS = [
"field/network/diagrams/ssl_field_network_fanout_truss.drawio",
"field/network/diagrams/ssl_field_network_fanout_direct.drawio",
"protocol/diagrams/ssl_field_network_fanout_truss_vision_highlight.drawio",
"protocol/diagrams/ssl_field_network_fanout_truss_gc_highlight.drawio",
]


Expand Down Expand Up @@ -182,3 +184,12 @@ def setup(app):
# Intel Core i7-7567U spec sheet — verified 2026-08-09
r"^https://www\.intel\.com/content/www/us/en/products/sku/97541/intel-core-i77567u-processor-4m-cache-up-to-4-00-ghz/specifications\.html$",
]

# The docs link to many individual files in github.com/RoboCup-SSL/ssl-protocol-defs
# (one per proto). Anonymous requests to github.com get secondary-rate-limited fast,
# and linkcheck's default backoff (linkcheck_rate_limit_timeout=300s) means a single
# rate-limited host can stall the whole linkcheck run for many minutes per retry,
# looking like a hang rather than a check failure. Fail fast instead so a
# rate-limited link shows up as a normal report line — re-run later once the limit
# resets, or authenticate (linkcheck_auth) if this becomes a frequent CI problem.
linkcheck_rate_limit_timeout = 15.0
84 changes: 83 additions & 1 deletion docs-source/protocol.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,94 @@
# League Protocols and Communication

[Just looking for the connection summary table?](#connection-summary-table)

"How do I connect to an SSL field?" is one of the first questions a software team member will ask. This page and its
sub-pages document the process of connecting up: interfacing to the field, transport protocols, and data formats. If you
aren't already roughly familiar with the SSL field, checkout the [field documentation](field.md) to learn about the
layout and network structure.

## What does a SSL field provide?

RoboCup SSL fields provide two primary services _to teams_.

1. Robot and Ball Localization (where are the robots and balls?)
1. Game State (game half, timeouts, penalties, etc.)

This article first covers vision (field geometry, robot and ball localization), then game controller (game state).
Conceptually, teams first want to receive robot positions. It does not matter what the game state is if you can't see
anything. Ensuring rules and game state compliance comes next.

## How do I connect to an SSL Field?

1. **A team is never required to reply to the field.** Teams can and do play full matches only _receiving_ field vision
and game controller data. The only input required from a team is it's keeper number which is entered via the Game
Controller Operator or the Remote Control, neither of which is provided by the team.
1. **Field data delivery is not guaranteed.** It's sent at a high rate so **teams are expected to tolerate occasional
dropped packets without re-transmission.** Typically a re-transmission would take a few ms to execute, by which time
the next data frame is probably ready anyway.
1. **All required field data is sent via [multicast](https://en.wikipedia.org/wiki/Multicast) or
[broadcast](<https://en.wikipedia.org/wiki/Broadcasting_(networking)>).** This allows the networking equipment to
duplicate the data stream as many times as needed without the league software managing dozens of connections. It also
means the team's software does not need to know the addresses or hostnames of any specific field computers in order
to connect. The team software simply needs to know the standard multicast addresses and ports of vision and game
controller, and you'll be able to connect to any standard field around the world. Specifically, these data streams
are [UDP](https://en.wikipedia.org/wiki/User_Datagram_Protocol) /[IPv4](https://en.wikipedia.org/wiki/IPv4)
+[IGMP](https://en.wikipedia.org/wiki/Internet_Group_Management_Protocol).
1. **All league packet data is defined by protocol buffers.** You can find the definitions in the
[ssl-protocol-defs repository](https://github.com/RoboCup-SSL/ssl-protocol-defs).

The actual protocols and data formats are documented in the sections below.

## Vision

A detailed description of the vision protocol is provided in a dedicated article.

[Vision Protocol](protocol/vision.md)

## Game Controller

A detailed description of the game controller protocol is provided in a dedicated article.

[Game Controller Protocol](protocol/gamecontroller.md)

## Connection Summary Table

Below is the summary table of protocol addressing and ports. The GC address can be found by listening to the GC
multicast group and reading the [source address](https://en.wikipedia.org/wiki/IPv4#Source_address) field of the IP
layer, rather than knowing it statically.

| Protocol | Protobuf | Type | Address | Port |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | ------------- | ---------- | ----- |
| SSL-Game-Controller (GC) | [Referee](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/gc/ssl_gc_referee_message.proto) | UDP Multicast | 224.5.23.1 | 10003 |
| SSL-Vision Detections | [SSL_WrapperPacket](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/vision/ssl_vision_wrapper.proto) | UDP Multicast | 224.5.23.2 | 10006 |
| AutoRef -> GC | [AutoRef](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/gc/ssl_gc_rcon_autoref.proto) | TCP | GC | 10007 |
| AutoRef -> GC | [AutoRef](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/gc/ssl_gc_rcon_autoref.proto) | TCP + SSL | GC | 10107 |
| Team -> GC | [Team](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/gc/ssl_gc_rcon_team.proto) | TCP | GC | 10008 |
| Team -> GC | [Team](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/gc/ssl_gc_rcon_team.proto) | TCP + SSL | GC | 10108 |
| Remote Control -> GC | [Remote Control](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/gc/ssl_gc_rcon_remotecontrol.proto) | TCP | GC | 10011 |
| Remote Control -> GC | [Remote Control](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/gc/ssl_gc_rcon_remotecontrol.proto) | TCP + SSL | GC | 10111 |
| SSL-Vision-Tracker | [TrackerWrapperPacket](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/vision/ssl_vision_wrapper_tracked.proto) | UDP Multicast | 224.5.23.2 | 10010 |
| Simulation Control | [SimulationControl](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/simulation/ssl_simulation_control.proto) | UDP | Simulator | 10300 |
| Robot Control Blue | [RobotControl](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/simulation/ssl_simulation_robot_control.proto) | UDP | Simulator | 10301 |
| Robot Control Yellow | [RobotControl](https://github.com/RoboCup-SSL/ssl-protocol-defs/blob/main/proto/simulation/ssl_simulation_robot_control.proto) | UDP | Simulator | 10302 |

## Additional Resources

- Unicast
- Multicast
- Broadcast
- TCP
- UDP
- IPv4
- IGMPv4

```{toctree}
---
maxdepth: 1
caption: Contents
---
protocol/vision.md
protocol/gamecontroller.md
protocol/referee.md
protocol/teamclient.md
protocol/simulator.md
```
37 changes: 37 additions & 0 deletions docs-source/protocol/diagrams/coordinate-system-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions docs-source/protocol/diagrams/coordinate-system-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions docs-source/protocol/diagrams/message-hierarchy.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
config:
layout: elk
elk:
nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart TD
Wrapper["SSL_WrapperPacket<br/>one of detection / geometry present"]
Wrapper --> Detection["SSL_DetectionFrame<br/>camera_id, frame_number,<br/>t_capture, t_sent"]
Wrapper --> Geometry["SSL_GeometryData"]

Detection --> Balls["balls[]<br/>SSL_DetectionBall"]
Detection --> RY["robots_yellow[]<br/>SSL_DetectionRobot"]
Detection --> RB["robots_blue[]<br/>SSL_DetectionRobot"]

Geometry --> Field["field<br/>SSL_GeometryFieldSize"]
Geometry --> Calib["calib[]<br/>SSL_GeometryCameraCalibration"]

classDef slate fill:#f8fafc,stroke:#475569,color:#0f172a;
classDef cyan fill:#ecfeff,stroke:#0891b2,color:#164e63;
classDef purple fill:#faf5ff,stroke:#9333ea,color:#581c87;
classDef amber fill:#fffbeb,stroke:#d97706,color:#78350f;
class Wrapper slate;
class Detection,Geometry cyan;
class Balls,RY,RB purple;
class Field,Calib amber;
21 changes: 21 additions & 0 deletions docs-source/protocol/diagrams/multi-camera-merge.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
config:
layout: elk
elk:
nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart LR
subgraph Cams["Cameras"]
C0["Camera 0"]
C1["Camera 1"]
CN["Camera N"]
end

C0 -- "SSL_DetectionFrame<br/>camera_id=0" --> Client["Team Client<br/>merge by camera_id,<br/>reconcile t_capture"]
C1 -- "camera_id=1" --> Client
CN -- "camera_id=N" --> Client

classDef amber fill:#fffbeb,stroke:#d97706,color:#78350f;
classDef cyan fill:#ecfeff,stroke:#0891b2,color:#164e63;
class C0,C1,CN amber;
class Client cyan;
29 changes: 29 additions & 0 deletions docs-source/protocol/diagrams/multicast-join-sequence.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
%%{init: {"sequence": {"useMaxWidth": false, "actorMargin": 220, "messageMargin": 40}}}%%
sequenceDiagram
participant Team as Team Client
participant Net as Switch / Router<br/>(multicast group 224.5.23.2:10006)
participant Vision as Vision Processor

Team->>Net: IGMP Join 224.5.23.2:10006
Note over Team,Vision: No handshake — Team is now another multicast receiver

Vision->>Net: SSL_WrapperPacket<br/>detection (frame 1)
Net->>Team: SSL_WrapperPacket<br/>detection (frame 1)

Vision->>Net: SSL_WrapperPacket<br/>detection (frame 2)
Net->>Team: SSL_WrapperPacket<br/>detection (frame 2)

Note over Vision,Team: Geometry publisher re-sends field geometry every 1s

Vision->>Net: SSL_WrapperPacket<br/>geometry
Net->>Team: SSL_WrapperPacket<br/>geometry

Vision->>Net: SSL_WrapperPacket<br/>detection (frame 3)
Net->>Team: SSL_WrapperPacket<br/>detection (frame 3)

Vision->>Net: SSL_WrapperPacket<br/>detection (frame 4)
Net--xTeam: SSL_WrapperPacket<br/>detection (frame 4) — dropped
Note over Team: No retransmission — team just waits for the next frame

Vision->>Net: SSL_WrapperPacket<br/>detection (frame 5)
Net->>Team: SSL_WrapperPacket<br/>detection (frame 5)
17 changes: 17 additions & 0 deletions docs-source/protocol/diagrams/multicast-join.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
config:
layout: elk
elk:
nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart TD
Team["Team Client<br/>IGMP join only"] -- "IGMP Join<br/>224.5.23.2:10006" --> Net["Switch / Router<br/>duplicates stream"]
Vision["Vision Processor"] -- "SSL_WrapperPacket<br/>UDP multicast, continuous, no ack" --> Net
Net -- "SSL_WrapperPacket" --> Team

classDef purple fill:#faf5ff,stroke:#9333ea,color:#581c87;
classDef cyan fill:#ecfeff,stroke:#0891b2,color:#164e63;
classDef gray fill:#f1f5f9,stroke:#64748b,color:#1e293b;
class Team purple;
class Vision cyan;
class Net gray;
15 changes: 15 additions & 0 deletions docs-source/protocol/diagrams/rcon-handshake-sequence.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
%%{init: {"sequence": {"useMaxWidth": false, "actorMargin": 220, "messageMargin": 40}}}%%
sequenceDiagram
participant Team as Team Client
participant GC as Game Controller

Team->>GC: TCP connect :10008 (or :10108 for TLS)
Team->>GC: TeamRegistration (team_name[, signature])
GC->>Team: ControllerReply (status_code=OK, next_token)
Note over Team,GC: Connection stays open — one registration, then repeated exchanges.<br/>next_token must be echoed back in the next Signature if using secure comms.

Team->>GC: TeamToController (ping)
GC->>Team: ControllerToTeam (controller_reply)

Team->>GC: TeamToController (desired_keeper)
GC->>Team: ControllerToTeam (controller_reply)
18 changes: 18 additions & 0 deletions docs-source/protocol/diagrams/referee-broadcast-sequence.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
%%{init: {"sequence": {"useMaxWidth": false, "actorMargin": 220, "messageMargin": 40}}}%%
sequenceDiagram
participant Team as Team Client
participant Net as Switch / Router<br/>(multicast group 224.5.23.1:10003)
participant GC as Game Controller

Team->>Net: IGMP Join 224.5.23.1:10003
Note over Team,GC: No handshake — Team is now another multicast receiver

GC->>Net: Referee (stage, command, scores)
Net->>Team: Referee (stage, command, scores)

GC->>Net: Referee
Net--xTeam: Referee — dropped
Note over Team: No retransmission — team just waits for the next packet

GC->>Net: Referee
Net->>Team: Referee
17 changes: 17 additions & 0 deletions docs-source/protocol/diagrams/referee-broadcast.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
config:
layout: elk
elk:
nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart TD
Team["Team Client<br/>IGMP join only"] -- "IGMP Join<br/>224.5.23.1:10003" --> Net["Switch / Router<br/>duplicates stream"]
GC["Game Controller"] -- "Referee<br/>UDP multicast, continuous, no ack" --> Net
Net -- "Referee" --> Team

classDef purple fill:#faf5ff,stroke:#9333ea,color:#581c87;
classDef cyan fill:#ecfeff,stroke:#0891b2,color:#164e63;
classDef gray fill:#f1f5f9,stroke:#64748b,color:#1e293b;
class Team purple;
class GC cyan;
class Net gray;
Loading
Loading