# Kendi Donanımınızı Getirin

Bu eğitim, kendi robot tasarımınızı LeRobot ekosistemine nasıl entegre edebileceğinizi ve tüm araçlarımıza (veri toplama, kontrol hatları, politika eğitimi ve çıkarım) nasıl erişim sağlayabileceğinizi açıklayacaktır.

Bu amaçla, LeRobot'ta fiziksel robot entegrasyonu için standart bir arayüz belirleyen [`Robot`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/robots/robot.py) temel sınıfını sunuyoruz. Nasıl uygulanacağını görelim.

## Ön koşullar

- Bir iletişim arayüzü (ör. seri, CAN, TCP) sunan kendi robotunuz
- Sensör verilerini okumak ve motor komutlarını programatik olarak göndermenin bir yolu, örneğin üreticinin SDK'sı veya API'si veya kendi protokol uygulamanız.
- LeRobot, ortamınıza yüklendi. [Kurulum Kılavuzumuza](./installation) göz atın.

## Motorlarınızı seçin

Feetech veya Dynamixel motorları kullanıyorsanız, LeRobot her iki aileyi de sürdüren yerleşik bir bus arayüzü olan [`SerialMotorsBus`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/motors/motors_bus.py) sağlar; her motorun modeli, hangi aileye ait olduğunu belirtir. API'si hakkında bilgi edinmek için buna başvurun. Bu bileşen, rustypot'u kuran `serial-motors` ek paketine ihtiyaç duyar: `pip install 'lerobot[serial-motors]'` veya kaynak kodundan `pip install -e ".[serial-motors]"` çalıştırın. Nasıl kullanılabileceğine dair iyi bir örnek için kendi [SO101 takipçi uygulamasımıza](https://github.com/huggingface/lerobot/blob/main/src/lerobot/robots/so_follower/so_follower.py) göz atabilirsiniz.

Uygun olmaları durumunda bunları kullanın. Aksi takdirde, bir Python arayüzü bulmanız veya yazmanız gerekecektir (bu konuda bu öğreticide bilgi verilmez):

- Python'da mevcut bir SDK bulun (veya C/C++ bağlamaları kullanın)
- veya temel bir iletişim sarmalayıcı uygulayın (ör. pyserial, socket veya CANopen üzerinden)

Yalnız değilsiniz—topluluk katkılarının çoğu özel kartlar veya yazılımlar kullanıyor!

Feetech ve Dynamixel için şu an şu servo motorları destekliyoruz:

- Feetech STS & SMS serisi: `sts3215`, `sts3250`, `sm8512bl`
- Feetech SCS serisi: `scs0009`
- Dynamixel X serisi (protokol 2.0): `xl330-m077`, `xl330-m288`, `xc330-t181`, `xc330-t288`, `xl430-w250`, `xl430-w250-2`, `xc430-w150`, `xm430-w350`, `xm540-w270`, `xh540-w150`

Modeller bir bus, STS/SMS ve SCS servo veya XL430 ve XL330 paylaşabilir: her motor, kendi modelinin tanımı, bayt sırası ve işaret kodlaması dahil olmak üzere, kendi modelinin tanımı üzerinden okunur ve yazılır. Aileler arasındaki farklar aynı tanımlardan kaynaklanır: hangi çalışma modu değeri konum kontrolü anlamına gelir (`bus.set_operating_mode("position")`), homing offset konuma eklenir mi yoksa ondan çıkar mı, hangi kayıtların mevcut olduğu.

Bir modeli desteklemek, her kalibrasyon yardımcısının o modelde çalıştığı anlamına gelmez: Feetech SCS0009'un ne bir çalışma modu ne de bir homing ofseti vardır, bu nedenle `set_operating_mode()` ve `set_half_turn_homings()` bu modeli reddeder. Aşağıdaki kalibrasyon tarifi, STS gibi her iki özelliğe de sahip olan servo motorlar içindir; bir SCS servo motoru yalnızca aralığıyla kalibre edilir.

Bu listede yer almayan Feetech veya Dynamixel servo kullanıyorsanız, onları [rustypot](https://github.com/pollen-robotics/rustypot) paketine ekleyin; bu paket, busların okuduğu kontrol tablolarını barındırır: mevcut bir kontrol tablosuyla ortaklaşan bir model için yalnızca model numarasının kaydedilmesi yeterlidir, yeni bir model için ise servo tanımı gereklidir ([servo katkı rehberi](https://github.com/pollen-robotics/rustypot/blob/v1.13.1/src/servo/README.md)’ne bakın). LeRobot, modelleri kurulu rustypot Python paketinden okuduğu için, bu paket yeni modeli içermelidir: bunu içeren bir rustypot sürümü veya kaynak kodundan derlenmiş rustypot.

Sonraki bölümlerde örnekler Feetech motorlarını kullanır. Gerekirse modelleri değiştirin ve motorlarınıza göre uyarlayın.

## Adım 1: `Robot` Arayüzünü Alt Sınıflandırın

Önce robotunuz için yapılandırma sınıfını ve bir dizi tanımlayıcıyı (`name`) belirtmeniz gerekir. Robotunuzun, kolayca değiştirmek istediğiniz özel gereksinimleri varsa (ör. port/adres, baudrate) bunlar buraya yazılmalıdır.

Burada, robotumuz için varsayılan olarak port adını ve bir kamerayı ekleyeceğiz:

```python
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,
            ),
        }
    )
```

Kameranızı nasıl algılayıp ekleyeceğinizi anlamak için [Kameralar öğreticisi](./cameras).

Ardından, `Robot` sınıfından türeyen gerçek robot sınıfımızı oluşturacağız. Bu soyut sınıf, robotunuzun LeRobot araçlarının geri kalanıyla kullanılabilir olması için uyması gereken bir sözleşme tanımlar.

Burada tek bir kameraya sahip basit bir 5-DoF robot oluşturacağız. Bu basit bir kol olabilir ancak `Robot` soyut sınıfının robotunuzun form faktörü hakkında hiçbir varsayım yapmadığına dikkat edin. Yeni robotlar tasarlarken hayal gücünüzü sınırsızca kullanabilirsiniz!

```python
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)
```

## Adım 2: Gözlem ve Eylem Özelliklerini Tanımlayın

Bu iki özellik, robotunuz ile onu kullanan araçlar (veri toplama veya öğrenme hatları gibi) arasındaki _arayüz sözleşmesini_ tanımlar.

> [!WARNING]
> Bu özelliklerin robot henüz bağlı olmasa bile çağrılabilir olması gerektiğini unutmayın; bu nedenle tanımlarken çalışma zamanı donanım durumuna güvenmekten kaçının.

### `observation_features`

Bu özellik, robotunuzun sensör çıktılarındaki yapıyı açıklayan bir sözlük döndürmelidir. Anahtarlar, `get_observation()` tarafından döndürülenlerle eşleşir ve değerler, diziler/görseller için şekli (shape) veya basit değerler için tipi (type) açıklar.

Bir kameraya sahip 5-DoF kolumuz için örnek:

```python
@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}
```

Bu durumda, gözlemler her motorun konumunu ve bir kamera görüntüsünü saklayan basit bir sözlükten oluşur.

### `action_features`

Bu özellik, robotunuzun `send_action()` üzerinden beklediği komutları tanımlar. Yine anahtarlar, beklenen giriş biçimiyle eşleşmeli ve değerler her komutun biçimini/tipini belirlemelidir.

Burada, `observation_features` ile aynı eklem proprioseptif özelliklerini (`self._motors_ft`) kullanırız: gönderilen eylem, her motor için hedef konum olacaktır.

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

## Adım 3: Bağlantı ve Bağlantı Kesme İşlemlerini Yönetme

Bu yöntemler, donanımınızla (ör. seri portlar, CAN arayüzleri, USB cihazları, kameralar) iletişim kurma ve kapatma işlemlerini ele almalıdır.

### `is_connected`

Bu özellik, robotun donanımıyla iletişimin kurulduğunu yansıtmalıdır. Bu özellik `True` olduğunda, `get_observation()` ve `send_action()` kullanılarak donanıma okuma ve yazma yapılabilmesi gerekir.

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

### `connect()`

Bu yöntem, donanım ile iletişim kurmalıdır. Ayrıca, robotunuz kalibrasyon gerektiriyorsa ve henüz kalibre edilmemişse, varsayılan olarak bir kalibrasyon prosedürü başlatmalıdır. Robotunuz belirli bir yapılandırma gerektiriyorsa, bu da burada çağrılmalıdır.

```python
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()`

Bu yöntem, donanım ile iletişimi zarif bir şekilde sonlandırmalıdır: ilgili tüm kaynakları (iş parçacıkları veya süreçler) serbest bırakmalı, portları kapatmalı vb.

Burada bunu zaten `SerialMotorsBus` ve `Camera` sınıflarımızda ele alıyoruz, bu yüzden yalnızca kendi `disconnect()` yöntemlerini çağırmamız gerekiyor:

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

## Adım 4: Kalibrasyon ve Yapılandırmayı Destekleme

LeRobot, kalibrasyon verilerinin otomatik olarak kaydedilip yüklenmesini destekler. Bu, ek ofsetleri, sıfır konumları veya sensör hizalaması için faydalıdır.

> Donanımınıza bağlı olarak bu durum geçerli olmayabilir. Bu durumda, bu yöntemleri basitçe no-op olarak bırakabilirsiniz:

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

def calibrate(self) -> None:
    pass
```

### `is_calibrated`

Bu, robotunuzun gerekli kalibrasyonun yüklü olup olmadığını yansıtmalıdır.

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

### `calibrate()`

Kalibrasyonun amacı ikilidir:

- Sadece bu aralık içinde komut göndermek için her bir motorun fiziksel hareket aralığını bilin.
- Ham motor konumlarını, kullanımdaki spesifik motora bağlı ve başka yerlerde tekrarlanamayacak keyfi ayrık değerler yerine, makul sürekli değerlere (ör. yüzde, derece) normalize edin.

Kalibrasyon mantığını (ilgiliyse) uygulaması ve `self.calibration` sözlüğünü güncellemesi gerekir. Feetech veya Dynamixel motorları kullanıyorsanız, `SerialMotorsBus` zaten kalibrasyonu elle çalıştırır:

1. `_keep_calibration_file()`, bu kimliğe ait kalibrasyon dosyasının yeniden kullanılmasını önerir. Dosyayı korursanız, motorlara yazılır ve kalibrasyon burada sona erer.
2. `record_calibration()` motorları serbest bırakır ve onları verdiğiniz çalışma moduna alır.
3. Motorların hareket aralığının ortasında eklem noktalarını tutmanızı ister: bu poz, her motor için yarım dönüşe karşılık gelir.
4. Her eklemi hareket ettirdikçe, ENTER tuşuna basana kadar eklem aralıklarını kaydeder. Sonsuza kadar dönen eklemler `full_turn_motors` içine alınır ve bunun yerine tüm kodlayıcı aralığını alır; 5-DoF kolumuzda böyle eklemler yoktur.
5. `write_calibration()` sonucu motorlara yazar ve `_save_calibration()` onu kalibrasyon dosyasına kaydeder.

```python
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()`

Donanımınız için herhangi bir yapılandırma (servo kontrol modları, denetleyici kazançları vb.) ayarlamak için bunu kullanın. Bu, genellikle bağlantı sırasında çalıştırılmalı ve idempotent olmalıdır.

```python
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)
```

## Adım 5: Sensör Okuma ve Eylem Gönderme Uygulaması

Bunlar en önemli çalışma zamanı işlevleridir: çekirdek G/D döngüsü.

### `get_observation()`

Robottan sensör değerlerinin sözlüğünü döndürür. Bunlar genellikle motor durumları, kamera kareleri, çeşitli sensörler vb. içerir. LeRobot çerçevesinde, bu gözlemler, alınacak eylemleri tahmin etmek için bir politika (policy) girdisi olarak kullanılır. Sözlük anahtarları ve yapısı `observation_features` ile eşleşmelidir.

```python
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()`

`action_features` ile eşleşen bir sözlük alır ve donanımınıza gönderir. Güvenlik sınırları (kırpma, yumuşatma) ekleyebilir ve aslında gönderileni döndürebilirsiniz.

Basitlik adına, örneklerimizde eylemlerin herhangi bir şekilde değiştirilmesini eklemeyeceğiz.

```python
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
```

### Tahminler arasında bekleme

Sıradan yerel RTC, yeni bir robot yeteneği olmadan kullanılabilir durumda kalır. Uzak dağıtım, planlanan asenkron dil duraklamaları ve kurtarılabilir eylem açlığı, tutulan hedef bekleme sözleşmesini gerektirir. Yalnızca `send_action()` üzerinden her eylem alanını yenilemenin denetleyici için güvenli olduğu durumlarda `supports_position_hold = True` ile katılın. Genellikle bu alanlar gerçek konum hedefleridir. Bir denetleyici, tekrarlandığında araç üzerindeki denetleyicinin dengesini koruduğu durumlarda, örneğin SONIC'in gizli hareket jetonu gibi ayrı olarak doğrulanmış tutulan bir komutla katılabilir. Tork etkinleştirme veya yalnızca `.pos` eki bunu sağlamaz; hız/güç ve hareket komutları hâlâ uygun değildir.

`send_action()` gibi yalnızca bir komut gönderildiğinde ilerleyen bir simülatör gibi, yeniden bir komut gelmeden bekleme yeteneğine sahip bir robot, `supports_command_hold = True` değerini ayarlar ve `hold()` işlevini uygular. Bu, konum tutma yerine kullanılır.

Ortak rollout uygulaması, `send_action()` tarafından döndürülen son tam ve sonlu eylemi, kavrayıcıyı ve sürücü kırpma işlemlerini de kapsayacak şekilde yeniler. Sürücünüz eylemi değiştirdiğinde, orijinal isteği değil, fiilen uygulanan hedefi döndürün. Sonraki gözlem güncellemeleri bu hedefi değiştirmez. Herhangi bir komut uygulanmadan önce, doğrulanmış bir ölçülen konum anlık görüntüsü bunu başlatır. Robot, korunan hedefine doğru yerleşebilir; bu sözleşme anlık bir fiziksel durmayı garanti etmek yerine yörünge ilerlemesini durdurur. Her dağıtım için yük desteğini, kavramayı ve komut yenileme davranışını donanımda doğrulayın.

Holding etkin olduğunda, özel işlemci aksiyonları ve teleoperation düzeltmeleri, gripper dahil olmak üzere tam bir konum komutunu korumak zorundadır. Sürücü, her aksiyon bileşenini sonlu uygulanmış değerlerle döndürmelidir. Eksik/geçersiz bir dönüş, komut uygulandıktan sonra bir sözleşme ihlalidir: rollout durur ve eski bir hedefi yeniden kullanmak yerine homing'i bastırır. Komut hataları, senkron rollout'ta da homing'i bastırır.

Remote rollout, bu sürücü yeteneğini otomatik olarak kontrol eder; ek bir tutma modu CLI bayrağı gerekmez. Genel gözlem hataları, normal rollout temizleme yolunu kullanır. Başlangıç konumuna dönmek yine de tam bir gözlem gerektirir ve bir kamera kullanılamaz durumda kalırsa başarısız olabilir.

| Robot uygulaması                                    | Konum-hedef bekleme desteği                                                                                                                                                                                                                                            |
| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SO takipçileri (SO-100/SO-101), OMX, Koch                 | Desteklenir.                                                                                                                                                                                                                                                                 |
| HopeJr kol ve el                                     | Desteklenir.                                                                                                                                                                                                                                                                 |
| Rebot B601                                              | Mevcut mutlak konum kolu/tutucu modları arasında desteklenir.                                                                                                                                                                                                         |
| YAM                                                     | Desteklenir. `command_timeout_s` süresince herhangi bir komut gelmezse, kol `idle_mode` ayarına göre konumunu korur veya havada asılı kalır.                                                                                                                                                     |
| OpenArm                                                 | `use_velocity_and_torque=false` ile desteklenir; karma eylem şemaları hariç tutulur.                                                                                                                                                                                         |
| BiSO, BiOpenArm, BiRebot B601, BiYAM                    | Her iki alt kol bunu desteklediğinde desteklenir; uygulanan hedefler sol/sağ öneklerini korur.                                                                                                                                                                      |
| Reachy2                                                 | Yalnızca `with_mobile_base=false`, `use_external_commands=false` ve `max_relative_target=null` ile desteklenir. Mobile-base komutları hızlardır, dış mod hedefleri iletmek yerine kullanılır ve kırpma yolu şu anda uygulanan değerler yerine orijinal değerleri döndürür. |
| LeKiwi (ağ istemcisi dahil), EarthRover Mini Plus | Desteklenmiyor: eylemler, konum hedefleri olarak korunamayan mobil-taban hızlarını içerir.                                                                                                                                                                         |
| Unitree G1                                              | Yalnızca `SonicWholeBodyController` ile desteklenir: waiting, yerleşik decoder dengelemeye devam ederken son tam 64-D hareket token'ını tekrarlar. GR00T/Holosoma lokomasyonu ve ham `.q` kontrolü hâlâ desteklenmemektedir.                                                      |

Bu beyanlar, sürücü komut sözleşmesini yansıtır; her gövde veya denetleyici yapılandırmasının fiziksel doğrulanmasını temsil etmez. Genel `Robot` varsayılanı hâlâ false olarak kalır. Yetenek kontrolleri, kontrol noktası uyumluluğunu, denetleyici ayarlamasını, yük desteğini veya donanım sağlığını belirlemez.

## Teleoperator Ekleme

Teleoperasyon cihazlarını uygulamak için ayrıca bir [`Teleoperator`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/teleoperators/teleoperator.py) temel sınıfı da sunuyoruz. Bu sınıf, `Robot` temel sınıfına çok benzer ve form faktörü hakkında hiçbir varsayım yapmaz.

Ana farklar GİD (giriş/çıkış) işlevlerinde yer alır: bir teleoperator, `get_action` aracılığıyla eylem üretmenize ve `send_feedback` aracılığıyla geri bildirim eylemleri almanıza olanak tanır. Geri bildirim, eylemi kontrol eden kişinin gönderilen eylemlerin sonuçlarını anlamasına yardımcı olabilecek, teleoperasyon cihazında kontrol edilebilen herhangi bir şey olabilir. Örneğin, bir lider kolda hareket/kuvvet geri bildirimi veya bir oyun kolu kontrolcüsünde titreşimler. Bir teleoperator uygulamak için bu aynı öğreticiyi izleyebilir ve bu iki yöntem için uyarlayabilirsiniz.

## Kendi `LeRobot` Cihazlarınızı Kullanma 🔌

Kendi özel donanımınızı—bir kamera, robot veya teleoperasyon cihazı olsun—ayrı, kurulumu yapılabilir bir Python paketi oluşturarak `lerobot` içine kolayca ekleyebilirsiniz. Birkaç basit kurala uyduğunuzda, `lerobot` komut satırı araçları (`lerobot-teleoperate` ve `lerobot-record` gibi) `lerobot` kaynak kodunda herhangi bir değişiklik gerektirmeden **oluşturduğunuz donanımları otomatik olarak keşfeder ve entegre eder**.

Bu kılavuz, eklentinizin uyması gereken kuralları özetler.

### 4 Temel Sözleşme

Özel cihazınızın keşfedilebilir olmasını sağlamak için aşağıdaki dört kurala uymalısınız.

#### 1\. Belirli Bir Önek ile Kurulabilir Bir Paket Oluşturma

Projeniz standart, kurulabilir bir Python paketi olmalıdır. Önemli olan, paketinizin adı (`pyproject.toml` veya `setup.py` içinde tanımlanan) aşağıdaki öneklerden biriyle başlamalıdır:

- Bir robot için `lerobot_robot_`.
- Bir kamera için `lerobot_camera_`.
- Teleoperasyon cihazı için `lerobot_teleoperator_`.
- `lerobot-rollout` stratejisi için `lerobot_strategy_` (bkz. [Kendi stratejinizi getirin](./inference#bring-your-own-strategy)).

Bu önek sistemi, `lerobot`'un eklentinizi Python ortamında otomatik olarak bulma biçimidir.

#### 2\. `SomethingConfig`/`Something` Adlandırma Desenini Takip Edin

Cihazınızın uygulama sınıfı, yapılandırma sınıfının adından `Config` son ekini çıkararak adlandırılmalıdır.

- **Yapılandırma Sınıfı:** `MyAwesomeTeleopConfig`
- **Cihaz Sınıfı:** `MyAwesomeTeleop`

#### 3\. Dosyalarınızı Öngörülebilir Bir Yapıda Yerleştirin

Cihaz sınıfı (`MyAwesomeTeleop`), yapılandırma sınıfına (`MyAwesomeTeleopConfig`) göre öngörülebilir bir modülde bulunmalıdır. `lerobot` bu konumları otomatik olarak arar:

- Yapılandırma sınıfıyla **aynı modülde**.
- **cihaz adıyla adlandırılmış bir alt modülde** (ör. `my_awesome_teleop.py`).

Önerilen ve en basit yapı, bunları aynı dizin içinde ayrı ve açıkça adlandırılmış dosyalara yerleştirmektir.

#### 4\. Sınıfları `__init__.py` Dosyasında Dışa Aktarın

Paketinizin `__init__.py` dosyası, yapılandırma ve cihaz sınıflarını içe aktarıp bunları erişilebilir hale getirmelidir.

### Hepsini Bir Araya Getirme: Tam Bir Örnek

Yeni bir teleoperator oluşturalım: `my_awesome_teleop`.

#### Dizin Yapısı

Proje klasörünün görünümü aşağıdaki gibidir. Paket adı, `lerobot_teleoperator_my_awesome_teleop`, **1. \# Sözleşmeye** uygun olarak adlandırılmıştır.

```
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
```

#### Dosya İçeriği

- **`config_my_awesome_teleop.py`**: Yapılandırma sınıfını tanımlar. `Config` son ekine dikkat edin (**Kural \#2**).

  ```python
  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`**: Cihazı uygular. Sınıf adı `MyAwesomeTeleop`, yapılandırma sınıfının adıyla eşleşir (**Kural \#2**). Bu dosya yapısı **Kural \#3** ile uyumludur.

  ```python
  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`**: Ana sınıfları dışa açar (**Convention \#4**).

  ```python
  from .config_my_awesome_teleop import MyAwesomeTeleopConfig
  from .my_awesome_teleop import MyAwesomeTeleop
  ```

### Kurulum ve Kullanım

1.  **Yeni eklentinizi Python ortamınıza yükleyin.** Yerel eklenti paketinizi `pip`'in düzenlenebilir modu ile veya PyPi'den yükleyebilirsiniz.

    ```bash
    # 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.  **Doğrudan komut satırından kullanın.** Artık özel cihazınızı türüne atıfta bulunarak kullanabilirsiniz.

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

Ve işte bu kadar\! Özel cihazınız artık tamamen entegre edildi.

### Örnek mi arıyorsunuz?

Topluluk, bu şekilde oluşturulmuş onlarca eklentiye bakmaktadır. Donanımınıza yakın birini bulmak için [Üçüncü Taraf Robotlar & Teleoperatörler](./third_party_robots) ve [Üçüncü Taraf Kameralar & Sensörler](./third_party_sensors) bölümlerine göz atın veya bu iki küçük paketten başlayın:

- https://github.com/SpesRobotics/lerobot-robot-xarm
- https://github.com/SpesRobotics/lerobot-teleoperator-teleop

## Sonuç

Robot sınıfınız tamamlandığında, LeRobot ekosisteminden yararlanabilirsiniz:

- Robotunuzu mevcut teleoperatörlerle kontrol edin veya teleoperasyon cihazınızı doğrudan entegre edin
- Eğitim verilerini kaydet ve görselleştir
- Bunu RL veya taklit öğrenme hatlarına entegre edin

Eklentiniz yayımlandıktan sonra, diğer kullanıcıların bulabilmesi için onu [Third-Party Robots & Teleoperators](./third_party_robots) veya [Third-Party Cameras & Sensors](./third_party_sensors) bölümüne ekleyen bir PR açın.

Yardım için [Discord](https://discord.gg/s3KuuzsPFb) üzerinden topluluğa ulaşmaktan çekinmeyin 🤗

