Python est un langage de programmation largement utilisé. L'envoi de commandes Modbus via Python offre un moyen pratique de contrôler les opérations du moteur. Vous trouverez ci-dessous un exemple de code simple pour envoyer des commandes Modbus à l'aide de Python. Les commandes Modbus proviennent de l'article Instructions d'utilisation RS485 du servomoteur A6, plus précisément de la section 2.3, « Mouvement en position absolue de 5000 impulsions (réglage par défaut : 10000 impulsions/tour, C00.02=10000) ». Ce code s'applique aux servovariateurs de la série A6-RS de StepperOnline et commande le moteur en mode position absolue pour un déplacement de 5000 impulsions.
Voici le code Python :
import serial
import time
import binascii
from crcmod import crcmod
# Configuration du port série - à modifier selon votre appareil
PORT = 'COM3' # Port série (Windows : 'COM3', Linux : '/dev/ttyUSB0')
BAUDRATE = 9600 # Vitesse de transmission (valeurs courantes : 9600, 19200, 38400, 57600, 115200)
PARITY = serial.PARITY_NONE
STOPBITS = serial.STOPBITS_ONE
BYTESIZE = serial.EIGHTBITS
TIMEOUT = 0.5 # Délai d'attente de lecture en secondes
# Création de la fonction CRC16 Modbus
modbus_crc = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)
# Définition des commandes (sans CRC)
commands_without_crc = [
"010600000000", # Définir le mode de contrôle du variateur en mode position C00.00=0
"010611010000", # Définir le profil de position en positionnement absolu C11.01=0
"010603000002", # Définir la source de la commande de position sur incrément de pas C03.00=2
"0106030D0001", # Définir la vitesse de fonctionnement à 1 tr/min C03.0D=1
"0106030C1388", # Définir le déplacement à 5000 impulsions C03.0C=5000
"010604000022", # Configurer DI1 comme validation de l'incrément de pas de position C04.00=34 (0x22)
"010604110001", # Activer le moteur et démarrer le fonctionnement C04.11=1
"010604010001", # Déclencher la validation DI1 C04.01=1
"010604110000", # Commande d'arrêt d'urgence, désactiver le moteur C04.11=0
"010604010000" # Désactiver DI1 C04.01=0
]
# Descriptions des commandes
descriptions = [
"Définir le mode de contrôle du variateur en mode position (C00.00=0)",
"Définir le profil de position en positionnement absolu (C11.01=0)",
"Définir la source de la commande de position sur incrément de pas (C03.00=2)",
"Définir la vitesse de fonctionnement à 1 tr/min (C03.0D=1)",
"Définir le déplacement à 5000 impulsions (C03.0C=5000)",
"Configurer DI1 comme validation de l'incrément de pas de position (C04.00=34)",
"Activer le moteur et démarrer le fonctionnement (C04.11=1)",
"Déclencher la validation DI1 (C04.01=1)",
"Commande d'arrêt d'urgence, désactiver le moteur (C04.11=0)",
"Désactiver DI1 (C04.01=0)"
]
def calculate_crc(hex_str):
"""Calculer le CRC16 Modbus pour une chaîne hexadécimale"""
data = binascii.unhexlify(hex_str)
crc = modbus_crc(data)
# Retourner le CRC au format petit-boutiste (octet de poids faible en premier)
return bytes([crc & 0xFF, (crc >> 8) & 0xFF])
def format_hex(data):
"""Formater les données octet en chaîne hexadécimale"""
return ' '.join([f"{b:02X}" for b in data])
def send_modbus_command(ser, hex_cmd, description):
"""Envoyer une commande Modbus unique et traiter la réponse"""
try:
# Calculer le CRC et l'ajouter à la commande
crc_bytes = calculate_crc(hex_cmd)
full_cmd = binascii.unhexlify(hex_cmd) + crc_bytes
# Envoyer la commande
ser.write(full_cmd)
print(f"\nEnvoi de la commande : {description}")
print(f"Données : {format_hex(full_cmd)}")
# Attendre le traitement par l'appareil
time.sleep(0.3)
# Lire la réponse (la réponse Modbus RTU fait généralement 8 octets)
response = ser.read(8)
if response:
print(f"Réponse de l'appareil : {format_hex(response)}")
return True
else:
print("Erreur : Aucune réponse reçue !")
return False
except Exception as e:
print(f"Erreur lors de l'envoi de la commande : {str(e)}")
return False
def main():
# Créer la connexion série
try:
ser = serial.Serial(
port=PORT,
baudrate=BAUDRATE,
parity=PARITY,
stopbits=STOPBITS,
bytesize=BYTESIZE,
timeout=TIMEOUT
)
print(f"Connexion réussie au port série : {ser.name}\n")
except serial.SerialException as e:
print(f"Échec de l'ouverture du port série : {str(e)}")
return
except Exception as e:
print(f"Une erreur s'est produite : {str(e)}")
return
# Envoyer toutes les commandes
for i, (cmd, desc) in enumerate(zip(commands_without_crc, descriptions), 1):
print(f"Exécution de la commande {i}/{len(commands_without_crc)}")
success = send_modbus_command(ser, cmd, desc)
if not success:
print("Échec de l'exécution de la commande, arrêt du programme")
break
# Appliquer un délai plus long pour les commandes critiques
if "Activer" in desc or "Déclencher" in desc or "urgence" in desc:
time.sleep(1.0) # Délai plus long pour les commandes liées au mouvement
else:
time.sleep(0.5) # Délai standard pour les commandes de configuration
# Fermer le port série
ser.close()
print("\nToutes les commandes ont été traitées, port série fermé")
if __name__ == "__main__":
main()
Remarques :
a. Ce code utilise la bibliothèque crcmod pour effectuer la vérification CRC des commandes Modbus. Vous devez installer les bibliothèques requises avant d'exécuter le code :
pip install pyserial crcmod
b. Configurez le port COM (PORT) et la vitesse de transmission (BAUDRATE) corrects en fonction de la configuration réelle de votre appareil. Ajustez les paramètres de délai (time.sleep) en fonction du temps de réponse de votre appareil.
c. Les commandes Modbus de cet exemple s'appliquent uniquement aux servovariateurs de la série A6-RS de StepperOnline. Si vous utilisez d'autres variateurs — tels que les servovariateurs de la série DSY-RS, les servovariateurs de la série T6 ou les variateurs pas à pas de la série RS de StepperOnline — modifiez les commandes Modbus conformément au manuel du variateur concerné.