A physics-based simulator for RoboCup Small Size League (SSL) built in Rust. Developed by luhbots for testing and developing robot strategy software without needing physical hardware.
LuhSim implements the official SSL simulation protocol over UDP using Protocol Buffers, making it a drop-in replacement for other SSL simulators like grSim or ErSim.
- 3D rigid body physics via Rapier3D 0.32 (glam/glamx math backend)
- Dribbler physics using a spring-damper model that holds the ball at the robot's front face
- Two teams (Blue and Yellow) with up to 16 robots each (IDs 0–15)
- SSL-compliant protocol using the official proto message definitions from
luhsoccer_protobuf - Vision output compatible with ssl-vision consumers (field geometry, ball/robot detections)
- Robot control — global velocity, local (robot-frame) velocity, wheel velocities, dribbler, flat/chip kick
- Teleportation API for repositioning robots and ball via simulator commands
- Dribbler contact detection reported per-robot in feedback packets
- Goal colliders — full goal box geometry (back wall, side walls, crossbar) as physics colliders
- [WIP] Configurable physics via
config.toml(ball mass, robot speed, field dimensions, etc.) - Simulation as library — the physics engine is a standalone subcrate (
src/simulation/) usable without the UDP server
To run the simulation with cargo you can use the command:
cargo run -- -r <realism_file> -g <geometry_file>where the files are just the config files for realism and geometry respectively.
Other options can be seen with --help
To build the simulation, you simply have to do it the normal way:
cargo build --releaseThen you can start the binary using the same commands as seen above.
On startup, the simulator binds four UDP ports (can all be overwritten with arguments):
| Port | Purpose | Protocol Direction |
|---|---|---|
10300 |
Simulator control (teleport, config) | Receive SimulatorCommand, send SimulatorResponse |
10301 |
Blue team robot commands | Receive RobotControl, send RobotControlResponse |
10302 |
Yellow team robot commands | Receive RobotControl, send RobotControlResponse |
10303 |
Vision sync control | Receive SimulationSyncRequest |
10020 |
Vision output | Send SslWrapperPacket (detection + geometry) |
The project is a Cargo workspace with two crates:
network_sim— (binary) UDP servers, protobuf encode/decode, main simulation loopsimulation— (library) (src/simulation/): all Rapier3D physics, no networking
- X-axis: field length (goal to goal)
- Y-axis: field width
- Z-axis: height (upward)
Vision output uses millimetres. Internal physics uses metres.
- Synchronous simulation mode: The
SimulationSyncRequestport is bound but the sync loop is not yet implemented — the simulator always runs in free-running mode. - Chip kick angle: Chip kick fires at a fixed angle derived from the kick command's
kick_anglefield; trajectory physics are handled by Rapier's gravity but no bounce model is implemented.