Instructions to use fport/getporti-lab with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LeRobot
How to use fport/getporti-lab with LeRobot:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- MJLab
How to use fport/getporti-lab with MJLab:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
getporti lab · trained robot brains
The policies behind the getporti robotics videos: Unitree Go2, G1 and Go1, Open Duck Mini v2, a microduck kick and a bimanual ALOHA arm pair, all trained by us in simulation (MuJoCo MJX + brax PPO; mjlab for the kick; LeRobot ACT for the arms), plus every checkpoint along the way and the transcripts of LLM agents that use them as tools. Each experiment changes one thing in an official recipe and keeps a matched control, so most brains here come in pairs: the one that learned the trick and the one that did not.
The training code, frozen experiment designs and full result tables live in the getporti-lab GitHub repository,
which is private for now; this page has everything needed to run the brains.
Every number below is grade L: ours, simulated, usually one training seed per arm. None of these policies has been
run on a real robot.
Brains
Go2 · go2-patrol/, go2-latency/
MuJoCo Playground's Go1 joystick task with the Go2 swapped in. Input 48 numbers, output 12 joint targets.
| File | What it is | Result |
|---|---|---|
go2-patrol/flat_201M.pkl |
the walking brain, 200 M steps from scratch (13.8 min on an A100) | 0.75 m/s, 0/16 falls on flat |
go2-patrol/bumps_finetune_41M.pkl |
flat brain fine-tuned 40 M steps on a 5 cm bumpy floor | 0/16 falls on bumps (flat brain: 3/16) |
go2-patrol/bumps_scratch_41M.pkl |
control: same 40 M steps on bumps, from scratch | 0/16 falls, but 0.005 m/s: it learned to stand |
go2-latency/delay_finetune_41M.pkl |
flat brain continued 40 M with random motor delay 0–60 ms | 0/16 falls up to 60 ms at 0.74 m/s (flat brain breaks at 32 ms) |
go2-latency/delay_scratch_201M.pkl |
control: random delay from scratch, 200 M | never falls, never walks (0.01 m/s) |
Karabaş, one Go2 brain through seven obstacles · karabas/
Each stage restores the policy and value function of an earlier one. Files 05_* and 06_* see a 55-point height
scan (input 103); the blind controls get the same 103 inputs with the scan zeroed.
| File | Stage | Result |
|---|---|---|
01_slope_64M.pkl |
slope park, grade curriculum | cobbled street climbed 16/16 (MJX) |
02_melon_payload_20M.pkl |
random payload 0–30 kg during training | 20 kg melon on the back: 0/32 falls |
02_melon_control_20M.pkl |
control: same steps, no payload | 32/32 falls with the melon |
03_stairs_blind_82M.pkl |
blind stair curriculum | limit 5–6 cm risers; 16 cm 0/32 |
04_bump_16M.pkl |
sharp-bump park | 10 cm speed bump 53/64 (start brain 14/64) |
05_curb_seeing_45M.pkl |
height scan in the policy, curb park | 15 cm curb 30/32 at this checkpoint |
05_curb_blind_45M.pkl |
control: scan zeroed | learns to halt at the curb |
06_stairs_seeing_78M.pkl |
stair rematch, gated reward relief + level curriculum | 16 cm stairs, median 9 of 10 steps |
06_stairs_blind_66M.pkl |
control: same recipe, scan zeroed | last checkpoint of the blind arm |
G1 humanoid · g1-push/
Playground G1JoystickFlatTerrain, 200 M steps each. Input 103, output 29.
| File | What it is | Falls in 480 scripted pushes |
|---|---|---|
g1-push/push.pkl |
trained with random pushes (Playground default) | 130 |
g1-push/nopush.pkl |
control: pushes off | 260 (Unitree's released policy: 252) |
Go1 · go1/
| File | What it is |
|---|---|
go1/go1_93M.{pkl,onnx} |
the official Go1 recipe trained on a Mac CPU (960 envs); the first checkpoint that walks, 2 h 05 min |
Open Duck Mini v2 · open-duck/
Open_Duck_Playground joystick task, trained on a Mac CPU. Input 101, output 14; ONNX next to every pickle.
| File | What it is |
|---|---|
walk_68M, walk_72M |
walking from scratch: first lifts its feet at 68.4 M (29.8 cm in 5 s) |
hacked_fast, hacked_fast_no_flip_end, hacked_energy, hacked_feet_air |
the 68.4 M duck continued on deliberately broken rewards; together they found flipping and crawling, freezing, and lying with feet up |
no_imitation_109M |
imitation reward removed: it stands, on every checkpoint |
torque_random_{89M,138M,301M} |
servo torque randomised: walks at the 1.86 N·m catalogue torque at 89 M and 138 M, has forgotten by 301 M |
Two-arm Turkish coffee · aloha-act/
LeRobot ACT (lerobot==0.6.1) on gym-aloha's bimanual ViperX with our cezve, cup and 60 balls. Load the folder with
ACTPolicy.from_pretrained.
| Folder | Demos | Successful pours / 32 at 20 k steps |
|---|---|---|
coffee_act_d50_20k/ |
50 | 9 |
coffee_act_d10_20k/ |
10 | 4 |
Goal kick, our RL kick for an LLM agent · goal-kick/out/
Trained by us on Pollen's microduck BallKick task (mjlab + rsl_rl PPO, 4 096 envs, 1 000 iterations, A100), ball anywhere
in a 7 × 7 cm patch beside the right foot. ONNX, Pollen's input layout; *.onnx.json holds the observation spec.
| File | Inputs | Result |
|---|---|---|
blind.onnx |
61 (proprioception, no ball) | 19 goals on 30 patch spots (Pollen's kick: 14); 26/81 in the strands-robots world |
see.onnx |
67 (+ ball position and velocity) | ties Blind in training (30 vs 32 of 81), 0/81 in the strands-robots world |
eval-{Blind,See}-<iteration>.npz are the 81-spot evaluations at iterations 0, 250, 500, 750 and 999.
Learning, step by step · checkpoints/
The full checkpoint series of every training run above (≈ 1 GB): each brain as it was at every evaluation during
training, named by environment steps (ckpt_<steps>.pkl, ONNX next to it where we exported one). Load any of them the
same way as the brains above and watch when a skill appears: when the Go2 first walks, when Karabaş first climbs a step,
when the duck lifts its feet and when it forgets.
checkpoints/<experiment>/<arm>/, for example checkpoints/karabas/06_stairs_seeing/, checkpoints/open-duck/walk/,
checkpoints/go2-patrol/flat/. Arms follow the tables above; _a1, _a3 are the earlier design amendments of a stage.
LLM agents driving robots · agent-runs/
Transcripts of Strands Agents runs with a local model (qwen 2.5 / 3.5 via Ollama) that controls robots through tools:
agent-runs/strands-agent/<run>/: an SO-100 arm asked to pick up a cube;tools.jsonlis every tool call with its arguments and result,qpos.jsonlthe arm's state,summary.jsonthe outcome.agent-runs/goal-kick/: the microduck agent that places a ball and kicks:goal-*.jsonper run (placements, kicks, goals),*.logthe agent's own output. With the original tool description it never scored in 9 runs; with one sentence saying where the ball must lie, 4 of 6 runs scored.
Use
Each .pkl is a brax PPO checkpoint (normalizer, policy, value). The policy is a small MLP, so plain numpy runs it;
no JAX or brax is needed. Copy this, or download load_brain.py from this repo:
import pickle
import numpy as np
from huggingface_hub import hf_hub_download
class _Bag: # stands in for brax/flax classes: no JAX needed
def __init__(self, *a, **k): pass
def __setstate__(self, s): self.__dict__.update(s if isinstance(s, dict) else {"state": s})
class _Unpickler(pickle.Unpickler):
def find_class(self, module, name):
if module.split(".")[0] in ("brax", "flax", "jax", "jaxlib", "optax", "ml_collections"):
return _Bag
return super().find_class(module, name)
def load_brain(path):
"""brax PPO checkpoint (normalizer, policy, value) -> numpy function: observation -> action."""
with open(path, "rb") as f:
norm, policy, _ = _Unpickler(f).load()
get = lambda o, k: o[k] if isinstance(o, dict) else getattr(o, k)
stat = lambda k: np.asarray(get(get(norm, k), "state") if not isinstance(get(norm, k), np.ndarray) else get(norm, k))
mean, std = stat("mean"), stat("std")
p = policy["params"]
layers = [(np.asarray(p[k]["kernel"]), np.asarray(p[k]["bias"])) for k in sorted(p, key=lambda s: int(s.split("_")[-1]))]
def act(obs):
x = (np.asarray(obs, np.float64) - mean) / std
with np.errstate(all="ignore"): # numpy on macOS Accelerate raises spurious matmul flags
for i, (w, b) in enumerate(layers):
x = x @ w + b
if i < len(layers) - 1:
x = x / (1 + np.exp(-x)) # swish
return np.tanh(x[: len(x) // 2]) # deterministic action = tanh(mean)
return act
brain = load_brain(hf_hub_download("fport/getporti-lab", "go2-patrol/flat_201M.pkl"))
action = brain(np.zeros(48)) # the 48-number Go2 observation, layout below
print(action.shape, action.round(2)) # 12 numbers; joint target = home pose + 0.5 * action
What goes in and what comes out:
| Robot | Input | Output | Control |
|---|---|---|---|
| Go2, Go1 (48) | body velocity (3), gyro (3), gravity in body frame (3), joint angles − home (12), joint velocities (12), last action (12), command vx vy yaw-rate (3) | 12 | target = home + 0.5 · action, 50 Hz, Kp 35, Kd 0.5 |
Karabaş 05_*, 06_* (103) |
the 48 above + a 55-point height scan (11 × 5 grid, 0.4 m behind to 0.6 m ahead of the trunk, ±0.2 m sideways; zeros for the blind controls) | 12 | same as Go2 |
| G1 (103) | Playground G1JoystickFlatTerrain observation |
29 | Playground G1 joystick task |
| Open Duck (101) | Open_Duck_Playground joystick observation | 14 | also as ONNX, input obs, same interface as the official export |
To roll one out in MuJoCo, use the matching MuJoCo Playground task (Go2 = the Go1 joystick task with Menagerie's
unitree_go2) and feed the observation every control step. The run_config*.json next to each brain records the env,
the one variable, the PPO settings, the restore point and the device, so a run can be repeated or continued
(restore_params with the same pickle).
The two ACT folders load with LeRobot 0.6.1: ACTPolicy.from_pretrained("<folder>").
Pins
jax 0.6.2, brax 0.12.4, playground 0.0.5, mujoco / mujoco-mjx 3.3.3, Menagerie cda5236, Open_Duck_Playground
b9be205; goal kick: microduck_rl bae39f5 (mjlab), strands-robots 0.6.0; agents: strands-agents 1.62 / 1.64. A different version can change the physics and with it every number above.