Buckets:

hf-doc-build/doc-dev / lerobot /pr_1713 /en /integrate_hardware.html
rtrm's picture
download
raw
66 kB
<meta charset="utf-8" /><meta name="hf:doc:metadata" content="{&quot;title&quot;:&quot;Bring Your Own Hardware&quot;,&quot;local&quot;:&quot;bring-your-own-hardware&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;Prerequisites&quot;,&quot;local&quot;:&quot;prerequisites&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Choose your motors&quot;,&quot;local&quot;:&quot;choose-your-motors&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Step 1: Subclass the Robot Interface&quot;,&quot;local&quot;:&quot;step-1-subclass-the-robot-interface&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Step 2: Define Observation and Action Features&quot;,&quot;local&quot;:&quot;step-2-define-observation-and-action-features&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;observation_features&quot;,&quot;local&quot;:&quot;observationfeatures&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;action_features&quot;,&quot;local&quot;:&quot;actionfeatures&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Step 3: Handle Connection and Disconnection&quot;,&quot;local&quot;:&quot;step-3-handle-connection-and-disconnection&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;is_connected&quot;,&quot;local&quot;:&quot;isconnected&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;connect()&quot;,&quot;local&quot;:&quot;connect&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;disconnect()&quot;,&quot;local&quot;:&quot;disconnect&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Step 4: Support Calibration and Configuration&quot;,&quot;local&quot;:&quot;step-4-support-calibration-and-configuration&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;configure()&quot;,&quot;local&quot;:&quot;configure&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Step 5: Implement Sensors Reading and Action Sending&quot;,&quot;local&quot;:&quot;step-5-implement-sensors-reading-and-action-sending&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;get_observation()&quot;,&quot;local&quot;:&quot;getobservation&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;send_action()&quot;,&quot;local&quot;:&quot;sendaction&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Adding a Teleoperator&quot;,&quot;local&quot;:&quot;adding-a-teleoperator&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Wrapping Up&quot;,&quot;local&quot;:&quot;wrapping-up&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2}],&quot;depth&quot;:1}">
<link href="/docs/lerobot/pr_1713/en/_app/immutable/assets/0.e3b0c442.css" rel="modulepreload">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/entry/start.ff6c7d92.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/chunks/scheduler.f6b352c8.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/chunks/singletons.8fa76063.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/chunks/index.26cf6c5a.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/chunks/paths.e7fcefe1.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/entry/app.492c5e10.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/chunks/index.b90df637.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/nodes/0.5be955ad.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/chunks/each.e59479a4.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/nodes/14.c8b15b10.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/chunks/Tip.366d2e6e.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/chunks/CodeBlock.e5718f9d.js">
<link rel="modulepreload" href="/docs/lerobot/pr_1713/en/_app/immutable/chunks/getInferenceSnippets.00196ff1.js"><!-- HEAD_svelte-u9bgzb_START --><meta name="hf:doc:metadata" content="{&quot;title&quot;:&quot;Bring Your Own Hardware&quot;,&quot;local&quot;:&quot;bring-your-own-hardware&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;Prerequisites&quot;,&quot;local&quot;:&quot;prerequisites&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Choose your motors&quot;,&quot;local&quot;:&quot;choose-your-motors&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Step 1: Subclass the Robot Interface&quot;,&quot;local&quot;:&quot;step-1-subclass-the-robot-interface&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Step 2: Define Observation and Action Features&quot;,&quot;local&quot;:&quot;step-2-define-observation-and-action-features&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;observation_features&quot;,&quot;local&quot;:&quot;observationfeatures&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;action_features&quot;,&quot;local&quot;:&quot;actionfeatures&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Step 3: Handle Connection and Disconnection&quot;,&quot;local&quot;:&quot;step-3-handle-connection-and-disconnection&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;is_connected&quot;,&quot;local&quot;:&quot;isconnected&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;connect()&quot;,&quot;local&quot;:&quot;connect&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;disconnect()&quot;,&quot;local&quot;:&quot;disconnect&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Step 4: Support Calibration and Configuration&quot;,&quot;local&quot;:&quot;step-4-support-calibration-and-configuration&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;configure()&quot;,&quot;local&quot;:&quot;configure&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Step 5: Implement Sensors Reading and Action Sending&quot;,&quot;local&quot;:&quot;step-5-implement-sensors-reading-and-action-sending&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;get_observation()&quot;,&quot;local&quot;:&quot;getobservation&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;send_action()&quot;,&quot;local&quot;:&quot;sendaction&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Adding a Teleoperator&quot;,&quot;local&quot;:&quot;adding-a-teleoperator&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Wrapping Up&quot;,&quot;local&quot;:&quot;wrapping-up&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2}],&quot;depth&quot;:1}"><!-- HEAD_svelte-u9bgzb_END --> <p></p> <h1 class="relative group"><a id="bring-your-own-hardware" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#bring-your-own-hardware"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Bring Your Own Hardware</span></h1> <p data-svelte-h="svelte-sl443g">This tutorial will explain how to integrate your own robot design into the LeRobot ecosystem and have it access all of our tools (data collection, control pipelines, policy training and inference).</p> <p data-svelte-h="svelte-yp6pog">To that end, we provide the <a href="https://github.com/huggingface/lerobot/blob/main/src/lerobot/robots/robot.py" rel="nofollow"><code>Robot</code></a> base class in the LeRobot which specifies a standard interface for physical robot integration. Let’s see how to implement it.</p> <h2 class="relative group"><a id="prerequisites" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#prerequisites"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Prerequisites</span></h2> <ul data-svelte-h="svelte-1dkkhxt"><li>Your own robot which exposes a communication interface (e.g. serial, CAN, TCP)</li> <li>A way to read sensor data and send motor commands programmatically, e.g. manufacturer’s SDK or API, or your own protocol implementation.</li> <li>LeRobot installed in your environment. Follow our <a href="./installation.mdx">Installation Guide</a>.</li></ul> <h2 class="relative group"><a id="choose-your-motors" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#choose-your-motors"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Choose your motors</span></h2> <p data-svelte-h="svelte-9dsyh9">If you’re using Feetech or Dynamixel motors, LeRobot provides built-in bus interfaces:</p> <ul data-svelte-h="svelte-1cfhvoe"><li><a href="https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/feetech/feetech.py" rel="nofollow"><code>FeetechMotorsBus</code></a> – for controlling Feetech servos</li> <li><a href="https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/dynamixel/dynamixel.py" rel="nofollow"><code>DynamixelMotorsBus</code></a> – for controlling Dynamixel servos</li></ul> <p data-svelte-h="svelte-169ujvt">Please refer to the <a href="https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/motors_bus.py" rel="nofollow"><code>MotorsBus</code></a> abstract class to learn about its API.
For a good example of how it can be used, you can have a look at our own <a href="https://github.com/huggingface/lerobot/blob/main/src/lerobot/robots/so101_follower/so101_follower.py" rel="nofollow">SO101 follower implementation</a></p> <p data-svelte-h="svelte-12o83v0">Use these if compatible. Otherwise, you’ll need to find or write a Python interface (not covered in this tutorial):</p> <ul data-svelte-h="svelte-1d5xfjp"><li>Find an existing SDK in Python (or use bindings to C/C++)</li> <li>Or implement a basic communication wrapper (e.g., via pyserial, socket, or CANopen)</li></ul> <p data-svelte-h="svelte-1e113uy">You’re not alone—many community contributions use custom boards or firmware!</p> <p data-svelte-h="svelte-145ejj4">For Feetech and Dynamixel, we currently support these servos: - Feetech: - STS &amp; SMS series (protocol 0): <code>sts3215</code>, <code>sts3250</code>, <code>sm8512bl</code> - SCS series (protocol 1): <code>scs0009</code> - Dynamixel (protocol 2.0 only): <code>xl330-m077</code>, <code>xl330-m288</code>, <code>xl430-w250</code>, <code>xm430-w350</code>, <code>xm540-w270</code>, <code>xc430-w150</code></p> <p data-svelte-h="svelte-wbam8h">If you are using Feetech or Dynamixel servos that are not in this list, you can add those in the <a href="https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/feetech/tables.py" rel="nofollow">Feetech table</a> or <a href="https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/dynamixel/tables.py" rel="nofollow">Dynamixel table</a>. Depending on the model, this will require you to add model-specific information. In most cases though, there shouldn’t be a lot of additions to do.</p> <p data-svelte-h="svelte-tm2a0s">In the next sections, we’ll use a <code>FeetechMotorsBus</code> as the motors interface for the examples. Replace it and adapt to your motors if necessary.</p> <h2 class="relative group"><a id="step-1-subclass-the-robot-interface" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#step-1-subclass-the-robot-interface"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Step 1: Subclass the Robot Interface</span></h2> <p data-svelte-h="svelte-rc24jv">You’ll first need to specify the config class and a string identifier (<code>name</code>) for your robot. If your robot has special needs that you’d like to be able to change easily, it should go here (e.g. port/address, baudrate).</p> <p data-svelte-h="svelte-1p0w0g0">Here, we’ll add the port name and one camera by default for our robot:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">from</span> dataclasses <span class="hljs-keyword">import</span> dataclass, field
<span class="hljs-keyword">from</span> lerobot.cameras <span class="hljs-keyword">import</span> CameraConfig
<span class="hljs-keyword">from</span> lerobot.cameras.opencv <span class="hljs-keyword">import</span> OpenCVCameraConfig
<span class="hljs-keyword">from</span> lerobot.robots <span class="hljs-keyword">import</span> RobotConfig
<span class="hljs-meta">@RobotConfig.register_subclass(<span class="hljs-params"><span class="hljs-string">&quot;my_cool_robot&quot;</span></span>)</span>
<span class="hljs-meta">@dataclass</span>
<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyCoolRobotConfig</span>(<span class="hljs-title class_ inherited__">RobotConfig</span>):
port: <span class="hljs-built_in">str</span>
cameras: <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, CameraConfig] = field(
default_factory={
<span class="hljs-string">&quot;cam_1&quot;</span>: OpenCVCameraConfig(
index_or_path=<span class="hljs-number">2</span>,
fps=<span class="hljs-number">30</span>,
width=<span class="hljs-number">480</span>,
height=<span class="hljs-number">640</span>,
),
}
)<!-- HTML_TAG_END --></pre></div> <p data-svelte-h="svelte-12tjci0"><a href="./cameras.mdx">Cameras tutorial</a> to understand how to detect and add your camera.</p> <p data-svelte-h="svelte-dxku0t">Next, we’ll create our actual robot class which inherits from <code>Robot</code>. This abstract class defines a contract you must follow for your robot to be usable with the rest of the LeRobot tools.</p> <p data-svelte-h="svelte-nb93rz">Here we’ll create a simple 5-DoF robot with one camera. It could be a simple arm but notice that the <code>Robot</code> abstract class does not assume anything on your robot’s form factor. You can let you imagination run wild when designing new robots!</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">from</span> lerobot.cameras <span class="hljs-keyword">import</span> make_cameras_from_configs
<span class="hljs-keyword">from</span> lerobot.motors <span class="hljs-keyword">import</span> Motor, MotorNormMode
<span class="hljs-keyword">from</span> lerobot.motors.feetech <span class="hljs-keyword">import</span> FeetechMotorsBus
<span class="hljs-keyword">from</span> lerobot.robots <span class="hljs-keyword">import</span> Robot
<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyCoolRobot</span>(<span class="hljs-title class_ inherited__">Robot</span>):
config_class = MyCoolRobotConfig
name = <span class="hljs-string">&quot;my_cool_robot&quot;</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, config: MyCoolRobotConfig</span>):
<span class="hljs-built_in">super</span>().__init__(config)
self.bus = FeetechMotorsBus(
port=self.config.port,
motors={
<span class="hljs-string">&quot;joint_1&quot;</span>: Motor(<span class="hljs-number">1</span>, <span class="hljs-string">&quot;sts3250&quot;</span>, MotorNormMode.RANGE_M100_100),
<span class="hljs-string">&quot;joint_2&quot;</span>: Motor(<span class="hljs-number">2</span>, <span class="hljs-string">&quot;sts3215&quot;</span>, MotorNormMode.RANGE_M100_100),
<span class="hljs-string">&quot;joint_3&quot;</span>: Motor(<span class="hljs-number">3</span>, <span class="hljs-string">&quot;sts3215&quot;</span>, MotorNormMode.RANGE_M100_100),
<span class="hljs-string">&quot;joint_4&quot;</span>: Motor(<span class="hljs-number">4</span>, <span class="hljs-string">&quot;sts3215&quot;</span>, MotorNormMode.RANGE_M100_100),
<span class="hljs-string">&quot;joint_5&quot;</span>: Motor(<span class="hljs-number">5</span>, <span class="hljs-string">&quot;sts3215&quot;</span>, MotorNormMode.RANGE_M100_100),
},
calibration=self.calibration,
)
self.cameras = make_cameras_from_configs(config.cameras)<!-- HTML_TAG_END --></pre></div> <h2 class="relative group"><a id="step-2-define-observation-and-action-features" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#step-2-define-observation-and-action-features"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Step 2: Define Observation and Action Features</span></h2> <p data-svelte-h="svelte-l9j1d3">These two properties define the <em>interface contract</em> between your robot and tools that consume it (such as data collection or learning pipelines).</p> <div class="course-tip course-tip-orange bg-gradient-to-br dark:bg-gradient-to-r before:border-orange-500 dark:before:border-orange-800 from-orange-50 dark:from-gray-900 to-white dark:to-gray-950 border border-orange-50 text-orange-700 dark:text-gray-400"><p data-svelte-h="svelte-12r8tyg">Note that these properties must be callable even if the robot is not yet connected, so avoid relying on runtime hardware state to define them.</p></div> <h3 class="relative group"><a id="observationfeatures" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#observationfeatures"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>observation_features</span></h3> <p data-svelte-h="svelte-u7pcb4">This property should return a dictionary describing the structure of sensor outputs from your robot. The keys match what <code>get_observation()</code> returns, and the values describe either the shape (for arrays/images) or the type (for simple values).</p> <p data-svelte-h="svelte-1t42iyr">Example for our 5-DoF arm with one camera:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-meta">@property</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">_motors_ft</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-built_in">type</span>]:
<span class="hljs-keyword">return</span> {
<span class="hljs-string">&quot;joint_1.pos&quot;</span>: <span class="hljs-built_in">float</span>,
<span class="hljs-string">&quot;joint_2.pos&quot;</span>: <span class="hljs-built_in">float</span>,
<span class="hljs-string">&quot;joint_3.pos&quot;</span>: <span class="hljs-built_in">float</span>,
<span class="hljs-string">&quot;joint_4.pos&quot;</span>: <span class="hljs-built_in">float</span>,
<span class="hljs-string">&quot;joint_5.pos&quot;</span>: <span class="hljs-built_in">float</span>,
}
<span class="hljs-meta">@property</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">_cameras_ft</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-built_in">tuple</span>]:
<span class="hljs-keyword">return</span> {
cam: (self.cameras[cam].height, self.cameras[cam].width, <span class="hljs-number">3</span>) <span class="hljs-keyword">for</span> cam <span class="hljs-keyword">in</span> self.cameras
}
<span class="hljs-meta">@property</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">observation_features</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-built_in">dict</span>:
<span class="hljs-keyword">return</span> {**self._motors_ft, **self._cameras_ft}<!-- HTML_TAG_END --></pre></div> <p data-svelte-h="svelte-1rkp57y">In this case, observations consist of a simple dict storing each motor’s position and a camera image.</p> <h3 class="relative group"><a id="actionfeatures" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#actionfeatures"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>action_features</span></h3> <p data-svelte-h="svelte-12yyl6o">This property describes the commands your robot expects via <code>send_action()</code>. Again, keys must match the expected input format, and values define the shape/type of each command.</p> <p data-svelte-h="svelte-1h5avx7">Here, we simply use the same joints proprioceptive features (<code>self._motors_ft</code>) as with <code>observation_features</code>: the action sent will simply the goal position for each motor.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">def</span> <span class="hljs-title function_">action_features</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-built_in">dict</span>:
<span class="hljs-keyword">return</span> self._motors_ft<!-- HTML_TAG_END --></pre></div> <h2 class="relative group"><a id="step-3-handle-connection-and-disconnection" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#step-3-handle-connection-and-disconnection"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Step 3: Handle Connection and Disconnection</span></h2> <p data-svelte-h="svelte-h4v7d7">These methods should handle opening and closing communication with your hardware (e.g. serial ports, CAN interfaces, USB devices, cameras).</p> <h3 class="relative group"><a id="isconnected" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#isconnected"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>is_connected</span></h3> <p data-svelte-h="svelte-1gpnath">This property should simply reflect that communication with the robot’s hardware is established. When this property is <code>True</code>, it should be possible to read and write to the hardware using <code>get_observation()</code> and <code>send_action()</code>.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-meta">@property</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">is_connected</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-built_in">bool</span>:
<span class="hljs-keyword">return</span> self.bus.is_connected <span class="hljs-keyword">and</span> <span class="hljs-built_in">all</span>(cam.is_connected <span class="hljs-keyword">for</span> cam <span class="hljs-keyword">in</span> self.cameras.values())<!-- HTML_TAG_END --></pre></div> <h3 class="relative group"><a id="connect" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#connect"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>connect()</span></h3> <p data-svelte-h="svelte-1iphpc4">This method should establish communication with the hardware. Moreover, if your robot needs calibration and is not calibrated, it should start a calibration procedure by default. If your robot needs some specific configuration, this should also be called here.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">def</span> <span class="hljs-title function_">connect</span>(<span class="hljs-params">self, calibrate: <span class="hljs-built_in">bool</span> = <span class="hljs-literal">True</span></span>) -&gt; <span class="hljs-literal">None</span>:
self.bus.connect()
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> self.is_calibrated <span class="hljs-keyword">and</span> calibrate:
self.calibrate()
<span class="hljs-keyword">for</span> cam <span class="hljs-keyword">in</span> self.cameras.values():
cam.connect()
self.configure()<!-- HTML_TAG_END --></pre></div> <h3 class="relative group"><a id="disconnect" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#disconnect"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>disconnect()</span></h3> <p data-svelte-h="svelte-lfuhuo">This method should gracefully terminate communication with the hardware: free any related resources (threads or processes), close ports, etc.</p> <p data-svelte-h="svelte-1seywak">Here, we already handle this in our <code>MotorsBus</code> and <code>Camera</code> classes so we just need to call their own <code>disconnect()</code> methods:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">def</span> <span class="hljs-title function_">disconnect</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-literal">None</span>:
self.bus.disconnect()
<span class="hljs-keyword">for</span> cam <span class="hljs-keyword">in</span> self.cameras.values():
cam.disconnect()<!-- HTML_TAG_END --></pre></div> <h2 class="relative group"><a id="step-4-support-calibration-and-configuration" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#step-4-support-calibration-and-configuration"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Step 4: Support Calibration and Configuration</span></h2> <p data-svelte-h="svelte-1e7cuec">LeRobot supports saving and loading calibration data automatically. This is useful for joint offsets, zero positions, or sensor alignment.</p> <blockquote data-svelte-h="svelte-9w4yye"><p>Note that depending on your hardware, this may not apply. If that’s the case, you can simply leave these methods as no-ops:</p></blockquote> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START -->&gt; @<span class="hljs-built_in">property</span>
&gt; <span class="hljs-keyword">def</span> <span class="hljs-title function_">is_calibrated</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-built_in">bool</span>:
&gt; <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
&gt;
&gt; <span class="hljs-keyword">def</span> <span class="hljs-title function_">calibrate</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-literal">None</span>:
&gt; <span class="hljs-keyword">pass</span>
&gt; ```
<span class="hljs-comment">### `is_calibrated`</span>
This should reflect whether your robot has the required calibration loaded.
<!-- HTML_TAG_END --></pre></div> python
<p data-svelte-h="svelte-1ufctnq">@property
def is_calibrated(self) -&gt; bool:
return self.bus.is_calibrated</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START -->
<span class="hljs-comment">### `calibrate()`</span>
The goal of the calibration <span class="hljs-keyword">is</span> twofold:
- Know the physical <span class="hljs-built_in">range</span> of motion of each motors <span class="hljs-keyword">in</span> order to only send commands within this <span class="hljs-built_in">range</span>.
- Normalize raw motors positions to sensible continuous values (e.g. percentages, degrees) instead of arbitrary discrete value dependant on the specific motor used that will <span class="hljs-keyword">not</span> replicate elsewhere.
It should implement the logic <span class="hljs-keyword">for</span> calibration (<span class="hljs-keyword">if</span> relevant) <span class="hljs-keyword">and</span> update the `self.calibration` dictionary. If you are using Feetech <span class="hljs-keyword">or</span> Dynamixel motors, our bus interfaces already include methods to <span class="hljs-built_in">help</span> <span class="hljs-keyword">with</span> this.
&lt;!-- prettier-ignore-start --&gt;
```python
<span class="hljs-keyword">def</span> <span class="hljs-title function_">calibrate</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-literal">None</span>:
self.bus.disable_torque()
<span class="hljs-keyword">for</span> motor <span class="hljs-keyword">in</span> self.bus.motors:
self.bus.write(<span class="hljs-string">&quot;Operating_Mode&quot;</span>, motor, OperatingMode.POSITION.value)
<span class="hljs-built_in">input</span>(<span class="hljs-string">f&quot;Move <span class="hljs-subst">{self}</span> to the middle of its range of motion and press ENTER....&quot;</span>)
homing_offsets = self.bus.set_half_turn_homings()
<span class="hljs-built_in">print</span>(
<span class="hljs-string">&quot;Move all joints sequentially through their entire ranges &quot;</span>
<span class="hljs-string">&quot;of motion.\nRecording positions. Press ENTER to stop...&quot;</span>
)
range_mins, range_maxes = self.bus.record_ranges_of_motion()
self.calibration = {}
<span class="hljs-keyword">for</span> motor, m <span class="hljs-keyword">in</span> self.bus.motors.items():
self.calibration[motor] = MotorCalibration(
<span class="hljs-built_in">id</span>=m.<span class="hljs-built_in">id</span>,
drive_mode=<span class="hljs-number">0</span>,
homing_offset=homing_offsets[motor],
range_min=range_mins[motor],
range_max=range_maxes[motor],
)
self.bus.write_calibration(self.calibration)
self._save_calibration()
<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;Calibration saved to&quot;</span>, self.calibration_fpath)<!-- HTML_TAG_END --></pre></div> <h3 class="relative group"><a id="configure" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#configure"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>configure()</span></h3> <p data-svelte-h="svelte-1gxojkw">Use this to set up any configuration for your hardware (servos control modes, controller gains, etc.). This should usually be run at connection time and be idempotent.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">def</span> <span class="hljs-title function_">configure</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-literal">None</span>:
<span class="hljs-keyword">with</span> self.bus.torque_disabled():
self.bus.configure_motors()
<span class="hljs-keyword">for</span> motor <span class="hljs-keyword">in</span> self.bus.motors:
self.bus.write(<span class="hljs-string">&quot;Operating_Mode&quot;</span>, motor, OperatingMode.POSITION.value)
self.bus.write(<span class="hljs-string">&quot;P_Coefficient&quot;</span>, motor, <span class="hljs-number">16</span>)
self.bus.write(<span class="hljs-string">&quot;I_Coefficient&quot;</span>, motor, <span class="hljs-number">0</span>)
self.bus.write(<span class="hljs-string">&quot;D_Coefficient&quot;</span>, motor, <span class="hljs-number">32</span>)<!-- HTML_TAG_END --></pre></div> <h2 class="relative group"><a id="step-5-implement-sensors-reading-and-action-sending" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#step-5-implement-sensors-reading-and-action-sending"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Step 5: Implement Sensors Reading and Action Sending</span></h2> <p data-svelte-h="svelte-1qfd9tp">These are the most important runtime functions: the core I/O loop.</p> <h3 class="relative group"><a id="getobservation" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#getobservation"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>get_observation()</span></h3> <p data-svelte-h="svelte-adteeq">Returns a dictionary of sensor values from the robot. These typically include motor states, camera frames, various sensors, etc. In the LeRobot framework, these observations are what will be fed to a policy in order to predict the actions to take. The dictionary keys and structure must match <code>observation_features</code>.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">def</span> <span class="hljs-title function_">get_observation</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Any</span>]:
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> self.is_connected:
<span class="hljs-keyword">raise</span> ConnectionError(<span class="hljs-string">f&quot;<span class="hljs-subst">{self}</span> is not connected.&quot;</span>)
<span class="hljs-comment"># Read arm position</span>
obs_dict = self.bus.sync_read(<span class="hljs-string">&quot;Present_Position&quot;</span>)
obs_dict = {<span class="hljs-string">f&quot;<span class="hljs-subst">{motor}</span>.pos&quot;</span>: val <span class="hljs-keyword">for</span> motor, val <span class="hljs-keyword">in</span> obs_dict.items()}
<span class="hljs-comment"># Capture images from cameras</span>
<span class="hljs-keyword">for</span> cam_key, cam <span class="hljs-keyword">in</span> self.cameras.items():
obs_dict[cam_key] = cam.async_read()
<span class="hljs-keyword">return</span> obs_dict<!-- HTML_TAG_END --></pre></div> <h3 class="relative group"><a id="sendaction" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#sendaction"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>send_action()</span></h3> <p data-svelte-h="svelte-1elar01">Takes a dictionary that matches <code>action_features</code>, and sends it to your hardware. You can add safety limits (clipping, smoothing) and return what was actually sent.</p> <p data-svelte-h="svelte-xmm0bj">For simplicity, we won’t be adding any modification of the actions in our example here.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">def</span> <span class="hljs-title function_">send_action</span>(<span class="hljs-params">self, action: <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Any</span>]</span>) -&gt; <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Any</span>]:
goal_pos = {key.removesuffix(<span class="hljs-string">&quot;.pos&quot;</span>): val <span class="hljs-keyword">for</span> key, val <span class="hljs-keyword">in</span> action.items()}
<span class="hljs-comment"># Send goal position to the arm</span>
self.bus.sync_write(<span class="hljs-string">&quot;Goal_Position&quot;</span>, goal_pos)
<span class="hljs-keyword">return</span> action<!-- HTML_TAG_END --></pre></div> <h2 class="relative group"><a id="adding-a-teleoperator" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#adding-a-teleoperator"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Adding a Teleoperator</span></h2> <p data-svelte-h="svelte-1s7uvme">For implementing teleoperation devices, we also provide a <a href="https://github.com/huggingface/lerobot/blob/main/src/lerobot/teleoperators/teleoperator.py" rel="nofollow"><code>Teleoperator</code></a> base class. This class is very similar to the <code>Robot</code> base class and also doesn’t assume anything on form factor.</p> <p data-svelte-h="svelte-19bs1hk">The main differences are in the I/O functions: a teleoperator allows you to produce action via <code>get_action</code> and can receive feedback actions via <code>send_feedback</code>. Feedback could be anything controllable on the teleoperation device that could help the person controlling it understand the consequences of the actions sent. Think motion/force feedback on a leader arm, vibrations on a gamepad controller for example. To implement a teleoperator, you can follow this same tutorial and adapt it for these two methods.</p> <h2 class="relative group"><a id="wrapping-up" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#wrapping-up"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Wrapping Up</span></h2> <p data-svelte-h="svelte-ta7vyn">Once your robot class is complete, you can leverage the LeRobot ecosystem:</p> <ul data-svelte-h="svelte-16m8r0w"><li>Control your robot with available teleoperators or integrate directly your teleoperating device</li> <li>Record training data and visualize it</li> <li>Integrate it into RL or imitation learning pipelines</li></ul> <p data-svelte-h="svelte-o90m39">Don’t hesitate to reach out to the community for help on our <a href="https://discord.gg/s3KuuzsPFb" rel="nofollow">Discord</a> 🤗</p> <a class="!text-gray-400 !no-underline text-sm flex items-center not-prose mt-4" href="https://github.com/huggingface/lerobot/blob/main/docs/source/integrate_hardware.mdx" target="_blank"><span data-svelte-h="svelte-1kd6by1">&lt;</span> <span data-svelte-h="svelte-x0xyl0">&gt;</span> <span data-svelte-h="svelte-1dajgef"><span class="underline ml-1.5">Update</span> on GitHub</span></a> <p></p>
<script>
{
__sveltekit_1l4d05w = {
assets: "/docs/lerobot/pr_1713/en",
base: "/docs/lerobot/pr_1713/en",
env: {}
};
const element = document.currentScript.parentElement;
const data = [null,null];
Promise.all([
import("/docs/lerobot/pr_1713/en/_app/immutable/entry/start.ff6c7d92.js"),
import("/docs/lerobot/pr_1713/en/_app/immutable/entry/app.492c5e10.js")
]).then(([kit, app]) => {
kit.start(app, element, {
node_ids: [0, 14],
data,
form: null,
error: null
});
});
}
</script>

Xet Storage Details

Size:
66 kB
·
Xet hash:
a1fbad4610e88fb4b61cc04e5464b65cb3e862457e2a2a8dad84e642aea5f2c1

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.