Tempo¶
The TempoSample project: a street sweeper driving the Lower Sector environment, with semantic labels overlaid.
Tempo is a collection of simulation-focused plugins for Unreal Engine. It makes the power of Unreal accessible to simulation and robotics developers, with plugins for client APIs, sensor simulation, agent behaviors, and more.
Tempo is the foundation on which you build a simulator for your application — a set of composable plugins, not a turnkey product.
-
Get running in an hour
Install the prerequisites, add Tempo to a project, build it, and drive a simulation from a Python REPL.
-
Understand the model
Deterministic time, the units and coordinate frame the API speaks, and how actors are named over the wire.
-
Explore the plugins
Time and the gRPC server, world control, sensors, movement, agents, geography, procedural content.
-
Look up an RPC
Every service, RPC, message and field — generated from the
.protofiles on every build.
Why Tempo¶
Tempo is for building your own robotics simulator on modern Unreal Engine and driving all of it from code. Among great simulators (CARLA, AirSim/Colosseum, Gazebo, Webots, Isaac Sim, Genesis), here is an honest look at where it fits.
What Tempo is good at¶
| Key feature | What it means for your simulator |
|---|---|
| Modern Unreal + ecosystem | Runs on UE 5.7 / 5.8 — Lumen, Nanite, PCG, Niagara, MetaHuman, Chaos, and the huge library of real-time content the engine community ships, all for free. |
| gRPC API, no ROS required | The primary interface is gRPC: language-agnostic, schema-first, with HTTP/2 streaming. Clients connect across machines and platforms (Rust on Linux → sim on a Mac) — a step up from the older msgpack-RPC interfaces some sims use, and not tied to an in-process language. |
| Code-generated, reflection-based control | One set of .proto files generates Python / Rust / C++ clients (sync + async). Spawn any actor and get/set any property over the wire — no engine code needed. |
| High-fidelity sensors | Cameras with multiple lens models (incl. wide-FOV fisheye), semantic + instance segmentation, 2D bounding boxes, and hardware H.264 streaming; lidar with per-beam calibration and material-derived reflectivity. |
| Deterministic time | Pause / play / step and wall-clock vs. fixed-step time, all over the API — built for reproducible runs and data generation. |
| Native, optional ROS 2 | rclcpp runs in-process (no separate bridge process) and is entirely optional. |
| Runs where you work | Linux, Windows, and macOS (unusual among photorealistic engine-based sims). Develop locally on the hardware you already have. |
| Extensible by design | Tempo is built entirely as Unreal plugins (plus a few engine patches). If you can build it in Unreal, you can build it alongside Tempo. |
Where another tool may fit better¶
| If you need… | Consider |
|---|---|
| Massive-scale parallel RL (thousands of GPU envs, Gym-style) | Isaac Lab, Genesis |
| Contact-rich / legged-robot physics fidelity | Isaac Sim (PhysX), Genesis (differentiable) |
| To drop in existing robot descriptions (URDF/SDF/USD) | Gazebo, Isaac Sim |
| A turnkey AV stack with prebuilt maps & scenarios | CARLA |
In short: Tempo is the strongest fit for a photorealistic, deeply customizable simulator on modern Unreal, controlled entirely from code, that runs on the hardware your team already has — especially if you're comfortable in Unreal. It's a younger project with a smaller community and content library than the largest established sims, and it deliberately leaves the last mile — your scenarios, robots, and application — to you. That trade-off is the point.
A taste of the API¶
Everything below is a client talking to a running Unreal Editor or packaged binary over gRPC.
import tempo_sim.tempo_core as tc
import tempo_sim.tempo_world as tw
import tempo_sim.TempoCore.Time_pb2 as Time
tc.set_time_mode(Time.TM_FIXED_STEP) # deterministic, reproducible time
tc.set_sim_steps_per_second(10)
rig = tw.spawn_actor(actor_type="BP_SensorRig")
tw.set_float_property(actor=rig.name, component="TempoCamera",
property="FOVAngle", value=60.0)
for _ in range(100):
tc.step() # advance exactly 0.1 s
Getting help¶
Not sure where to start? Want guidance from the authors? Find us on Discord.
Something not working as expected, or a key feature missing? Send us an issue. Want to contribute? We'll be happy to review your PR.