Bibliothèque Rust complète pour contrôler les servomoteurs ST3215 via communication série. Cette bibliothèque offre une interface simple et sûre pour gérer tous les aspects des servos ST3215.
- API Rust complète - Interface type-safe et ergonomique
- Bindings C/C++ - Utilisation depuis C++ via FFI
- Multi-plateforme - Windows, Linux, macOS
- Communication série optimisée - Support de multiples ports
- Gestion du torque - Activation/désactivation précise
- Multiples modes - Position, vitesse, PWM, pas-à-pas
- Lecture des capteurs - Tension, courant, température, charge
- Étalonnage automatique - Détection des limites min/max
- Thread-safe - Utilisation sécurisée en multi-threading
Ajoutez cette dépendance dans votre Cargo.toml :
[dependencies]
st3215 = { path = "." }git clone https://github.com/Cogni-Robot/servo-controller
cd servo-controller
cargo build --releaseuse st3215::ST3215;
fn main() -> Result<(), String> {
// Connexion au port série
let controller = ST3215::new("/dev/ttyUSB0")?;
// Lister tous les servos connectés
let servos = controller.list_servos();
println!("Servos trouvés: {:?}", servos);
// Contrôler un servo
let servo_id = 1;
controller.enable_torque(servo_id)?;
controller.move_to(servo_id, 2048, 2400, 50, false);
Ok(())
}- Initialisation
- Détection et connexion
- Contrôle du torque
- Contrôle de position
- Contrôle de vitesse
- Lecture des capteurs
- Configuration avancée
- Étalonnage
- Exemples
Crée une nouvelle instance du contrôleur ST3215.
Paramètres:
device: Chemin du port série
Retour: Result<ST3215, String>
Exemples:
// Windows
let controller = ST3215::new("COM3")?;
// Linux
let controller = ST3215::new("/dev/ttyUSB0")?;
let controller = ST3215::new("/dev/ttyACM0")?;
// MacOS
let controller = ST3215::new("/dev/cu.usbserial-1234")?;Vérifie si un servo est présent et répond.
Paramètres:
sts_id: ID du servo (0-253)
Retour: true si le servo répond, false sinon
Exemple:
if controller.ping_servo(1) {
println!("Servo 1 est connecté");
}Scanne tous les IDs possibles (0-253) et retourne la liste des servos trouvés.
Retour: Vecteur contenant les IDs des servos détectés
Exemple:
let servos = controller.list_servos();
println!("Servos trouvés: {:?}", servos);
// Output: Servos trouvés: [1, 2, 5, 8]Active le torque du servo. Le servo maintiendra sa position et pourra être contrôlé.
Paramètres:
sts_id: ID du servo
Retour: Result<(), String>
Exemple:
controller.enable_torque(1)?;
println!("Torque activé");Désactive le torque du servo. Le servo peut être déplacé manuellement.
Paramètres:
sts_id: ID du servo
Retour: Result<(), String>
Exemple:
controller.disable_torque(1)?;
println!("Le servo peut être déplacé manuellement");Déplace le servo vers une position cible avec vitesse et accélération spécifiées.
Paramètres:
sts_id: ID du servoposition: Position cible (0-4095)speed: Vitesse de déplacement en step/s (0-3400)acc: Accélération en 100 step/s² (0-254)wait: Sitrue, bloque jusqu'à ce que la position soit atteinte
Retour: Some(true) en cas de succès, None en cas d'erreur
Exemple:
// Déplacement rapide sans attente
controller.move_to(1, 2048, 2400, 50, false);
// Déplacement lent avec attente
controller.move_to(1, 1024, 500, 20, true);
println!("Position atteinte!");Écrit directement une position cible sans modifier vitesse/accélération.
Paramètres:
sts_id: ID du servoposition: Position cible (0-4095)
Retour: Some(true) en cas de succès, None en cas d'erreur
Exemple:
controller.set_speed(1, 2000);
controller.set_acceleration(1, 50);
controller.write_position(1, 2048);Lit la position actuelle du servo.
Paramètres:
sts_id: ID du servo
Retour: Some(position) si réussi, None sinon
Exemple:
if let Some(pos) = controller.read_position(1) {
println!("Position actuelle: {}", pos);
}Vérifie si le servo est en mouvement.
Paramètres:
sts_id: ID du servo
Retour: Some(true) si en mouvement, Some(false) si arrêté, None en cas d'erreur
Exemple:
controller.move_to(1, 3000, 1500, 50, false);
while controller.is_moving(1) == Some(true) {
println!("En mouvement...");
std::thread::sleep(std::time::Duration::from_millis(100));
}
println!("Position atteinte!");Active le mode rotation continue avec une vitesse spécifiée.
Paramètres:
sts_id: ID du servospeed: Vitesse de rotation en step/s (-3400 à +3400)- Positif: rotation horaire
- Négatif: rotation anti-horaire
Retour: Result<(), String>
Exemple:
// Rotation horaire à 500 step/s
controller.rotate(1, 500)?;
// Rotation anti-horaire à 1000 step/s
controller.rotate(1, -1000)?;
// Arrêter
controller.disable_torque(1)?;Configure la vitesse pour les déplacements en mode position.
Paramètres:
sts_id: ID du servospeed: Vitesse en step/s (0-3400)
Retour: Some(true) en cas de succès, None en cas d'erreur
Exemple:
controller.set_speed(1, 2400);Lit la vitesse actuelle du servo.
Paramètres:
sts_id: ID du servo
Retour: Some(speed) si réussi, None sinon. La vitesse peut être négative.
Exemple:
if let Some(speed) = controller.read_speed(1) {
println!("Vitesse actuelle: {} step/s", speed);
}Configure l'accélération du servo.
Paramètres:
sts_id: ID du servoacc: Accélération (0-254), unité: 100 step/s²
Retour: Some(true) en cas de succès, None en cas d'erreur
Exemple:
// Accélération rapide (5000 step/s²)
controller.set_acceleration(1, 50);
// Accélération lente (1000 step/s²)
controller.set_acceleration(1, 10);Lit la valeur d'accélération configurée.
Paramètres:
sts_id: ID du servo
Retour: Some(acc) si réussi, None sinon
Exemple:
if let Some(acc) = controller.read_acceleration(1) {
println!("Accélération: {} (× 100 step/s²)", acc);
}Lit la tension d'alimentation du servo.
Paramètres:
sts_id: ID du servo
Retour: Some(voltage) en volts, None en cas d'erreur
Exemple:
if let Some(voltage) = controller.read_voltage(1) {
println!("Tension: {:.1} V", voltage);
if voltage < 6.0 {
println!("Attention: Tension faible!");
}
}Lit le courant consommé par le servo.
Paramètres:
sts_id: ID du servo
Retour: Some(current) en milliampères, None en cas d'erreur
Exemple:
if let Some(current) = controller.read_current(1) {
println!("Courant: {:.1} mA", current);
}Lit la température interne du servo.
Paramètres:
sts_id: ID du servo
Retour: Some(temperature) en degrés Celsius, None en cas d'erreur
Exemple:
if let Some(temp) = controller.read_temperature(1) {
println!("Température: {} °C", temp);
if temp > 70 {
println!("Attention: Température élevée!");
controller.disable_torque(1)?;
}
}Lit la charge actuelle sur le servo.
Paramètres:
sts_id: ID du servo
Retour: Some(load) en pourcentage, None en cas d'erreur
Exemple:
if let Some(load) = controller.read_load(1) {
println!("Charge: {:.1}%", load);
}Lit l'état de tous les capteurs du servo.
Paramètres:
sts_id: ID du servo
Retour: HashMap avec les états des capteurs (true = OK, false = Erreur)
"Voltage": État de la tension"Sensor": État du capteur"Temperature": État de la température"Current": État du courant"Angle": État de l'angle"Overload": État de surcharge
Exemple:
if let Some(status) = controller.read_status(1) {
for (sensor, ok) in status {
let icon = if ok { "OK" } else { "ERR" };
println!("[{}] {}: {}", icon, sensor, if ok { "OK" } else { "ERROR" });
}
}Change le mode opérationnel du servo.
Paramètres:
sts_id: ID du servomode: Mode à activer0: Mode position (contrôle de position précis)1: Mode vitesse constante (rotation continue)2: Mode PWM (contrôle direct du PWM)3: Mode pas-à-pas (contrôle stepper)
Retour: Result<(), String>
Exemple:
// Mode position (par défaut)
controller.set_mode(1, 0)?;
// Mode rotation continue
controller.set_mode(1, 1)?;Lit le mode actuel du servo.
Paramètres:
sts_id: ID du servo
Retour: Some(mode) si réussi, None sinon
Exemple:
if let Some(mode) = controller.read_mode(1) {
let mode_name = match mode {
0 => "Position",
1 => "Vitesse",
2 => "PWM",
3 => "Pas-à-pas",
_ => "Inconnu",
};
println!("Mode actuel: {}", mode_name);
}Applique une correction de position (offset).
Paramètres:
sts_id: ID du servocorrection: Valeur de correction en steps (-2047 à +2047)
Retour: Result<(), String>
Exemple:
// Ajouter un offset de +100 steps
controller.correct_position(1, 100)?;
// Soustraire 50 steps
controller.correct_position(1, -50)?;
// Réinitialiser
controller.correct_position(1, 0)?;Lit la correction de position actuelle.
Paramètres:
sts_id: ID du servo
Retour: Some(correction) si réussi, None sinon
Exemple:
if let Some(corr) = controller.read_correction(1) {
println!("Correction actuelle: {} steps", corr);
}Change l'ID d'un servo.
Paramètres:
sts_id: ID actuel du servonew_id: Nouvel ID (0-253)
Retour: Result<(), String>
Attention: Cette opération modifie l'EEPROM du servo.
Exemple:
// Changer l'ID de 1 à 5
controller.change_id(1, 5)?;
println!("ID changé: le servo répond maintenant à l'ID 5");
// Vérification
if controller.ping_servo(5) {
println!("Nouveau ID confirmé");
}Verrouille l'EEPROM du servo pour éviter les modifications accidentelles.
Paramètres:
sts_id: ID du servo
Retour: CommResult
Exemple:
controller.lock_eprom(1);Déverrouille l'EEPROM du servo pour permettre les modifications.
Paramètres:
sts_id: ID du servo
Retour: CommResult
Exemple:
controller.unlock_eprom(1);
controller.change_id(1, 5)?;
controller.lock_eprom(5);Étalonne automatiquement un servo en trouvant ses positions min et max.
Paramètres:
sts_id: ID du servo
Retour: Tuple (min_position, max_position)
Important:
- Ne fonctionne que sur des servos avec butées mécaniques
- Le servo va effectuer une rotation complète
- Assurez-vous qu'il n'y a pas d'obstacles
Exemple:
println!("Démarrage de l'étalonnage...");
let (min, max) = controller.tare_servo(1);
match (min, max) {
(Some(min_pos), Some(max_pos)) => {
println!("Étalonnage réussi!");
println!(" Position min: {}", min_pos);
println!(" Position max: {}", max_pos);
println!(" Course totale: {} steps", max_pos - min_pos);
}
_ => println!("Échec de l'étalonnage"),
}Définit la position actuelle comme position 2048 (milieu).
Paramètres:
sts_id: ID du servo
Retour: Some(true) en cas de succès, None en cas d'erreur
Exemple:
// Placer manuellement le servo à la position souhaitée
controller.disable_torque(1)?;
println!("Placez le servo à la position centrale...");
std::thread::sleep(std::time::Duration::from_secs(5));
// Définir cette position comme 2048
controller.define_middle(1);
controller.enable_torque(1)?;use st3215::ST3215;
fn main() -> Result<(), String> {
let controller = ST3215::new("/dev/ttyUSB0")?;
println!("Scan des servos...");
let servos = controller.list_servos();
println!("\n{} servo(s) trouvé(s):", servos.len());
for id in servos {
println!(" - Servo ID: {}", id);
}
Ok(())
}use st3215::ST3215;
fn main() -> Result<(), String> {
let controller = ST3215::new("/dev/ttyUSB0")?;
let servo_id = 1;
// Activer le torque
controller.enable_torque(servo_id)?;
// Déplacer vers différentes positions
let positions = [1024, 2048, 3072, 2048];
for &pos in &positions {
println!("Déplacement vers {}", pos);
controller.move_to(servo_id, pos, 2000, 50, true);
std::thread::sleep(std::time::Duration::from_millis(500));
}
// Désactiver le torque
controller.disable_torque(servo_id)?;
Ok(())
}use st3215::ST3215;
use std::time::Duration;
use std::thread;
fn main() -> Result<(), String> {
let controller = ST3215::new("/dev/ttyUSB0")?;
let servo_id = 1;
controller.enable_torque(servo_id)?;
// Monitoring en boucle
for _ in 0..10 {
println!("\n--- État du servo {} ---", servo_id);
if let Some(pos) = controller.read_position(servo_id) {
println!("Position: {}", pos);
}
if let Some(voltage) = controller.read_voltage(servo_id) {
println!("Tension: {:.1} V", voltage);
}
if let Some(current) = controller.read_current(servo_id) {
println!("Courant: {:.1} mA", current);
}
if let Some(temp) = controller.read_temperature(servo_id) {
println!("Température: {} °C", temp);
}
if let Some(load) = controller.read_load(servo_id) {
println!("Charge: {:.1}%", load);
}
thread::sleep(Duration::from_secs(1));
}
Ok(())
}use st3215::ST3215;
use std::time::Duration;
use std::thread;
fn main() -> Result<(), String> {
let controller = ST3215::new("/dev/ttyUSB0")?;
let servo_id = 1;
// Rotation horaire pendant 3 secondes
println!("Rotation horaire...");
controller.rotate(servo_id, 500)?;
thread::sleep(Duration::from_secs(3));
// Rotation anti-horaire pendant 3 secondes
println!("Rotation anti-horaire...");
controller.rotate(servo_id, -500)?;
thread::sleep(Duration::from_secs(3));
// Arrêt
println!("Arrêt...");
controller.disable_torque(servo_id)?;
Ok(())
}use st3215::ST3215;
fn main() -> Result<(), String> {
let controller = ST3215::new("/dev/ttyUSB0")?;
let servos = controller.list_servos();
println!("Contrôle de {} servos", servos.len());
// Activer tous les servos
for &id in &servos {
controller.enable_torque(id)?;
}
// Déplacer tous les servos vers la position centrale
for &id in &servos {
controller.move_to(id, 2048, 2000, 50, false);
}
// Attendre que tous soient en position
std::thread::sleep(std::time::Duration::from_secs(2));
// Lire les positions finales
for &id in &servos {
if let Some(pos) = controller.read_position(id) {
println!("Servo {}: position = {}", id, pos);
}
}
Ok(())
}# Mode debug
cargo build
# Mode release (optimisé)
cargo build --release# Exemple basique
cargo run --example basic --release
# Exemple de contrôle du torque
cargo run --example torque_control --release
# Programme principal
cargo run --releasecargo testCette bibliothèque peut être utilisée depuis C/C++ via les bindings FFI.
Voir la documentation complète: CPP_INTEROP.md
#include "st3215.h"
int main() {
// Créer le contrôleur
ST3215Handle* controller = st3215_new("/dev/ttyUSB0");
// Activer le torque
st3215_enable_torque(controller, 1, 1);
// Déplacer le servo
st3215_move_to(controller, 1, 2048, 2400, 50, 0);
// Libérer les ressources
st3215_free(controller);
return 0;
}| Paramètre | Valeur min | Valeur max | Unité |
|---|---|---|---|
| Position | 0 | 4095 | steps |
| Vitesse | 0 | 3400 | step/s |
| Accélération | 0 | 254 | × 100 step/s² |
| Tension | 6.0 | 8.4 | V |
| Température | -5 | 75 | °C |
| ID | 0 | 253 | - |
STS_MODEL_L/H(3-4): Numéro de modèle
STS_ID(5): ID du servoSTS_BAUD_RATE(6): Vitesse de communicationSTS_MIN_ANGLE_LIMIT_L/H(9-10): Limite min d'angleSTS_MAX_ANGLE_LIMIT_L/H(11-12): Limite max d'angleSTS_OFS_L/H(31-32): Offset de positionSTS_MODE(33): Mode opérationnel
STS_TORQUE_ENABLE(40): Activation du coupleSTS_ACC(41): AccélérationSTS_GOAL_POSITION_L/H(42-43): Position cibleSTS_GOAL_TIME_L/H(44-45): Temps pour atteindre la positionSTS_GOAL_SPEED_L/H(46-47): Vitesse cibleSTS_LOCK(55): Verrouillage EEPROM
STS_PRESENT_POSITION_L/H(56-57): Position actuelleSTS_PRESENT_SPEED_L/H(58-59): Vitesse actuelleSTS_PRESENT_LOAD_L/H(60-61): Charge actuelleSTS_PRESENT_VOLTAGE(62): Tension actuelleSTS_PRESENT_TEMPERATURE(63): Température actuelleSTS_STATUS(65): Bits d'état des capteursSTS_MOVING(66): Statut de mouvementSTS_PRESENT_CURRENT_L/H(69-70): Courant actuel
| Mode | Valeur | Description |
|---|---|---|
| Position | 0 | Contrôle de position précis (0-4095) |
| Vitesse | 1 | Rotation continue à vitesse constante |
| PWM | 2 | Contrôle direct du signal PWM |
| Stepper | 3 | Mode pas-à-pas |
# Logs de base
RUST_LOG=info cargo run
# Logs détaillés
RUST_LOG=debug cargo run
# Logs très détaillés
RUST_LOG=trace cargo run# Ajouter l'utilisateur au groupe dialout
sudo usermod -a -G dialout $USER
# Ou donner les permissions au port
sudo chmod 666 /dev/ttyUSB0- Vérifier la connexion physique
- Vérifier le câblage (TX/RX, alimentation)
- Vérifier le baudrate (par défaut: 1000000)
- Tester avec
ping_servo()
- Vérifier la correction de position:
read_correction() - Réinitialiser la correction:
correct_position(id, 0) - Effectuer un étalonnage:
tare_servo(id)
serialport(4.3) - Communication série multiplateformethiserror(1.0) - Gestion élégante des erreursserde(1.0) - Sérialisation (optionnel)serde_json(1.0) - JSON (optionnel)
Ce projet est sous licence MIT. Voir le fichier LICENSE pour plus de détails.
NotPunchnox
Merci à tous les contributeurs et utilisateurs de cette bibliothèque!
Made with ❤️ and 🦀 Rust