Python to powszechnie używany język programowania. Wysyłanie poleceń Modbus za pośrednictwem Pythona stanowi wygodny sposób sterowania pracą silnika. Poniżej znajduje się prosty przykład kodu do wysyłania poleceń Modbus przy użyciu Pythona. Polecenia Modbus pochodzą z artykułu Instrukcja obsługi RS485 serwosilnika A6, a konkretnie z rozdziału 2.3 „Ruch pozycjonowania absolutnego o 5000 impulsów (ustawienie domyślne: 10000 impulsów/obr., C00.02=10000)." Kod ten ma zastosowanie do serwonapędów StepperOnline z serii A6-RS i steruje silnikiem w trybie pozycjonowania absolutnego na 5000 impulsów.
Oto kod w języku Python:
import serial
import time
import binascii
from crcmod import crcmod
# Konfiguracja portu szeregowego - zmodyfikuj zgodnie z rzeczywistym urządzeniem
PORT = 'COM3' # Port szeregowy (Windows: 'COM3', Linux: '/dev/ttyUSB0')
BAUDRATE = 9600 # Prędkość transmisji (typowe wartości: 9600, 19200, 38400, 57600, 115200)
PARITY = serial.PARITY_NONE
STOPBITS = serial.STOPBITS_ONE
BYTESIZE = serial.EIGHTBITS
TIMEOUT = 0.5 # Limit czasu odczytu w sekundach
# Utworzenie funkcji Modbus CRC16
modbus_crc = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)
# Definicje poleceń (bez CRC)
commands_without_crc = [
"010600000000", # Ustaw tryb sterowania napędem na tryb pozycjonowania C00.00=0
"010611010000", # Ustaw profil pozycjonowania na pozycjonowanie absolutne C11.01=0
"010603000002", # Ustaw źródło polecenia pozycji na przyrost krokowy C03.00=2
"0106030D0001", # Ustaw prędkość roboczą na 1 obr./min C03.0D=1
"0106030C1388", # Ustaw przemieszczenie na 5000 impulsów C03.0C=5000
"010604000022", # Skonfiguruj DI1 jako włączenie przyrostu krokowego pozycji C04.00=34 (0x22)
"010604110001", # Włącz silnik i rozpocznij pracę C04.11=1
"010604010001", # Aktywuj włączenie DI1 C04.01=1
"010604110000", # Polecenie awaryjnego zatrzymania, wyłącz silnik C04.11=0
"010604010000" # Wyłącz DI1 C04.01=0
]
# Opisy poleceń
descriptions = [
"Ustaw tryb sterowania napędem na tryb pozycjonowania (C00.00=0)",
"Ustaw profil pozycjonowania na pozycjonowanie absolutne (C11.01=0)",
"Ustaw źródło polecenia pozycji na przyrost krokowy (C03.00=2)",
"Ustaw prędkość roboczą na 1 obr./min (C03.0D=1)",
"Ustaw przemieszczenie na 5000 impulsów (C03.0C=5000)",
"Skonfiguruj DI1 jako włączenie przyrostu krokowego pozycji (C04.00=34)",
"Włącz silnik i rozpocznij pracę (C04.11=1)",
"Aktywuj włączenie DI1 (C04.01=1)",
"Polecenie awaryjnego zatrzymania, wyłącz silnik (C04.11=0)",
"Wyłącz DI1 (C04.01=0)"
]
def calculate_crc(hex_str):
"""Oblicz Modbus CRC16 dla ciągu szesnastkowego"""
data = binascii.unhexlify(hex_str)
crc = modbus_crc(data)
# Zwróć CRC w formacie little-endian (najpierw młodszy bajt)
return bytes([crc & 0xFF, (crc >> 8) & 0xFF])
def format_hex(data):
"""Sformatuj dane bajtowe jako ciąg szesnastkowy"""
return ' '.join([f"{b:02X}" for b in data])
def send_modbus_command(ser, hex_cmd, description):
"""Wyślij pojedyncze polecenie Modbus i obsłuż odpowiedź"""
try:
# Oblicz CRC i dołącz do polecenia
crc_bytes = calculate_crc(hex_cmd)
full_cmd = binascii.unhexlify(hex_cmd) + crc_bytes
# Wyślij polecenie
ser.write(full_cmd)
print(f"\nWysyłanie polecenia: {description}")
print(f"Dane: {format_hex(full_cmd)}")
# Poczekaj na przetworzenie przez urządzenie
time.sleep(0.3)
# Odczytaj odpowiedź (odpowiedź Modbus RTU to zazwyczaj 8 bajtów)
response = ser.read(8)
if response:
print(f"Odpowiedź urządzenia: {format_hex(response)}")
return True
else:
print("Błąd: Nie otrzymano odpowiedzi!")
return False
except Exception as e:
print(f"Błąd podczas wysyłania polecenia: {str(e)}")
return False
def main():
# Utwórz połączenie szeregowe
try:
ser = serial.Serial(
port=PORT,
baudrate=BAUDRATE,
parity=PARITY,
stopbits=STOPBITS,
bytesize=BYTESIZE,
timeout=TIMEOUT
)
print(f"Pomyślnie połączono z portem szeregowym: {ser.name}\n")
except serial.SerialException as e:
print(f"Nie udało się otworzyć portu szeregowego: {str(e)}")
return
except Exception as e:
print(f"Wystąpił błąd: {str(e)}")
return
# Wyślij wszystkie polecenia
for i, (cmd, desc) in enumerate(zip(commands_without_crc, descriptions), 1):
print(f"Wykonywanie polecenia {i}/{len(commands_without_crc)}")
success = send_modbus_command(ser, cmd, desc)
if not success:
print("Wykonanie polecenia nie powiodło się, zakończenie programu")
break
# Zastosuj dłuższe opóźnienie dla poleceń krytycznych
if "Włącz" in desc or "Aktywuj" in desc or "awaryjnego" in desc:
time.sleep(1.0) # Dłuższe opóźnienie dla poleceń związanych z ruchem
else:
time.sleep(0.5) # Standardowe opóźnienie dla poleceń konfiguracyjnych
# Zamknij port szeregowy
ser.close()
print("\nWszystkie polecenia przetworzone, port szeregowy zamknięty")
if __name__ == "__main__":
main()
Uwagi:
a. Ten kod opiera się na bibliotece crcmod do wykonywania weryfikacji CRC poleceń Modbus. Przed uruchomieniem kodu należy zainstalować wymagane biblioteki:
pip install pyserial crcmod
b. Ustaw prawidłowy port COM (PORT) i prędkość transmisji (BAUDRATE) zgodnie z rzeczywistą konfiguracją urządzenia. Dostosuj parametry opóźnienia (time.sleep) w zależności od czasu odpowiedzi urządzenia.
c. Polecenia Modbus w tym przykładzie mają zastosowanie wyłącznie do serwonapędów StepperOnline z serii A6-RS. Jeśli używasz innych napędów — takich jak serwonapędy StepperOnline z serii DSY-RS, serwonapędy z serii T6 lub napędy krokowe z serii RS — zmodyfikuj polecenia Modbus zgodnie z instrukcją odpowiedniego napędu.