ICRA 2026

GATO: GPU-Accelerated and Batched Trajectory Optimization for Scalable Edge Model Predictive Control

An open source, GPU-accelerated trajectory optimization solver for batched model predictive control.

1School of Engineering and Applied Science, Columbia University  ·  2University of Michigan
3Barnard College, Columbia University  ·  4Dartmouth College

Real-Time Batch MPC on Hardware

Industrial Manipulator
In the paper’s experiments, GATO achieves 18–21× speedup over CPU baselines and 1.4–16× speedup over GPU baselines as batch size increases. Dated current-code comparisons appear below.

Co-Designed GPU Parallelism for Trajectory Optimization

While Model Predictive Control (MPC) delivers strong performance across robotics applications, solving the underlying (batches of) nonlinear trajectory optimization (TO) problems online remains computationally demanding. Existing GPU-accelerated approaches typically (i) parallelize a single solve to meet real-time deadlines, (ii) scale to very large batches at slower-than-real-time rates, or (iii) achieve speed by restricting model generality (e.g., point-mass dynamics or a single linearization). This leaves a large gap in solver performance for many state-of-the-art MPC applications that require real-time batches of tens to low-hundreds of solves. As such, we present GATO, an open source, GPU-accelerated, batched TO solver co-designed across algorithm, software, and computational hardware to deliver real-time throughput for these moderate batch size regimes. Our approach leverages a combination of block-, warp-, and thread-level parallelism within and across solves for ultra-high performance. We demonstrate the effectiveness of our approach through a combination of: simulated benchmarks showing speedups of 18-21x over CPU baselines and 1.4-16x over GPU baselines as batch size increases; case studies highlighting improved disturbance rejection and convergence behavior; and finally a validation on hardware using an industrial manipulator. We open source GATO to support reproducibility and adoption.

GPU-Accelerated Batched SQP

GATO solves batches of nonlinear trajectory optimization problems using a GPU-accelerated Sequential Quadratic Programming (SQP) approach co-designed across algorithm, software, and hardware. At each SQP iteration, it:

  1. Batch initialization: Initializes all trajectories in parallel across GPU threads, amortizing setup cost over the entire batch.
  2. Parallelized KKT formation & factorization: Exploits block-, warp-, and thread-level GPU parallelism both within a single solve (across time steps) and across solves (across the batch) to form and factor the KKT system via Schur complement decomposition with no CPU-GPU data transfer in the inner loop.
  3. Line search & convergence: Applies a GPU-resident line search with merit function evaluation, enabling fast convergence and strong disturbance rejection without falling back to CPU.

This co-design fills the critical gap between single-solve real-time methods and large-batch offline solvers, enabling scalable edge MPC for manipulation and other robotics applications.

GATO system design overview showing algorithm, software, and hardware co-design

Published Paper Results

These figures report the paper's experiments, not benchmarks of the latest software revision. See the reproduction protocols and current limitations.

Solve-Time Scaling
Bar chart of solve times varying batch size across CPU and GPU solvers
Batch × Horizon Heatmap
Heat map of GATO solve times varying batch size and time horizon

(Left) Solve times for 6-DoF manipulator motions while varying the batch size (M) and underlying solver. N=64 for all solves. GATO shows far improved scalability as compared to state-of-the-art CPU and GPU solutions. (Right) A heat map of solve times while varying both batch size (M) and time horizon (N). GATO is able to reach kHz control rates for real-time iterations of large batches (512) of short horizon (N=8) trajectories, as well as smaller batches (32) of longer horizon trajectories (N=128), showing the flexibility of the design.

Figure-8 Tracking
Bar chart of tracking error and scatter plot of joint velocities for figure-8 task
Disturbance Rejection
End-effector trajectories during figure-8 task with external force applied

Figure-8 tracking task, with an external disturbance applied at the end effector. (Left) Bar chart shows tracking error, scatter plot shows average total joint velocities. Increasing GATO's batch size enables increased disturbance rejection, lowering tracking error and joint velocities until the increased latency from a larger batch size outweighs the optimality gains. (Right) End-effector trajectories realized during this experiment when 50N of external force is applied at the end effector, again showing that modest batch sizes lead to the best performance.

Solve-Time CDF
Cumulative density function of solve times for GATO across different batch sizes and pendulum configurations
Hardware Experiment
Hardware experiment showing GATO successfully and unsuccessfully accounting for time-varying unmodeled disturbance

(Left) Cumulative density function of the solve times for a trajectory length N=16 for GATO across different batch sizes and varied pendulum configurations. For each batch size, the solver accounts for 100 disturbance scenarios. We see how larger batch sizes enable more accurate unmodeled disturbance rejection. (Right) Hardware experiment showing the solver successfully (M=32) and unsuccessfully (M=1) accounting for the time-varying unmodeled disturbance and reach the targets.

Current-Code Experiments

October 2026 experiments use an NVIDIA RTX 5090 with CUDA 13.2. The October 1 iiwa14 figures below use GATO b893083; the Indy7 comparison was collected October 3. These are dated research measurements, not a new release or a reproduction of every paper result. The reproduction protocols specify the differences from the paper.

Solve-Time Scaling (Current)
Current solve times at N=64 for GATO, a multi-threaded QDLDL-based CPU solver and MPCGPU as batch size grows
Batch × Horizon Heatmap (Current)
Current heat map of GATO solve times across batch size and horizon

Internal solver time per batched solve on a matched iiwa14 figure-eight benchmark. GATO is 4.4–7.2× faster than the multi-threaded QDLDL-based CPU solver and is faster than the October 1 MPCGPU baseline at batch sizes of four and above. This MPCGPU baseline predates its October 3 graph-driver update. The paper used Indy7, a different timing boundary and different hardware; these ratios are not directly comparable.

An October 6 check on source 813c6e3 measured controller-call overhead of approximately 42–209 µs across the two arms and batches 1–128. The call excludes sensing, reference preparation and actuator I/O; it is not a whole robot-cycle deadline measurement. Timing boundaries and source details.

Current defaults and device-array calls

October 19–20 measurements cover the current constraint defaults and all five fixed-base arms. At N64 with default ADMM limits, one-iteration NumPy controller-call medians span 0.926–1.284 ms for batches 1 and 8. PyTorch and JAX device inputs preserve the plans but do not reduce call latency in this replay. Host pauses remain visible, including a 43 ms call with limits off; iteration budgets are not hard deadlines. These prescribed-input replays do not establish closed-loop feasibility or replace the paper comparisons. Protocol, all-arm results and raw samples.

URDF limit rows are enabled by default for fixed-base controllers without existing rows. They are soft numerical constraints, not actuator clipping or a hardware safety layer. New-arm holdouts and sustained-saturation studies still show effort or velocity excursions. Constraint behavior and measured limitations.

Indy7: the paper’s robot, a matched current harness

On the same figure-eight problem at N = 64, GATO is 5.2–10.6× faster than the CPU baseline across batches 1–128. Selected October 3 cells are below; all values are internal solver medians in milliseconds. Single-run CPU variability limits the precision of these ratios.

BatchGATOCPUSpeedup
10.2662.4989.4×
40.3383.1699.4×
160.6333.3075.2×
641.87512.0026.4×
1283.62121.9616.1×

The six-joint arm narrows, but does not close, the gap to the published 18–21× CPU comparison. Hardware, baseline implementation and timing boundaries also differ. Bundled values and source hashes accompany the experiment report.

Disturbance hypotheses: two arm-arrival tasks

Exploratory success versus batch size: stop FE 15, 100, 99, 98 percent; pass-through FE 6, 62, 84, 82 and identified-weight 26, 83, 97, 95 percent

Batching improves arm-arrival success in both tested settings. The stop task uses a 1.5 s reference ramp and 100 ms dwell; pass-through uses step references and an instantaneous gate. Both require EE error below 5 cm and joint-velocity norm below 1 rad/s, with a simulated 15 kg swinging payload. These seed-0 scenarios were reused during tuning; the stop artifact records a dirty source tree. Neither task enforces actuator limits or tests payload placement. Clean-source, held-out feasibility validation is a separate experiment, not implied by these curves. Re-render from the bundled evidence.

Held-out feasibility check, October 4: a separate frozen pool completed 1,200 episodes. Both stop variants, including applied-torque clamping, reached all five goals in 100/100 scenarios at batches 8, 32 and 128. However, zero episodes satisfied all measured effort, velocity and position limits. Torque clamping alone did not make the trajectories feasible. These are simulated arm-arrival results, not evidence of hardware-safe payload handling. Complete held-out summary.

Disturbance Rejection (Current)
Current tracking error and joint velocity versus disturbance force for several batch sizes
Batched Rho Search (Current)
Current relative merit versus SQP iteration for several batch sizes

(Left) Figure-eight tracking under an end-effector disturbance at fixed simulation pacing. Larger batches keep tracking error low as the force grows; fixed pacing measures control quality without the batch-latency effect shown in the paper. (Right) Relative merit versus SQP iteration, averaged over 50 random goals and 24 cost settings, when each batch member uses a different regularization value. The paper averaged a larger cost grid.

Supported Robot Systems

GATO ships with five fixed-base arm models and experimental Go2 floating-base examples. Register your own URDF with gato.register_robot(...); its solver compiles once on first use. See the feature-status page for tested configurations: Go2 standing is demonstrated; closed-loop walking remains in development.

RobotDOFNotes
KUKA iiwa147Industrial manipulator; grid dynamics pre-generated via GRiD
Neuromeka Indy76Collaborative robot; grid dynamics pre-generated via GRiD
Franka Research 37Pre-generated dynamics; N64 correctness and replay coverage
Kinova Gen37Pre-generated dynamics; N64 correctness and replay coverage
Universal Robots UR5e6Pre-generated dynamics; N64 correctness and replay coverage
Unitree Go212 + floating baseN16 experimental standing and contact-force variants; walking remains in development

Solver modules are compiled per (robot, knot points, variant) and cached per machine. The signed receipt covers the listed module set, not every buildable horizon or variant combination. Indy7 and iiwa14 have broader horizon coverage; the new arms are tested at N64 and Go2 at N16. See the receipt scope.

Quick Start

The pip command installs the published package. Features listed as unreleased in the changelog require the corresponding source checkout.

Install (Linux + NVIDIA CUDA toolkit)

pip install gato-mpc     # the import name is gato

Solve a batch — numpy, torch or JAX arrays in, the same kind out

import numpy as np
import gato

solver = gato.BSQP(gato.robot_urdf("indy7"), batch_size=8,
                   N=32, dt=0.01, plant_type="indy7")  # compiles once
x0 = np.zeros((8, solver.nx), dtype=np.float32)
goals = np.zeros((8, 32 * 6), dtype=np.float32)
goals[:, 0::6], goals[:, 2::6] = 0.35, 0.5
res = solver.solve(x0, goals)
res = solver.solve(x0, goals, xu_warm=res.xu)  # explicit warm start
print(res.u0(0))

From a checkout (examples, paper figures, the signed receipt)

git clone https://github.com/A2R-Lab/GATO.git && cd GATO
./tools/install.sh --test
MODULES="indy7:64" JOBS=2 ./tools/build.sh
source .venv/bin/activate
python examples/01_single_solve.py        # numbered examples 01 through 14

C++/CUDA (power users) — the same solver, no wrapper in the loop

cmake -S examples/cpp -B build-cpp -DGATO_ROBOT=indy7 -DGATO_N=32   # includes + defines via gato.paths
cmake --build build-cpp --parallel 2 && ./build-cpp/batched_solve      # BSQP<T>::solve on your device buffers

The CUDA module for each (robot, horizon) is compiled on your machine the first time it is used — a few minutes, logged when it starts — and cached under ~/.cache/gato; GRiD and GLASS arrive through the pinned grid-rbd wheel, so no submodule is needed. Wheels never contain compiled modules. See the quick start and requirements, documentation, and numbered examples. Printed demo durations on a shared GPU are not performance measurements. The checkout command builds only Indy7 N64; other example modules compile on first use. Optional examples require their documented dependencies. Use the receipt build profile to prepare the full test module set.

Related Projects

BibTeX

bibtex
@inproceedings{du2026gato,
    title={GATO: GPU-Accelerated and Batched Trajectory Optimization for Scalable Edge Model Predictive Control},
    author={Alexander Du and Emre Adabag and Gabriel Bravo and Brian Plancher},
    booktitle={IEEE International Conference on Robotics and Automation (ICRA)},
    year={2026},
    month={June}
}
GATO logo