nikodembartnik's picture
Upload folder using huggingface_hub
c1e993b verified
Raw History Blame Contribute Delete
26.9 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>LeRobot Command Builder</title>
<meta
name="description"
content="Fill in your robot, ports and dataset once. Copy the exact LeRobot commands for calibration, teleoperation, recording, training and rollout."
/>
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E%F0%9F%A4%96%3C/text%3E%3C/svg%3E" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip-link" href="#steps">Skip to commands</a>
<header class="topbar">
<div class="topbar__brand">
<img class="logo" src="logo.png" alt="LeRobot" width="130" height="42" />
<div>
<h1>Command Builder</h1>
<p class="topbar__sub">Set your hardware once β€” copy the right command at every step.</p>
</div>
</div>
<div class="topbar__actions">
<span class="saved-pill" id="savedPill" role="status" aria-live="polite">Saved locally</span>
<button class="btn btn--ghost" id="themeToggle" type="button" title="Toggle light / dark">
<span id="themeIcon" aria-hidden="true">◐</span><span class="sr-only">Toggle theme</span>
</button>
</div>
</header>
<div class="layout">
<!-- ───────────────────────── SIDEBAR ───────────────────────── -->
<aside class="sidebar" aria-label="Configuration">
<section class="panel panel--profiles">
<h2 class="panel__title">Profile</h2>
<p class="panel__hint">One profile per robot setup. Everything below is remembered in this browser.</p>
<select id="profileSelect" aria-label="Active profile"></select>
<label class="field field--tight">
<span class="field__label">Name</span>
<input type="text" id="profileName" placeholder="SO-101 bench" autocomplete="off" />
</label>
<div class="btn-row">
<button class="btn btn--sm" id="profileNew" type="button">New</button>
<button class="btn btn--sm" id="profileDuplicate" type="button">Duplicate</button>
<button class="btn btn--sm btn--danger" id="profileDelete" type="button">Delete</button>
</div>
<div class="btn-row btn-row--tight">
<button class="btn btn--sm btn--ghost" id="profileExport" type="button">Export JSON</button>
<button class="btn btn--sm btn--ghost" id="profileImport" type="button">Import JSON</button>
<button class="btn btn--sm btn--ghost" id="profileShare" type="button">Copy share link</button>
</div>
<input type="file" id="profileFile" accept=".json,application/json" hidden />
</section>
<section class="panel">
<h2 class="panel__title">You</h2>
<label class="field">
<span class="field__label">Hugging Face username</span>
<input type="text" id="hfUser" placeholder="your-username" autocomplete="off" spellcheck="false" />
<span class="field__hint">Used as the <code>&lt;user&gt;/&lt;name&gt;</code> prefix for datasets and policies.</span>
</label>
</section>
<section class="panel">
<h2 class="panel__title">Robot (follower)</h2>
<label class="field">
<span class="field__label">Type</span>
<select id="robotType"></select>
</label>
<p class="type-note" id="robotNote"></p>
<label class="field">
<span class="field__label">Calibration ID</span>
<input type="text" id="robotId" placeholder="my_follower" autocomplete="off" spellcheck="false" />
<span class="field__hint">A name you pick. Reuse it in every command so calibration is found.</span>
</label>
<div id="robotConnFields"></div>
</section>
<section class="panel">
<h2 class="panel__title">Teleoperator (leader)</h2>
<label class="field">
<span class="field__label">Type</span>
<select id="teleopType"></select>
</label>
<label class="field">
<span class="field__label">Calibration ID</span>
<input type="text" id="teleopId" placeholder="my_leader" autocomplete="off" spellcheck="false" />
</label>
<div id="teleopConnFields"></div>
</section>
<section class="panel">
<div class="panel__head">
<h2 class="panel__title">Cameras</h2>
<button class="btn btn--sm" id="cameraAdd" type="button">+ Add</button>
</div>
<p class="panel__hint">
Camera keys become observation keys in your dataset β€” keep them stable between recording and rollout.
</p>
<div id="cameraList" class="camera-list"></div>
</section>
<section class="panel">
<h2 class="panel__title">Command style</h2>
<label class="check">
<input type="checkbox" id="multiline" />
<span>Multi-line (<code>\</code> continuations)</span>
</label>
<label class="check">
<input type="checkbox" id="useHfVar" />
<span>Use <code>$HF_USER</code> instead of the literal name</span>
</label>
<label class="check">
<input type="checkbox" id="displayData" />
<span>Add <code>--display_data=true</code> (Rerun viewer)</span>
</label>
</section>
</aside>
<!-- ───────────────────────── STEPS ───────────────────────── -->
<main class="steps" id="steps">
<nav class="stepnav" aria-label="Steps">
<a href="#step-1"><b>1</b> Calibrate</a>
<a href="#step-2"><b>2</b> Teleoperate</a>
<a href="#step-3"><b>3</b> Record</a>
<a href="#step-4"><b>4</b> Train</a>
<a href="#step-5"><b>5</b> Rollout</a>
</nav>
<!-- Prerequisites: installing LeRobot and finding serial ports happen
before this tool is useful, so they are links rather than a step. -->
<section class="prereq">
<p class="prereq__lead">
<strong>Before step 1</strong> β€” install LeRobot, assemble the arms and find your serial ports:
</p>
<p class="prereq__links">
<a id="docInstall" href="https://huggingface.co/docs/lerobot/installation" target="_blank" rel="noopener">Installation β†—</a>
<a id="docHardware" href="https://huggingface.co/docs/lerobot/hardware_guide" target="_blank" rel="noopener">Hardware guide β†—</a>
<a id="docRobot" href="https://huggingface.co/docs/lerobot/so101" target="_blank" rel="noopener">Robot setup β†—</a>
<a id="docCheatsheet" href="https://huggingface.co/docs/lerobot/cheat-sheet" target="_blank" rel="noopener">CLI cheat-sheet β†—</a>
</p>
<p class="prereq__extra" id="prereqExtra"></p>
</section>
<div class="warnings" id="warnings" hidden></div>
<!-- STEP 1 -->
<section class="step" id="step-1">
<header class="step__head">
<span class="step__num">1</span>
<div>
<h2 class="step__title">Calibrate</h2>
<p class="step__sub">Teaches LeRobot each joint's range. Do the follower and the leader separately.</p>
</div>
</header>
<div class="step__body">
<div class="step__main">
<div class="cmd" data-cmd="calibrate_robot"></div>
<div class="cmd" data-cmd="calibrate_teleop"></div>
</div>
<aside class="step__aside">
<h3>What to do physically</h3>
<ol>
<li>Move every joint to its <strong>middle</strong> position, then press Enter.</li>
<li>Sweep each joint slowly through its <strong>full</strong> range, one at a time.</li>
<li>Press Enter to save.</li>
</ol>
<p>
Calibration is stored per <code>id</code>. If you change the <code>id</code> later, LeRobot will ask you
to calibrate again β€” so pick a name and keep it.
</p>
<h3>When to redo it</h3>
<ul>
<li>You reassembled or reprinted a joint.</li>
<li>You swapped a motor.</li>
<li>Teleoperation feels offset even though the ports are right.</li>
</ul>
<h3>Read more</h3>
<ul class="doclinks">
<li><a id="docRobotAside" href="https://huggingface.co/docs/lerobot/so101" target="_blank" rel="noopener">Your robot's setup guide β†—</a></li>
<li><a href="https://huggingface.co/docs/lerobot/hardware_guide" target="_blank" rel="noopener">Hardware guide β†—</a></li>
</ul>
</aside>
</div>
</section>
<!-- STEP 2 -->
<section class="step" id="step-2">
<header class="step__head">
<span class="step__num">2</span>
<div>
<h2 class="step__title">Teleoperate</h2>
<p class="step__sub">No recording. Prove the whole chain works before you spend an hour on data.</p>
</div>
</header>
<div class="step__body">
<div class="step__main">
<div class="inline-fields">
<label class="field field--inline">
<span class="field__label">Control loop FPS</span>
<input type="number" id="teleopFps" min="1" max="500" />
</label>
</div>
<div class="cmd" data-cmd="teleoperate"></div>
</div>
<aside class="step__aside">
<h3>Checklist before you record</h3>
<ul>
<li>Follower tracks the leader smoothly, no jumps or dead joints.</li>
<li>Gripper opens and closes over its full range.</li>
<li>
Every camera shows up in the Rerun window, in focus, with the whole workspace visible.
</li>
<li>
<strong>Ask yourself: could I do this task from the camera views alone?</strong> If not, move the
cameras now β€” not after 50 episodes.
</li>
</ul>
<p>
Do 5–10 practice runs without recording. Decide on one repeatable strategy. Hesitant demos teach the
model hesitation.
</p>
</aside>
</div>
</section>
<!-- STEP 3 -->
<section class="step" id="step-3">
<header class="step__head">
<span class="step__num">3</span>
<div>
<h2 class="step__title">Record a dataset</h2>
<p class="step__sub">Arrow keys drive the session: β†’ next, ← redo, ESC finish &amp; upload.</p>
</div>
</header>
<div class="step__body">
<div class="step__main">
<div class="inline-fields">
<label class="field field--inline field--wide">
<span class="field__label">Dataset name</span>
<div class="repo-input">
<span class="repo-input__prefix" id="datasetPrefix">user/</span>
<input type="text" id="datasetName" placeholder="pick_place_lego" autocomplete="off" spellcheck="false" />
</div>
</label>
<label class="field field--inline field--wide">
<span class="field__label">Task description (one sentence)</span>
<input type="text" id="taskDesc" placeholder="Pick the Lego block and drop it in the box on the right." />
</label>
<label class="field field--inline">
<span class="field__label">Episodes</span>
<input type="number" id="numEpisodes" min="1" />
</label>
<label class="field field--inline">
<span class="field__label">Episode seconds</span>
<input type="number" id="episodeTime" min="1" />
</label>
<label class="field field--inline">
<span class="field__label">Reset seconds</span>
<input type="number" id="resetTime" min="0" />
</label>
<label class="field field--inline">
<span class="field__label">Dataset FPS</span>
<input type="number" id="datasetFps" min="1" max="120" />
</label>
</div>
<div class="check-row">
<label class="check">
<input type="checkbox" id="pushToHub" />
<span>Push to the Hub when finished</span>
</label>
<label class="check">
<input type="checkbox" id="privateDataset" />
<span>Private dataset</span>
</label>
<label class="check">
<input type="checkbox" id="resumeRecording" />
<span>Resume an existing dataset</span>
</label>
</div>
<div class="cmd" data-cmd="record"></div>
<h3 class="sub-head">Then check your data β€” before training, always</h3>
<div class="link-row">
<a class="btn btn--accent" id="vizLink" href="https://huggingface.co/spaces/lerobot/visualize_dataset" target="_blank" rel="noopener">
Open dataset viewer β†—
</a>
<span class="link-row__note" id="vizNote">Opens the Hub viewer for this dataset.</span>
</div>
<div class="cmd" data-cmd="viz"></div>
<div class="cmd" data-cmd="replay"></div>
</div>
<aside class="step__aside">
<h3>The golden rule</h3>
<p>
Your first 50 episodes should be a <strong>constrained</strong> version of the task: one object, roughly
fixed position, fixed cameras, one operator. Train a quick ACT model, see what fails, <em>then</em> widen.
</p>
<h3>Data quality beats model choice</h3>
<ul>
<li>Same grasp, same approach vector, same timing every episode.</li>
<li>Deliberate and clean beats fast and sloppy. Speed comes last.</li>
<li>Diffuse, consistent lighting matters more than resolution.</li>
<li>Bolt down the rig and the cameras before recording anything.</li>
</ul>
<h3>What to look for in the viewer</h3>
<ul>
<li>Dropped frames or FPS dips.</li>
<li>Motion blur or an out-of-frame gripper.</li>
<li>Episodes where the task actually failed β€” delete them.</li>
</ul>
<h3>Read more</h3>
<ul class="doclinks">
<li><a href="https://huggingface.co/docs/lerobot/il_robots" target="_blank" rel="noopener">Recording a dataset β†—</a></li>
<li><a href="https://huggingface.co/docs/lerobot/cameras" target="_blank" rel="noopener">Camera setup β†—</a></li>
</ul>
</aside>
</div>
</section>
<!-- STEP 4 -->
<section class="step" id="step-4">
<header class="step__head">
<span class="step__num">4</span>
<div>
<h2 class="step__title">Train</h2>
<p class="step__sub">Pick a policy, point it at a dataset, decide where the weights land.</p>
</div>
</header>
<div class="step__body">
<div class="step__main">
<div class="inline-fields">
<label class="field field--inline field--wide">
<span class="field__label">Train on dataset</span>
<div class="repo-input">
<button class="btn btn--sm btn--fill" id="useRecordedDataset" type="button">
← Use name from step 3
</button>
<input type="text" id="trainDataset" placeholder="user/pick_place_lego" autocomplete="off" spellcheck="false" />
</div>
<span class="field__hint">
Click to pull in the dataset you just recorded, or type any LeRobot-format Hub dataset β€” it does
not have to be your own.
</span>
</label>
<label class="field field--inline field--wide">
<span class="field__label">Policy</span>
<select id="policyType"></select>
</label>
<label class="field field--inline">
<span class="field__label">Device</span>
<select id="device"></select>
</label>
<label class="field field--inline">
<span class="field__label">Batch size</span>
<input type="number" id="batchSize" min="1" />
</label>
<label class="field field--inline">
<span class="field__label">Steps</span>
<input type="number" id="steps" min="1" step="1000" />
</label>
<label class="field field--inline field--wide">
<span class="field__label">Output directory (local checkpoints)</span>
<input type="text" id="outputDir" placeholder="outputs/train/act_pick_place_lego" autocomplete="off" spellcheck="false" />
</label>
<label class="field field--inline field--wide">
<span class="field__label">Push trained policy to</span>
<input type="text" id="policyRepo" placeholder="user/act_pick_place_lego" autocomplete="off" spellcheck="false" />
<span class="field__hint">Leave empty to keep the policy local only.</span>
</label>
<label class="field field--inline field--wide">
<span class="field__label">Run on Hugging Face Jobs (optional)</span>
<input type="text" id="jobTarget" placeholder="a10g-small" autocomplete="off" spellcheck="false" />
<span class="field__hint">No local GPU? Put a flavor here. List them with <code>hf jobs hardware</code>.</span>
</label>
</div>
<div class="check-row">
<label class="check">
<input type="checkbox" id="wandb" />
<span>Log to Weights &amp; Biases</span>
</label>
<label class="check">
<input type="checkbox" id="resumeTraining" />
<span>Resume from last checkpoint</span>
</label>
</div>
<div class="cmd" data-cmd="train"></div>
<div class="cmd" data-cmd="train_resume"></div>
</div>
<aside class="step__aside">
<h3 id="policyNoteHead">Policy notes</h3>
<p id="policyNote"></p>
<h3>How long</h3>
<ul>
<li><strong>ACT, ~50 episodes:</strong> 50k–100k steps is a reasonable first run.</li>
<li>Watch the loss curve, but judge on the <em>real robot</em> β€” loss is a weak proxy for success rate.</li>
<li>Out of VRAM? Halve the batch size before you touch anything else.</li>
</ul>
<h3>Checkpoints</h3>
<p>
Checkpoints land in <code id="ckptPath">outputs/train/&lt;job&gt;/checkpoints/</code>. The one you want at
rollout time is <code>checkpoints/last/pretrained_model</code>.
</p>
<h3>Read more</h3>
<ul class="doclinks">
<li><a id="docPolicy" href="https://huggingface.co/docs/lerobot/act" target="_blank" rel="noopener">This policy's guide β†—</a></li>
<li><a href="https://huggingface.co/docs/lerobot/il_robots" target="_blank" rel="noopener">Imitation learning walkthrough β†—</a></li>
<li><a href="https://huggingface.co/docs/lerobot/hardware_guide" target="_blank" rel="noopener">Hardware guide β†—</a></li>
<li><a href="https://huggingface.co/docs/lerobot/multi_gpu_training" target="_blank" rel="noopener">Multi-GPU training β†—</a></li>
<li><a href="https://huggingface.co/docs/hub/jobs" target="_blank" rel="noopener">Hugging Face Jobs β†—</a></li>
</ul>
</aside>
</div>
</section>
<!-- STEP 5 -->
<section class="step" id="step-5">
<header class="step__head">
<span class="step__num">5</span>
<div>
<h2 class="step__title">Rollout</h2>
<p class="step__sub">Run the policy on the real robot β€” and measure it honestly.</p>
</div>
</header>
<div class="step__body">
<div class="step__main">
<div class="inline-fields">
<label class="field field--inline field--wide">
<span class="field__label">Policy path or Hub repo</span>
<div class="repo-input">
<button class="btn btn--sm btn--fill" id="useTrainedPolicy" type="button">
← Use policy from step 4
</button>
<input type="text" id="policyPath" placeholder="outputs/train/act_pick_place_lego/checkpoints/last/pretrained_model" autocomplete="off" spellcheck="false" />
</div>
<span class="field__hint">
Click to fill in where step 4 saved your policy, or paste a local checkpoint path or Hub repo id.
</span>
</label>
<label class="field field--inline field--wide">
<span class="field__label">Strategy</span>
<select id="rolloutStrategy"></select>
</label>
<label class="field field--inline field--wide">
<span class="field__label">Inference backend</span>
<select id="inferenceType"></select>
</label>
<label class="field field--inline">
<span class="field__label">Duration (s)</span>
<input type="number" id="rolloutDuration" min="0" />
<span class="field__hint">0 = run until you stop it.</span>
</label>
<label class="field field--inline">
<span class="field__label">Rollout FPS</span>
<input type="number" id="rolloutFps" min="1" max="500" />
</label>
<label class="field field--inline field--wide" id="rolloutDatasetField">
<span class="field__label">Record rollouts into</span>
<div class="repo-input">
<span class="repo-input__prefix" id="rolloutPrefix">user/</span>
<input type="text" id="rolloutDataset" placeholder="eval_pick_place_lego" autocomplete="off" spellcheck="false" />
</div>
</label>
</div>
<div class="check-row">
<label class="check">
<input type="checkbox" id="interactive" />
<span>Interactive mode (<code>/start</code>, <code>/subtask</code>, <code>/stop</code> from stdin)</span>
</label>
</div>
<div class="cmd" data-cmd="rollout"></div>
</div>
<aside class="step__aside">
<h3 id="strategyNoteHead">Strategy</h3>
<p id="strategyNote"></p>
<h3 id="inferenceNoteHead">Inference</h3>
<p id="inferenceNote"></p>
<h3>Evaluate like you mean it</h3>
<ul>
<li>
Run ~10 attempts under the <em>same</em> conditions as training and count successes. That number, not
the loss curve, is your result.
</li>
<li>Compare against a teleoperated baseline β€” if you can't do it by hand reliably, the policy won't.</li>
<li>
Failures cluster. Watch where: wrong approach angle, grasp slips, object outside the training
distribution. Each one points at different data to collect next.
</li>
</ul>
<p>
Want those attempts saved? Switch the strategy to <code>episodic</code> or <code>sentry</code> β€” they
record while the policy runs. Feed failures back with <code>dagger</code>: you take over when it goes
wrong, and only your corrections get recorded.
</p>
<h3>Read more</h3>
<ul class="doclinks">
<li><a href="https://huggingface.co/docs/lerobot/inference" target="_blank" rel="noopener">Running inference β†—</a></li>
<li><a href="https://huggingface.co/docs/lerobot/rtc" target="_blank" rel="noopener">Real-Time Chunking β†—</a></li>
<li><a href="https://huggingface.co/docs/lerobot/hil_data_collection" target="_blank" rel="noopener">Human-in-the-loop data β†—</a></li>
</ul>
</aside>
</div>
</section>
<footer class="foot">
<p>
Built for <a href="https://github.com/huggingface/lerobot" target="_blank" rel="noopener">huggingface/lerobot</a>.
Commands mirror the current CLI β€” check
<a href="https://huggingface.co/docs/lerobot" target="_blank" rel="noopener">the docs</a> if a flag was renamed.
</p>
<p class="foot__privacy">
Everything you type stays in this browser's <code>localStorage</code>. Nothing is uploaded, and there is no
backend to send it to.
</p>
</footer>
</main>
</div>
<div class="toast" id="toast" role="status" aria-live="polite" hidden></div>
<script type="module" src="app.js"></script>
</body>
</html>