# Moteurs

`SerialMotorsBus` est l’interface de bas niveau vers une chaîne de servomoteurs Feetech ou Dynamixel sur un bus série. Les robots l’utilisent pour lire les positions et écrire les positions cibles ; vous n’y touchez que rarement directement, sauf si vous ajoutez du matériel. Le modèle de chaque moteur est recherché dans [rustypot](https://github.com/pollen-robotics/rustypot), qui contient les tables de contrôle et les caractéristiques qui diffèrent entre les familles, et qui gère également le port série. `FeetechMotorsBus` et `DynamixelMotorsBus` sont des alias obsolètes de celui-ci, conservés pour une seule version.

### Migration depuis les bus basés sur le SDK

Les alias conservent les noms de classes, et non les anciens attributs du SDK et les tables de modèles :

- `bus.model_resolution_table[model]` devient `bus.resolution(model)` ; les autres tables de modèles (`model_ctrl_table`, `model_number_table`, ...) sont désormais les définitions de servos de rustypot.
- Les modes de fonctionnement sont sélectionnés par leur nom, `bus.set_operating_mode("position")`, au lieu d’écrire une valeur `OperatingMode` dans le registre `Operating_Mode`.
- Le port SDK et les gestionnaires de paquets ne sont plus exposés : rustypot possède le port série.
- `protocol_version` est ignoré : le modèle de chaque moteur fournit son protocole.

Consultez [Bring Your Own Hardware](../integrate_hardware) pour ajouter un nouveau bus, ainsi que [Updating Feetech Firmware](../feetech) et [Damiao Motors and CAN Bus](../damiao) pour les notes spécifiques aux appareils.

## SerialMotorsBus[[lerobot.motors.SerialMotorsBus]]

#### lerobot.motors.SerialMotorsBus[[lerobot.motors.SerialMotorsBus]]

```python
lerobot.motors.SerialMotorsBus(port: str, motors: dict[str, Motor], calibration: dict[str, MotorCalibration] | None = None)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L156)

Lire et écrire une chaîne de servos connectés en cascade sur un port série unique, Feetech ou Dynamixel.

rustypot gère les métadonnées de chaque modèle (table de contrôle, résolution, débits, modes de fonctionnement) ainsi que l’entrée/sortie série ; LeRobot gère la normalisation, l’étalonnage et les paramètres recommandés. Les moteurs de plusieurs modèles, tels que STS et SCS ou XL430 et XL330, partagent le port.

Pour trouver le port, exécutez :
```bash
lerobot-find-port
>>> Finding all available ports for the MotorsBus.
>>> ["/dev/tty.usbmodem575E0032081", "/dev/tty.usbmodem575E0031751"]
>>> Remove the usb cable from your MotorsBus and press Enter when done.
>>> The port of this MotorsBus is /dev/tty.usbmodem575E0031751.
>>> Reconnect the usb cable.
```

Exemple pour un seul Feetech sts3215 sur le bus :
```python
from lerobot.motors import Motor, MotorNormMode, SerialMotorsBus

bus = SerialMotorsBus(
    port="/dev/tty.usbmodem575E0031751",
    motors={"my_motor": Motor(1, "sts3215", MotorNormMode.RANGE_M100_100)},
)
bus.connect()

position = bus.read("Present_Position", "my_motor", normalize=False)

# Move a few motor steps as an example
bus.write("Goal_Position", "my_motor", position + 30, normalize=False)

bus.disconnect()
```

#### configure_motors[[lerobot.motors.SerialMotorsBus.configure_motors]]

```python
configure_motors(return_delay_time: int = 0, maximum_acceleration: int = 254, acceleration: int = 254)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L572)

**Paramètres :**

return_delay_time (`int`, *facultatif*, valeur par défaut `0`) : Délai avant qu'un moteur ne réponde, en unités de 2 µs ; les moteurs quittent l'usine avec une valeur de 250 (500 µs).

maximum_acceleration (`int`, *facultatif*, valeur par défaut `254`) : Plafond d'accélération, sur les servomoteurs qui en disposent (Feetech STS), une valeur élevée accélère l'accélération et le décélération.

acceleration (`int`, *facultatif*, valeur par défaut `254`) : Accélération, sur les servos qui en disposent (Feetech).

Écrivez les paramètres recommandés par LeRobot sur chaque moteur.

#### connect[[lerobot.motors.SerialMotorsBus.connect]]

```python
connect(handshake: bool = True)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L396)

**Paramètres :**

handshake (`bool`, *facultatif*, par défaut `True`) : Indique s'il faut vérifier que chaque moteur répond avec le numéro de modèle de son modèle, et que les moteurs Feetech d'une même définition exécutent un seul et même firmware.

**Exceptions levées :** ``DeviceAlreadyConnectedError`` ou ``ConnectionError`` ou ``RuntimeError``

- ``DeviceAlreadyConnectedError`` -- Si le port est déjà ouvert.
- ``ConnectionError`` -- Si le port n'a pas pu être ouvert.
- ``RuntimeError`` -- Si la poignée de main échoue ; le port est à nouveau fermé.

Ouvrez le port série et vérifiez les moteurs.

#### disable_torque[[lerobot.motors.SerialMotorsBus.disable_torque]]

```python
disable_torque(motors: NameOrID | Sequence[NameOrID] | None = None, num_retry: int = 0)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L650)

**Paramètres :**

motors (`str | int | Sequence[str | int]`, *facultatif*) : Moteurs à libérer, par nom ou par identifiant. `None` sélectionne tous les moteurs.

num_retry (`int`, *facultatif*, valeur par défaut `0`) : Nombre de tentatives supplémentaires sur chaque moteur après un échec de communication.

**Levée :** ``ConnectionError``

- ``ConnectionError`` -- Si certains moteurs n'ont pas pu être atteints ; le message les nomme.

Désactiver le couple des moteurs sélectionnés.

Avec le couple désactivé, l'EEPROM d'un moteur peut être écrite, et le verrouillage d'un moteur Feetech s'ouvre pour cela. Chaque moteur sélectionné est tenté ; les échecs sont signalés, et les moteurs sans réponse peuvent rester avec le couple activé.

#### déconnecter[[lerobot.motors.SerialMotorsBus.disconnect]]

```python
disconnect(disable_torque: bool = True)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L440)

**Paramètres :**

disable_torque (`bool`, *facultatif*, valeur par défaut `True`) : Indique s'il faut désactiver le couple de chaque moteur avant de fermer le port, afin qu'aucun moteur ne reste en résistance.

Fermez le port série, par défaut avec le couple de chaque moteur désactivé.

Sûr à appeler sur un bus déjà déconnecté, et le port est libéré même si la désactivation du couple échoue.

#### enable_torque[[lerobot.motors.SerialMotorsBus.enable_torque]]

```python
enable_torque(motors: NameOrID | Sequence[NameOrID] | None = None, num_retry: int = 0)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L669)

**Paramètres :**

motors (`str | int | Sequence[str | int]`, *facultatif*) : Moteurs à maintenir, par nom ou par identifiant. `None` sélectionne tous les moteurs.

num_retry (`int`, *facultatif*, valeur par défaut `0`) : Nombre de tentatives supplémentaires sur chaque moteur après un échec de communication.

**Levée :** ``ConnectionError``

- ``ConnectionError`` -- Si certains moteurs n'ont pas pu être atteints ; le message les nomme.

Activez le couple des moteurs sélectionnés et fermez le verrouillage des moteurs Feetech.

#### ping[[lerobot.motors.SerialMotorsBus.ping]]

```python
ping(motor: NameOrID, num_retry: int = 0)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L1069)

**Paramètres :**

motor (`str | int`) : Moteur, par nom ou par identifiant, l'un des moteurs du bus.

num_retry (`int`, *facultatif*, valeur par défaut `0`) : Nombre de tentatives supplémentaires en cas d'échec de communication.

**Retourne :** `int | None`

Le numéro du modèle, `None` lorsque le moteur ne répond pas ou refuse la lecture.

Le numéro de modèle auquel un moteur répond.

Lit `Model_Number` plutôt que d’envoyer un ping : la présence et l’identité ne coûtent alors qu’un aller-retour au lieu de deux.

#### read[[lerobot.motors.SerialMotorsBus.read]]

```python
read(data_name: str, motor: str, normalize: bool = True, num_retry: int = 0)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L1090)

**Paramètres :**

data_name (`str`) : Nom de l'enregistrement, par exemple `"Present_Position"` ; la casse n'a pas d'importance.

motor (`str`) : Nom du moteur.

normalize (`bool`, *facultatif*, valeur par défaut `True`) : Indique s'il faut mettre à l'échelle une position à l'intervalle défini par son mode de calibration et de normalisation.

num_retry (`int`, *facultatif*, valeur par défaut `0`) : Nombre de tentatives supplémentaires en cas d'échec de communication.

**Retourne :** `int | float`

La valeur brute, ou la valeur normalisée.

**Exceptions levées :** ``ConnectionError`` ou ``RuntimeError``

- ``ConnectionError`` -- Si le moteur ne répond pas.
- ``RuntimeError`` -- Si le moteur refuse la lecture. Une alarme dans son état, comme une surcharge, ne déclenche pas d'exception.

Lire un registre d'un moteur.

#### read_calibration[[lerobot.motors.SerialMotorsBus.read_calibration]]

```python
read_calibration()
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L744)

**Retourne :** `dict[str, MotorCalibration]`

La calibration de chaque moteur, par nom.

Lisez la calibration de chaque moteur.

Un moteur sans registre de décalage de position zéro (Feetech SCS) renvoie 0, et un moteur sans registre `Drive_Mode` (Feetech) renvoie le mode de conduite 0.

#### record_calibration[[lerobot.motors.SerialMotorsBus.record_calibration]]

```python
record_calibration(mode: str, full_turn_motors: Sequence[str], inverted_motors: Sequence[str] = (), motors: Sequence[str] | None = None)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L931)

**Paramètres :**

mode (`str`) : Mode de fonctionnement des moteurs, par exemple `"position"`.

full_turn_motors (`Sequence[str]`) : Moteurs donnés sur l'ensemble de la plage de l'encodeur plutôt que sur la plage parcourue.

inverted_motors (`Sequence[str]`, *facultatif*, par défaut `()`) : Moteurs tournant dans l'autre sens.

motors (`Sequence[str]`, *facultatif*) : Moteurs à calibrer. `None` calibre tous les moteurs.

**Retourne :** `dict[str, MotorCalibration]`

La calibration de chaque moteur, dans l'ordre du bus.

**Levée :** ``ValueError``

- ``ValueError`` -- Si un moteur n'est pas sur le bus, ou si un moteur complet ou inversé n'est pas l'un des moteurs à calibrer ; aucun moteur n'a alors été modifié.

Calibrer les moteurs déplacés à la main.

Les moteurs sélectionnés sont libérés, placés en mode de fonctionnement et leur direction est définie : pour un moteur doté d'un registre `Drive_Mode`, celui-ci est écrit, avec ou sans inversion, tandis que pour les autres, en tant que servomoteurs Feetech, une inversion est appliquée logiciellement lors de la normalisation. L'utilisateur maintient ensuite les articulations au milieu de leur plage de mouvement, ce qui correspond à un demi-tour de chaque moteur, et fait parcourir à chaque articulation toute sa plage, en enregistrant jusqu'à la touche ENTER. Un moteur à rotation complète n'est pas enregistré : il couvre l'ensemble de l'encodeur de son modèle.

Les moteurs ont besoin du mode de fonctionnement et d'un décalage de référence, dont le Feetech SCS0009 est dépourvu. Leurs décalages de référence et limites de position sont réécrits, le `calibration` mis en cache est effacé et leur couple reste désactivé. La calibration renvoyée n'est ni écrite dans les limites de position ni sauvegardée : `~SerialMotorsBus.write_calibration` l'écrit et l'appareil la sauvegarde.

#### record_ranges_of_motion[[lerobot.motors.SerialMotorsBus.record_ranges_of_motion]]

```python
record_ranges_of_motion(motors: NameOrID | Sequence[NameOrID] | None = None, display_values: bool = True)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L876)

**Paramètres :**

motors (`str | int | Sequence[str | int]`, *facultatif*) : Moteurs à enregistrer, par nom ou par identifiant. `None` sélectionne tous les moteurs.

display_values (`bool`, *facultatif*, par défaut `True`) : Indique s'il faut afficher le tableau en direct.

**Retourne :** `tuple[dict[str, int | float], dict[str, int | float]]`

La position brute la plus basse et la plus haute de chaque moteur, par nom.

**Levée :** ``ValueError``

- ``ValueError`` -- Si un moteur ne s'est pas déplacé : sa position minimale et sa position maximale sont égales.

Enregistrez la plage de déplacement parcourue manuellement par chaque moteur sélectionné, jusqu'à la touche ENTER.

Les articulations sont déplacées à la main, le couple étant désactivé, tandis qu'un tableau en direct affiche les positions.

#### reset_calibration[[lerobot.motors.SerialMotorsBus.reset_calibration]]

```python
reset_calibration(motors: NameOrID | Sequence[NameOrID] | None = None)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L799)

**Paramètres :**

motors (`str | int | Sequence[str | int]`, *facultatif*) : Moteurs à réinitialiser, par nom ou par identifiant. `None` sélectionne tous les moteurs.

Restaurer l'étalonnage d'usine des moteurs sélectionnés.

Le décalage de retour à la position de référence est défini sur 0 pour les moteurs qui en sont équipés, et les limites de position couvrent l'ensemble de l'encodeur. Le `calibration` mis en cache est effacé.

#### résolution[[lerobot.motors.SerialMotorsBus.resolution]]

```python
resolution(model: str)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L268)

**Paramètres :**

model (`str`) : Modèle de l'un des moteurs du bus, par exemple `"sts3215"`.

**Retourne :** `int`

Le nombre d'étapes par tour, par exemple 4096 sur un encodeur 12 bits.

**Levée :** ``ValueError``

- ``ValueError`` -- Si le modèle ne compte pas les étapes de l'encodeur.

Étapes de l'encodeur par tour d'un modèle de moteur.

#### set_baudrate[[lerobot.motors.SerialMotorsBus.set_baudrate]]

```python
set_baudrate(baudrate: int)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L707)

**Paramètres :**

baudrate (`int`) : Vitesse en bauds, en bits par seconde.

Modifiez le taux de bauds du port ouvert.

Le port s'ouvre à `default_baudrate` à chaque connexion.

#### set_half_turn_homings[[lerobot.motors.SerialMotorsBus.set_half_turn_homings]]

```python
set_half_turn_homings(motors: NameOrID | Sequence[NameOrID] | None = None)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L820)

**Paramètres :**

motors (`str | int | Sequence[str | int]`, *facultatif*) : Moteurs à ramener à la position d'origine, par nom ou par identifiant. `None` sélectionne tous les moteurs.

**Retourne :** `dict[str, int]`

Le décalage de retour à la position zéro écrit sur chaque moteur, par nom.

**Levée :** ``ValueError``

- ``ValueError`` -- Si un moteur sélectionné ne possède pas de décalage de référence, comme le Feetech SCS.

Faire effectuer à chaque moteur sélectionné une demi-tour.

La calibration des moteurs est réinitialisée, puis chacun reçoit le décalage de référence qui amène sa position actuelle à la moitié de son encodeur, par exemple 2047 pour un encodeur sur 12 bits. Chaque moteur sélectionné doit avoir un décalage de référence, ce qui est vérifié avant l'écriture de tout registre.

#### set_operating_mode[[lerobot.motors.SerialMotorsBus.set_operating_mode]]

```python
set_operating_mode(mode: str, motors: NameOrID | Sequence[NameOrID] | None = None)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L600)

**Paramètres :**

mode (`str`) : Nom du mode de fonctionnement, par exemple `"position"`.

motors (`str | int | Sequence[str | int]`, *facultatif*) : Moteurs à définir, par nom ou par identifiant. `None` sélectionne tous les moteurs.

**Levée :** ``ValueError``

- ``ValueError`` -- Si le moteur sélectionné ne possède pas ce mode ; aucun moteur n'a alors changé de mode.

Placez les moteurs sélectionnés dans un mode de fonctionnement, spécifié par son nom.

Les modes proviennent de la définition de chaque moteur, ils dépendent donc du modèle et non uniquement de la famille : le Feetech SCS0009 n’en possède aucun. Le mode doit exister pour chaque moteur sélectionné, ce qui est vérifié avant que n’importe quel moteur ne change de mode. Écrivez-le avec le couple désactivé.

- `position` : contient une position cible au sein d'un tour ainsi que les limites de position.
- `velocity` : tourne en continu à une vitesse cible, comme une roue.
- `pwm` : pilote directement la tension du moteur, en boucle ouverte.
- `step` (Feetech) : se déplace du nombre d'étapes indiqué comme position cible.
- `current` (Dynamixel) : conserve un courant cible, c'est-à-dire un couple, quelle que soit la position.
- `extended_position` (Dynamixel) : maintient une position cible sur plusieurs tours. Les registres `Min_Position_Limit` et `Max_Position_Limit` sont ignorés dans ce mode.
- `current_based_position` (Dynamixel) : maintient une position cible sur plusieurs tours, avec le courant limité par le courant cible, comme une pince qui ne doit pas écraser ce qu’elle tient.

#### setup_motor[[lerobot.motors.SerialMotorsBus.setup_motor]]

```python
setup_motor(motor: str, initial_baudrate: int | None = None, initial_id: int | None = None)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L471)

**Paramètres :**

motor (`str`) : Nom du moteur.

initial_baudrate (`int`, *facultatif*) : Vitesse en bauds à laquelle le moteur répond actuellement.

initial_id (`int`, *facultatif*) : Id auquel le moteur répond actuellement, utilisé avec `initial_baudrate`.

**Exceptions levées :** ``RuntimeError`` ou ``ConnectionError``

- ``RuntimeError`` -- Si le moteur n'est pas trouvé, n'est pas de son modèle, ou ne répond pas comme configuré une fois mis en place.
- ``ConnectionError`` -- Si la communication avec le moteur échoue.

Donnez à un moteur unique son identifiant et le taux de baud par défaut du bus.

Le moteur doit être le seul sur le bus. À moins que `initial_baudrate` et `initial_id` soient tous deux fournis, il est d'abord détecté : à `initial_baudrate` si seul celui-ci est fourni, sinon parmi les débits de son modèle ; un `initial_id` fourni seul est remplacé par l'identifiant trouvé. rustypot désactive ensuite son couple, ouvre sa mémoire EEPROM et y écrit l'identifiant et le débit.

#### setup_motors[[lerobot.motors.SerialMotorsBus.setup_motors]]

```python
setup_motors(motors: Sequence[str] | None = None)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L530)

**Paramètres :**

motors (`Sequence[str]`, *facultatif*) : Moteurs dans l'ordre dans lequel ils sont configurés. `None` va du dernier moteur au premier, du pince vers le bas sur un bras.

Configurez les moteurs un par un, en demandant à chacun d’être seul sur le bus.

#### sync_read[[lerobot.motors.SerialMotorsBus.sync_read]]

```python
sync_read(data_name: str, motors: NameOrID | Sequence[NameOrID] | None = None, normalize: bool = True, num_retry: int = 0)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L1193)

**Paramètres :**

data_name (`str`) : Nom de l'enregistrement, par exemple `"Present_Position"` ; la casse n'a pas d'importance.

motors (`str | int | Sequence[str | int]`, *facultatif*) : Moteurs à lire, par nom ou par identifiant. `None` lit tous les moteurs.

normalize (`bool`, *facultatif*, valeur par défaut `True`) : Indique s'il faut mettre à l'échelle les positions selon la plage définie par leur mode de calibration et de normalisation.

num_retry (`int`, *facultatif*, valeur par défaut `0`) : Nombre de tentatives supplémentaires après un échec de communication. Une nouvelle tentative renvoie tous les groupes, y compris ceux qui avaient réussi ; un moteur ou un registre inconnu n'est jamais retenté.

**Retourne :** `dict[str, int | float]`

La valeur de chaque moteur, par nom.

**Exceptions levées :** ``ConnectionError`` ou ``RuntimeError``

- ``ConnectionError`` -- Si un moteur ne répond pas.
- ``RuntimeError`` -- Si un moteur refuse la lecture. Une alarme dans un statut, comme une surcharge, ne déclenche pas d'exception.

Lire un registre de plusieurs moteurs.

rustypot envoie une lecture synchronisée par groupe de moteurs partageant un protocole ainsi que l'adresse et la taille du registre, et lit les moteurs d'un servomoteur sans lecture synchronisée, comme le Feetech SCS, l'un après l'autre. Les valeurs ne constituent donc pas un instantané simultané.

#### sync_write[[lerobot.motors.SerialMotorsBus.sync_write]]

```python
sync_write(data_name: str, values: Value | dict[str, Value], normalize: bool = True, num_retry: int = 0)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L1253)

**Paramètres :**

data_name (`str`) : Nom de l'enregistrement, par exemple `"Goal_Position"` ; la casse n'a pas d'importance.

values (`int | float | dict[str, int | float]`) : Une valeur pour chaque moteur, ou une valeur par nom de moteur.

normalize (`bool`, *facultatif*, valeur par défaut `True`) : Indique si les positions sont fournies dans la plage définie par leur mode de calibration et de normalisation.

num_retry (`int`, *facultatif*, valeur par défaut `0`) : Nombre de tentatives supplémentaires après un échec du port. Une nouvelle tentative renvoie chaque groupe.

**Levée :** ``ConnectionError``

- ``ConnectionError`` -- Si le port échoue.

Écrivez un registre de plusieurs moteurs, sans attendre de réponse.

Contrairement à `~SerialMotorsBus.write`, aucun moteur ne répond à une écriture synchrone : plus rapide, adaptée aux boucles de contrôle, mais un paquet perdu passe inaperçu. rustypot envoie une écriture synchrone par groupe de moteurs partageant le même protocole ainsi que l'adresse et la taille du registre.

#### torque_disabled[[lerobot.motors.SerialMotorsBus.torque_disabled]]

```python
torque_disabled(motors: NameOrID | Sequence[NameOrID] | None = None)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L684)

**Paramètres :**

motors (`str | int | Sequence[str | int]`, *facultatif*) : Moteurs à libérer, par nom ou par identifiant. `None` sélectionne tous les moteurs.

Désactiver le couple des moteurs sélectionnés pendant la durée d'un bloc `with`.

Le couple est réactivé à la sortie, même si le bloc lève une exception, ce qui convient à la configuration des moteurs.

Exemple :
```python
>>> with bus.torque_disabled():
...     bus.set_operating_mode("position")
```

#### write[[lerobot.motors.SerialMotorsBus.write]]

```python
write(data_name: str, motor: str, value: Value, normalize: bool = True, num_retry: int = 0)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L1146)

**Paramètres :**

data_name (`str`) : Nom de l'enregistrement, par exemple `"Goal_Position"` ; la casse n'a pas d'importance.

motor (`str`) : Nom du moteur.

value (`int | float`) : Valeur à écrire, normalisée ou brute selon `normalize`.

normalize (`bool`, *facultatif*, par défaut `True`) : Indique si une position est donnée dans la plage définie par son mode de calibration et de normalisation.

num_retry (`int`, *facultatif*, valeur par défaut `0`) : Nombre de tentatives supplémentaires en cas d'échec de communication.

**Exceptions levées :** ``ConnectionError`` ou ``RuntimeError``

- ``ConnectionError`` -- Si le moteur ne répond pas.
- ``RuntimeError`` -- Si le moteur refuse l'écriture. Une alarme dans son état, comme une surcharge, ne déclenche pas d'exception.

Écrivez dans le registre d'un moteur et attendez sa réponse.

Contrairement à `~SerialMotorsBus.sync_write`, le moteur accuse réception de l’écriture, si bien qu’un échec est signalé : plus lent, mais adapté à la configuration des moteurs.

#### write_calibration[[lerobot.motors.SerialMotorsBus.write_calibration]]

```python
write_calibration(calibration_dict: dict[str, MotorCalibration], cache: bool = True)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L774)

**Paramètres :**

calibration_dict (`dict[str, MotorCalibration]`) : Calibration de chaque moteur, par nom, telle que renvoyée par `~SerialMotorsBus.read_calibration`.

cache (`bool`, *facultatif*, par défaut `True`) : Indique s'il faut conserver l'étalonnage en tant que `calibration` du bus, ce qui normalise les positions.

Écrivez une calibration vers les moteurs et, par défaut, mettez-la en cache.

Les limites de position sont écrites sur chaque moteur, et le décalage de référence sur les moteurs qui en possèdent un. Ni l’identifiant ni le mode de pilotage ne sont écrits : le mode de pilotage d’un Feetech est appliqué en logiciel lors de la normalisation, et le registre `Drive_Mode` d’un Dynamixel est configuré séparément.

## Moteur[[lerobot.motors.Motor]]

#### lerobot.motors.Motor[[lerobot.motors.Motor]]

```python
lerobot.motors.Motor(id: int, model: str, norm_mode: MotorNormMode, motor_type_str: str | None = None, recv_id: int | None = None)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L148)

## MotorCalibration[[lerobot.motors.MotorCalibration]]

#### lerobot.motors.MotorCalibration[[lerobot.motors.MotorCalibration]]

```python
lerobot.motors.MotorCalibration(id: int, drive_mode: int, homing_offset: int, range_min: int, range_max: int)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L139)

## MotorNormMode[[lerobot.motors.MotorNormMode]]

#### lerobot.motors.MotorNormMode[[lerobot.motors.MotorNormMode]]

```python
lerobot.motors.MotorNormMode(*values)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L125)

## DriveMode[[lerobot.motors.DriveMode]]

`DriveMode` possède deux membres, `NON_INVERTED = 0` et `INVERTED = 1`. Utilisez `.value` là où un entier est attendu, dans un registre `Drive_Mode` ou dans `MotorCalibration.drive_mode` :

```python
bus.write("Drive_Mode", "elbow_flex", DriveMode.INVERTED.value)
```

#### lerobot.motors.DriveMode[[lerobot.motors.DriveMode]]

```python
lerobot.motors.DriveMode(*values)
```

[Source](https://github.com/huggingface/lerobot/blob/v0.7.0/src/lerobot/motors/motors_bus.py#L131)

Valeur du registre `Drive_Mode` d'un Dynamixel, et de `MotorCalibration.drive_mode`.

