LeRobot documentation

Dùng phần cứng của riêng bạn

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.7.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Dùng phần cứng của riêng bạn

Hướng dẫn này sẽ giải thích cách tích hợp thiết kế robot của bạn vào hệ sinh thái LeRobot và cho phép nó truy cập tất cả các công cụ của chúng tôi (thu thập dữ liệu, các pipeline điều khiển, huấn luyện và suy luận chính sách).

Với mục đích đó, chúng tôi cung cấp lớp cơ sở Robot trong LeRobot, xác định một giao diện chuẩn cho việc tích hợp robot vật lý. Hãy cùng xem cách triển khai nó.

Yêu cầu tiên quyết

  • Robot của bạn có giao diện giao tiếp (ví dụ: serial, CAN, TCP)
  • Một cách để đọc dữ liệu cảm biến và gửi lệnh động cơ theo chương trình, ví dụ như SDK hoặc API của nhà sản xuất, hoặc chính bạn tự triển khai giao thức.
  • LeRobot đã được cài đặt trong môi trường của bạn. Hãy làm theo Hướng dẫn cài đặt của chúng tôi.

Chọn động cơ của bạn

Nếu bạn đang sử dụng động cơ Feetech hoặc Dynamixel, LeRobot cung cấp giao diện bus tích hợp sẵn, SerialMotorsBus, có thể điều khiển cả hai dòng động cơ này: model của từng động cơ sẽ xác định dòng tương ứng. Hãy tham khảo tài liệu của nó để tìm hiểu về API. Bạn cần cài đặt gói bổ sung serial-motors, trong đó sẽ cài đặt rustypot: pip install 'lerobot[serial-motors]', hoặc pip install -e ".[serial-motors]" từ bản checkout mã nguồn. Để có một ví dụ tốt về cách sử dụng, bạn có thể xem cách triển khai SO101 follower của chúng tôi.

Sử dụng các thành phần này nếu tương thích. Nếu không, bạn sẽ cần tìm hoặc viết một giao diện Python (không được đề cập trong hướng dẫn này):

  • Tìm một SDK có sẵn trong Python (hoặc sử dụng các bindings cho C/C++)
  • Hoặc triển khai một lớp bọc giao tiếp cơ bản (ví dụ: thông qua pyserial, socket hoặc CANopen)

Bạn không đơn độc—nhiều đóng góp từ cộng đồng sử dụng các bo mạch tùy chỉnh hoặc firmware!

Đối với Feetech và Dynamixel, hiện tại chúng tôi hỗ trợ các servo sau:

  • Feetech STS & SMS series: sts3215, sts3250, sm8512bl
  • Feetech SCS series: scs0009
  • Dòng Dynamixel X (giao thức 2.0): xl330-m077, xl330-m288, xc330-t181, xc330-t288, xl430-w250, xl430-w250-2, xc430-w150, xm430-w350, xm540-w270, xh540-w150

Các model có thể chia sẻ một bus, các servo STS/SMS và SCS hoặc XL430 và XL330: mỗi motor được đọc và ghi thông qua định nghĩa của chính model của nó, bao gồm cả thứ tự byte và mã hóa dấu. Sự khác biệt giữa các dòng sản phẩm bắt nguồn từ chính các định nghĩa đó: giá trị chế độ hoạt động nào có nghĩa là điều khiển vị trí (bus.set_operating_mode("position")), offset homing được cộng vào vị trí hay bị trừ khỏi vị trí, và những thanh ghi nào tồn tại.

Việc hỗ trợ một model không có nghĩa là mọi công cụ hiệu chỉnh đều hoạt động trên model đó: Feetech SCS0009 không có chế độ hoạt động cũng như không có độ lệch về vị trí gốc, do đó set_operating_mode() và set_half_turn_homings() sẽ từ chối model này. Công thức hiệu chỉnh bên dưới dành cho các servo có cả hai, chẳng hạn như STS; một servo SCS được hiệu chỉnh chỉ bằng phạm vi của nó.

Nếu bạn đang sử dụng servo Feetech hoặc Dynamixel không có trong danh sách này, hãy thêm chúng vào rustypot, nơi lưu trữ các bảng điều khiển mà các bus đọc: một model chia sẻ bảng điều khiển hiện có chỉ cần đăng ký số model, còn một model mới cần định nghĩa servo (xem hướng dẫn đóng góp servo). LeRobot đọc các model từ gói Python rustypot đã cài đặt, vì vậy nó phải bao gồm model mới: một bản phát hành rustypot có chứa model đó, hoặc rustypot được biên dịch từ mã nguồn.

Trong các phần tiếp theo, các ví dụ sử dụng động cơ Feetech. Hãy thay đổi các model và điều chỉnh cho phù hợp với động cơ của bạn nếu cần.

Bước 1: Kế thừa giao diện Robot

Trước tiên, bạn cần chỉ định lớp cấu hình và một chuỗi định danh (name) cho robot của bạn. Nếu robot của bạn có các yêu cầu đặc biệt mà bạn muốn có thể thay đổi dễ dàng, hãy đặt chúng ở đây (ví dụ: cổng/địa chỉ, baudrate).

Ở đây, chúng ta sẽ thêm tên cổng và một camera mặc định cho robot của mình:

from dataclasses import dataclass, field

from lerobot.cameras import CameraConfig
from lerobot.cameras.opencv import OpenCVCameraConfig
from lerobot.robots import RobotConfig


@RobotConfig.register_subclass("my_cool_robot")
@dataclass
class MyCoolRobotConfig(RobotConfig):
    port: str
    cameras: dict[str, CameraConfig] = field(
        default_factory=lambda: {
            "cam_1": OpenCVCameraConfig(
                index_or_path=2,
                fps=30,
                width=480,
                height=640,
            ),
        }
    )

Hướng dẫn về camera để hiểu cách phát hiện và thêm camera của bạn.

Tiếp theo, chúng ta sẽ tạo lớp robot thực tế của mình, kế thừa từ Robot. Lớp trừu tượng này định nghĩa một hợp đồng mà bạn phải tuân theo để robot của bạn có thể được sử dụng với các công cụ LeRobot khác.

Ở đây chúng ta sẽ tạo một robot 5-DoF đơn giản với một camera. Nó có thể là một cánh tay đơn giản, nhưng hãy lưu ý rằng lớp trừu tượng Robot không giả định bất kỳ điều gì về hình dạng của robot của bạn. Bạn có thể để trí tưởng tượng bay bổng khi thiết kế các robot mới!

from typing import Any

from lerobot.cameras import make_cameras_from_configs
from lerobot.motors import Motor, MotorCalibration, MotorNormMode, SerialMotorsBus
from lerobot.robots import Robot

class MyCoolRobot(Robot):
    config_class = MyCoolRobotConfig
    name = "my_cool_robot"

    def __init__(self, config: MyCoolRobotConfig):
        super().__init__(config)
        self.config = config
        self.bus = SerialMotorsBus(
            port=self.config.port,
            motors={
                "joint_1": Motor(1, "sts3250", MotorNormMode.RANGE_M100_100),
                "joint_2": Motor(2, "sts3215", MotorNormMode.RANGE_M100_100),
                "joint_3": Motor(3, "sts3215", MotorNormMode.RANGE_M100_100),
                "joint_4": Motor(4, "sts3215", MotorNormMode.RANGE_M100_100),
                "joint_5": Motor(5, "sts3215", MotorNormMode.RANGE_M100_100),
            },
            calibration=self.calibration,
        )
        self.cameras = make_cameras_from_configs(config.cameras)

Bước 2: Định nghĩa các đặc trưng quan sát và hành động

Hai thuộc tính này xác định khế ước giao diện giữa robot của bạn và các công cụ sử dụng nó (chẳng hạn như các pipeline thu thập dữ liệu hoặc học tập).

Lưu ý rằng các thuộc tính này phải có thể gọi được ngay cả khi robot chưa được kết nối, do đó hãy tránh dựa vào trạng thái phần cứng thời gian chạy để định nghĩa chúng.

observation_features

Thuộc tính này nên trả về một từ điển mô tả cấu trúc của các đầu ra cảm biến từ robot của bạn. Các khóa khớp với những gì get_observation() trả về, và các giá trị mô tả hình dạng (cho mảng/ảnh) hoặc kiểu (cho các giá trị đơn giản).

Ví dụ cho cánh tay 5-DoF của chúng ta với một camera:

@property
def _motors_ft(self) -> dict[str, type]:
    return {
        "joint_1.pos": float,
        "joint_2.pos": float,
        "joint_3.pos": float,
        "joint_4.pos": float,
        "joint_5.pos": float,
    }

@property
def _cameras_ft(self) -> dict[str, tuple]:
    return {
        cam: (self.cameras[cam].height, self.cameras[cam].width, 3) for cam in self.cameras
    }

@property
def observation_features(self) -> dict:
    return {**self._motors_ft, **self._cameras_ft}

Trong trường hợp này, các quan sát bao gồm một dict đơn giản lưu trữ vị trí của mỗi động cơ và một hình ảnh từ camera.

action_features

Thuộc tính này mô tả các lệnh mà robot của bạn kỳ vọng nhận được qua send_action(). Một lần nữa, các khóa phải khớp với định dạng đầu vào mong đợi, và các giá trị xác định hình dạng/kiểu của từng lệnh.

Ở đây, chúng ta đơn giản sử dụng các đặc trưng cảm nhận vị trí khớp (self._motors_ft) giống như với observation_features: hành động được gửi đi sẽ đơn giản là vị trí đích cho mỗi động cơ.

@property
def action_features(self) -> dict:
    return self._motors_ft

Bước 3: Xử lý kết nối và ngắt kết nối

Các phương thức này nên xử lý việc mở và đóng kết nối giao tiếp với phần cứng của bạn (ví dụ: cổng serial, giao diện CAN, thiết bị USB, camera).

is_connected

Thuộc tính này đơn giản chỉ nên phản ánh việc kết nối với phần cứng của robot đã được thiết lập. Khi thuộc tính này là True, bạn nên có thể đọc và ghi vào phần cứng bằng cách sử dụng get_observation() và send_action().

@property
def is_connected(self) -> bool:
    return self.bus.is_connected and all(cam.is_connected for cam in self.cameras.values())

connect()

Phương thức này nên thiết lập kết nối với phần cứng. Hơn nữa, nếu robot của bạn cần hiệu chuẩn và chưa được hiệu chuẩn, nó nên bắt đầu quy trình hiệu chuẩn theo mặc định. Nếu robot của bạn cần một số cấu hình cụ thể, các cấu hình này cũng nên được gọi tại đây.

def connect(self, calibrate: bool = True) -> None:
    self.bus.connect()
    if not self.is_calibrated and calibrate:
        self.calibrate()

    for cam in self.cameras.values():
        cam.connect()

    self.configure()

disconnect()

Phương thức này nên kết thúc giao tiếp với phần cứng một cách êm đẹp: giải phóng mọi tài nguyên liên quan (các luồng hoặc tiến trình), đóng các cổng, v.v.

Ở đây, chúng ta đã xử lý điều này trong các lớp SerialMotorsBus và Camera của mình, vì vậy chúng ta chỉ cần gọi phương thức disconnect() của chúng:

def disconnect(self) -> None:
    self.bus.disconnect()
    for cam in self.cameras.values():
        cam.disconnect()

Bước 4: Hỗ trợ hiệu chuẩn và cấu hình

LeRobot hỗ trợ tự động lưu và nạp dữ liệu hiệu chuẩn. Điều này hữu ích cho các độ lệch khớp, vị trí zero hoặc căn chỉnh cảm biến.

Lưu ý rằng tùy thuộc vào phần cứng của bạn, điều này có thể không áp dụng. Nếu đúng như vậy, bạn có thể đơn giản để các phương thức này ở dạng no-op:

@property
def is_calibrated(self) -> bool:
    return True

def calibrate(self) -> None:
    pass

is_calibrated

Điều này nên phản ánh xem robot của bạn đã được nạp hiệu chuẩn cần thiết hay chưa.

@property
def is_calibrated(self) -> bool:
    return self.bus.is_calibrated

calibrate()

Mục tiêu của việc hiệu chuẩn là kép:

  • Hiểu được phạm vi chuyển động vật lý của từng động cơ để chỉ gửi các lệnh nằm trong phạm vi này.
  • Chuẩn hóa các vị trí động cơ thô thành các giá trị liên tục hợp lý (ví dụ: phần trăm, độ) thay vì các giá trị rời rạc tùy ý phụ thuộc vào động cơ cụ thể được sử dụng, vốn sẽ không thể tái lập ở nơi khác.

Nó nên triển khai logic cho việc hiệu chuẩn (nếu liên quan) và cập nhật từ điển self.calibration. Nếu bạn đang sử dụng động cơ Feetech hoặc Dynamixel, SerialMotorsBus đã thực hiện hiệu chuẩn thủ công:

  1. _keep_calibration_file() cho phép bạn tái sử dụng tệp hiệu chuẩn của id này. Nếu bạn giữ lại, tệp sẽ được ghi vào các động cơ và quá trình hiệu chuẩn kết thúc tại đó.
  2. record_calibration() giải phóng các động cơ và đặt chúng vào chế độ hoạt động mà bạn chỉ định.
  3. Nó yêu cầu bạn giữ các khớp ở giữa phạm vi chuyển động: tư thế đó sẽ tương ứng với nửa vòng quay của mỗi động cơ.
  4. Nó ghi lại phạm vi của từng khớp khi bạn di chuyển chúng, cho đến khi bạn nhấn ENTER. Các khớp xoay liên tục sẽ được đưa vào full_turn_motors và nhận toàn bộ phạm vi encoder thay vào đó; cánh tay 5-DoF của chúng tôi không có khớp nào như vậy.
  5. write_calibration() ghi kết quả vào các động cơ, và _save_calibration() lưu nó vào tệp hiệu chuẩn.
def calibrate(self) -> None:
    if self._keep_calibration_file(self.bus):
        return

    self.calibration = self.bus.record_calibration("position", full_turn_motors=[])
    self.bus.write_calibration(self.calibration)
    self._save_calibration()
    print("Calibration saved to", self.calibration_fpath)

configure()

Sử dụng điều này để thiết lập bất kỳ cấu hình nào cho phần cứng của bạn (chế độ điều khiển servo, hệ số bộ điều khiển, v.v.). Việc này thường nên được thực hiện khi kết nối và phải có tính chất idempotent.

def configure(self) -> None:
    with self.bus.torque_disabled():
        self.bus.configure_motors()
        for motor in self.bus.motors:
            self.bus.set_operating_mode("position", motor)
            self.bus.write("P_Coefficient", motor, 16)
            self.bus.write("I_Coefficient", motor, 0)
            self.bus.write("D_Coefficient", motor, 32)

Bước 5: Triển khai đọc cảm biến và gửi hành động

Đây là các hàm thời gian chạy quan trọng nhất: vòng lặp I/O cốt lõi.

get_observation()

Trả về một từ điển chứa các giá trị cảm biến từ robot. Những giá trị này thường bao gồm trạng thái động cơ, khung hình từ camera, các cảm biến khác nhau, v.v. Trong framework LeRobot, các quan sát này sẽ được đưa vào một policy để dự đoán các hành động cần thực hiện. Các khóa và cấu trúc của từ điển phải khớp với observation_features.

def get_observation(self) -> dict[str, Any]:
    if not self.is_connected:
        raise ConnectionError(f"{self} is not connected.")

    # Read arm position
    obs_dict = self.bus.sync_read("Present_Position")
    obs_dict = {f"{motor}.pos": val for motor, val in obs_dict.items()}

    # Capture images from cameras
    for cam_key, cam in self.cameras.items():
        obs_dict[cam_key] = cam.async_read()

    return obs_dict

send_action()

Nhận một từ điển khớp với action_features và gửi nó đến phần cứng của bạn. Bạn có thể thêm các giới hạn an toàn (cắt, làm mượt) và trả về những gì thực sự đã được gửi.

Để đơn giản, chúng ta sẽ không thêm bất kỳ sự thay đổi nào cho các hành động trong ví dụ ở đây.

def send_action(self, action: dict[str, Any]) -> dict[str, Any]:
    goal_pos = {key.removesuffix(".pos"): val for key, val in action.items()}

    # Send goal position to the arm
    self.bus.sync_write("Goal_Position", goal_pos)

    return action

Chờ giữa các lần dự đoán

Chế độ RTC cục bộ thông thường vẫn có thể sử dụng mà không cần khả năng robot mới. Việc triển khai từ xa, các khoảng dừng ngôn ngữ bất đồng bộ theo kế hoạch và tình trạng thiếu hành động có thể phục hồi đòi hỏi một thỏa thuận chờ giữ mục tiêu. Chỉ bật tùy chọn này bằng supports_position_hold = True khi việc làm mới mọi trường hành động thông qua send_action() là an toàn cho bộ điều khiển. Thông thường, các trường đó là các mục tiêu vị trí thực tế. Một bộ điều khiển có thể chọn tham gia bằng một lệnh giữ đã được xác thực riêng biệt, chẳng hạn như token chuyển động tiềm ẩn của SONIC, khi việc lặp lại nó giúp bộ điều khiển trên thiết bị duy trì thăng bằng. Việc bật mô-men xoắn hoặc chỉ có hậu tố .pos không đủ để thiết lập điều này; các lệnh vận tốc/lực và di chuyển vẫn không phù hợp.

Cài đặt rollout dùng chung làm mới hành động hữu hạn hoàn chỉnh cuối cùng được trả về bởi send_action(), bao gồm cả kẹp và bất kỳ việc cắt (clipping) nào của driver. Hãy trả về đích (target) thực tế đã được áp dụng, chứ không phải yêu cầu gốc, khi driver của bạn sửa đổi nó. Các bản cập nhật quan sát (observation) tiếp theo sẽ không thay thế đích đó. Trước khi bất kỳ lệnh nào được áp dụng, một bản chụp (snapshot) vị trí đo đã được xác thực sẽ khởi tạo nó. Robot có thể ổn định dần về phía đích được giữ lại; hợp đồng này dừng việc tiến triển quỹ đạo (trajectory) chứ không đảm bảo dừng vật lý tức thời. Hãy xác minh hỗ trợ tải, khả năng kẹp và hành vi làm mới lệnh trên phần cứng cho mỗi triển khai.

Khi tính năng giữ (holding) được bật, các bộ xử lý hành động tùy chỉnh và các điều chỉnh điều khiển từ xa phải duy trì lệnh vị trí hoàn chỉnh, bao gồm cả kẹp (gripper). Trình điều khiển phải trả về mọi thành phần hành động với các giá trị áp dụng hữu hạn. Việc trả về không hoàn chỉnh/không hợp lệ là sự vi phạm hợp đồng sau khi lệnh được áp dụng: quá trình rollout sẽ dừng lại và ngăn chặn việc đưa về vị trí gốc (homing) thay vì tái sử dụng một mục tiêu cũ. Các lỗi lệnh cũng ngăn chặn việc đưa về vị trí gốc trong quá trình rollout đồng bộ.

Remote rollout tự động kiểm tra khả năng của driver này; không cần cờ CLI chế độ giữ bổ sung. Các lỗi quan sát chung sử dụng đường dẫn dọn dẹp rollout thông thường. Việc quay lại vị trí ban đầu vẫn cần một quan sát hoàn chỉnh và có thể thất bại nếu một camera vẫn không khả dụng.

Triển khai robotHỗ trợ chờ theo vị trí đích
SO followers (SO-100/SO-101), OMX, KochĐược hỗ trợ.
HopeJr cánh tay và bàn tayĐược hỗ trợ.
Rebot B601Được hỗ trợ trên các chế độ cánh tay/kẹp tuyệt đối hiện có.
YAMĐược hỗ trợ. Nếu không có lệnh nào đến trong command_timeout_s, cánh tay sẽ giữ nguyên vị trí hoặc lơ lửng, tùy theo cài đặt của idle_mode.
OpenArmĐược hỗ trợ với use_velocity_and_torque=false; các schema hành động hỗn hợp bị loại trừ.
BiSO, BiOpenArm, BiRebot B601, BiYAMĐược hỗ trợ khi cả hai nhánh cơ bản đều hỗ trợ; các mục tiêu được áp dụng của chúng giữ nguyên tiền tố trái/phải.
Reachy2Chỉ được hỗ trợ với with_mobile_base=false, use_external_commands=false và max_relative_target=null. Lệnh mobile-base là vận tốc, chế độ bên ngoài không truyền các mục tiêu, và đường dẫn cắt hiện tại trả về giá trị gốc thay vì giá trị đã áp dụng.
LeKiwi (bao gồm client mạng), EarthRover Mini PlusKhông hỗ trợ: các hành động bao gồm vận tốc cơ sở di động, không thể được giữ lại như các mục tiêu vị trí.
Unitree G1Chỉ được hỗ trợ với SonicWholeBodyController: lệnh chờ sẽ lặp lại token chuyển động 64-D hoàn chỉnh cuối trong khi bộ giải mã trên thiết bị tiếp tục cân bằng. Locomotion của GR00T/Holosoma và điều khiển .q thô vẫn chưa được hỗ trợ.

Các khai báo này phản ánh hợp đồng lệnh của trình điều khiển, không phải việc xác thực vật lý cho mọi biến thể hoặc cấu hình bộ điều khiển. Mặc định chung của Robot vẫn là false. Các kiểm tra khả năng không xác lập tính tương thích checkpoint, hiệu chỉnh bộ điều khiển, hỗ trợ tải hoặc tình trạng phần cứng.

Thêm một Teleoperator

Để triển khai các thiết bị điều khiển từ xa, chúng tôi cũng cung cấp lớp cơ sở Teleoperator. Lớp này rất giống với lớp cơ sở Robot và cũng không giả định bất kỳ điều gì về hình dạng thiết bị.

Các điểm khác biệt chính nằm ở các hàm I/O: một teleoperator cho phép bạn tạo ra hành động thông qua get_action và có thể nhận các hành động phản hồi thông qua send_feedback. Phản hồi có thể là bất kỳ thứ gì có thể điều khiển được trên thiết bị teleoperation, giúp người điều khiển hiểu được hậu quả của các hành động đã gửi đi. Ví dụ như phản hồi chuyển động/lực trên cánh tay dẫn động, hoặc rung trên tay cầm game. Để triển khai một teleoperator, bạn có thể làm theo hướng dẫn này và điều chỉnh cho phù hợp với hai phương thức trên.

Sử dụng Thiết bị LeRobot Của Bạn 🔌

Bạn có thể dễ dàng mở rộng lerobot với phần cứng tùy chỉnh của riêng mình—dù là camera, robot hay thiết bị teleoperation—bằng cách tạo một gói Python riêng biệt, có thể cài đặt được. Nếu bạn tuân theo một vài quy ước đơn giản, các công cụ dòng lệnh của lerobot (như lerobot-teleoperate và lerobot-record) sẽ tự động phát hiện và tích hợp các sáng tạo của bạn mà không cần bất kỳ thay đổi nào đối với mã nguồn lerobot.

Hướng dẫn này nêu bật các quy ước mà plugin của bạn phải tuân theo.

4 Quy ước cốt lõi

Để đảm bảo thiết bị tùy chỉnh của bạn có thể được phát hiện, bạn phải tuân thủ bốn quy tắc sau.

1 . Tạo một Gói Cài Đặt Có Tiền Tụ Cụ Thể

Dự án của bạn phải là một gói Python chuẩn, có thể cài đặt được. Quan trọng là tên gói của bạn (được định nghĩa trong pyproject.toml hoặc setup.py) phải bắt đầu bằng một trong các tiền tố sau:

  • lerobot_robot_ cho một robot.
  • lerobot_camera_ cho một camera.
  • lerobot_teleoperator_ cho thiết bị điều khiển từ xa.
  • lerobot_strategy_ cho chiến lược lerobot-rollout (xem Mang chiến lược của riêng bạn).

Hệ thống tiền tố này là cách lerobot tự động tìm thấy plugin của bạn trong môi trường Python.

2 . Tuân theo Mẫu Đặt Tên SomethingConfig / Something

Lớp triển khai của thiết bị của bạn phải được đặt tên theo lớp cấu hình của nó, chỉ cần bỏ hậu tố Config.

  • Lớp cấu hình: MyAwesomeTeleopConfig
  • Lớp thiết bị: MyAwesomeTeleop

3. Đặt tệp của bạn trong một cấu trúc dễ dự đoán

Lớp thiết bị (MyAwesomeTeleop) phải nằm trong một module có thể dự đoán được so với lớp cấu hình của nó (MyAwesomeTeleopConfig). lerobot sẽ tự động tìm kiếm tại các vị trí sau:

  • Trong cùng module với lớp config.
  • Trong một submodule được đặt tên theo thiết bị (ví dụ: my_awesome_teleop.py).

Cấu trúc được khuyến nghị và đơn giản nhất là đặt chúng trong các tệp riêng biệt, có tên rõ ràng, cùng nằm trong một thư mục.

4 . Công khai các lớp trong __init__.py

Tệp __init__.py của gói của bạn nên import và expose cả lớp configuration lẫn lớp device, giúp chúng dễ dàng truy cập.

Kết hợp tất cả: Một ví dụ hoàn chỉnh

Hãy tạo một teleoperator mới có tên là my_awesome_teleop.

Cấu trúc thư mục

Dưới đây là cách thư mục dự án nên trông như thế nào. Tên gói, lerobot_teleoperator_my_awesome_teleop, tuân theo Quy ước #1.

lerobot_teleoperator_my_awesome_teleop/
├── pyproject.toml # (or setup.py) lists lerobot as a dependency
└── lerobot_teleoperator_my_awesome_teleop/
    ├── __init__.py
    ├── config_my_awesome_teleop.py
    └── my_awesome_teleop.py

Nội dung tệp

  • config_my_awesome_teleop.py: Định nghĩa lớp cấu hình. Lưu ý hậu tố Config (Quy ước #2).

    from dataclasses import dataclass
    
    from lerobot.teleoperators.config import TeleoperatorConfig
    
    @TeleoperatorConfig.register_subclass("my_awesome_teleop")
    @dataclass
    class MyAwesomeTeleopConfig(TeleoperatorConfig):
        # Your configuration fields go here
        port: str = "192.168.1.1"
  • my_awesome_teleop.py: Triển khai thiết bị. Tên lớp MyAwesomeTeleop khớp với tên lớp cấu hình của nó (Quy ước #2). Cấu trúc tệp này tuân thủ Quy ước #3.

    from lerobot.teleoperators.teleoperator import Teleoperator
    
    from .config_my_awesome_teleop import MyAwesomeTeleopConfig
    
    class MyAwesomeTeleop(Teleoperator):
        config_class = MyAwesomeTeleopConfig
        name = "my_awesome_teleop"
    
        def __init__(self, config: MyAwesomeTeleopConfig):
            super().__init__(config)
            self.config = config
    
        # Your device logic (e.g., connect) goes here
  • __init__.py: Công bố các lớp chính (Quy ước #4).

    from .config_my_awesome_teleop import MyAwesomeTeleopConfig
    from .my_awesome_teleop import MyAwesomeTeleop

Cài đặt và Sử dụng

  1. Cài đặt plugin mới của bạn trong môi trường Python. Bạn có thể cài đặt gói plugin cục bộ của mình bằng chế độ chỉnh sửa của pip hoặc từ PyPi.

    # Locally
    # Navigate to your plugin's root directory and install it
    cd lerobot_teleoperator_my_awesome_teleop
    pip install -e .
    
    # From PyPi
    pip install lerobot_teleoperator_my_awesome_teleop
  2. Sử dụng trực tiếp từ dòng lệnh. Bây giờ, bạn có thể sử dụng thiết bị tùy chỉnh của mình bằng cách tham chiếu đến kiểu của nó.

    # Add the other arguments you need (robot type, ports, ids, ...)
    lerobot-teleoperate --teleop.type=my_awesome_teleop ...

Và như vậy là xong! Thiết bị tùy chỉnh của bạn giờ đã được tích hợp hoàn toàn.

Bạn đang tìm một ví dụ?

Cộng đồng duy trì hàng chục plugin được xây dựng theo cách này. Duyệt qua Third-Party Robots & Teleoperators và Third-Party Cameras & Sensors để tìm một plugin phù hợp với phần cứng của bạn, hoặc bắt đầu từ hai gói nhỏ này:

Tổng kết

Khi lớp robot của bạn đã hoàn tất, bạn có thể tận dụng hệ sinh thái LeRobot:

  • Điều khiển robot của bạn bằng các thiết bị teleoperator có sẵn hoặc tích hợp trực tiếp thiết bị teleoperating của bạn
  • Ghi lại dữ liệu huấn luyện và trực quan hóa
  • Tích hợp nó vào các quy trình học tăng cường hoặc học bắt chước

Sau khi plugin của bạn được phát hành, hãy mở một PR để thêm nó vào Third-Party Robots & Teleoperators hoặc Third-Party Cameras & Sensors để người dùng khác có thể tìm thấy.

Đừng ngần ngại liên hệ với cộng đồng để được hỗ trợ trên Discord của chúng tôi 🤗

Update on GitHub