Peristaltikpumpen spielen eine entscheidende Rolle in der mikrofluidischen Forschung und medizinischen Diagnostik und bieten eine präzise Fluidsteuerung bei minimalem Kontaminationsrisiko. Unter den zahlreichen verfügbaren Optionen haben sich Longer-Pumpen, hergestellt von Longer Precision Pump Co., Ltd., einen Ruf für ihre Zuverlässigkeit, Präzision und Vielseitigkeit erworben.
Eines der herausragenden Merkmale von Longer-Peristaltikpumpen ist die Möglichkeit ihrer Fernsteuerung von einem Computer aus, wodurch Benutzer komplexe Pumpintervalle mit Schleifen, Pausen und variablen Flussraten mit größerer Flexibilität und Komfort ausführen können.
In diesem Blogbeitrag widmen wir uns der Steuerung von Longer-Peristaltikpumpen über das Modbus-RTU-Protokoll, einem weit verbreiteten seriellen Kommunikationsprotokoll, das das Senden von Befehlen an die Pumpe und das Empfangen von Antworten ermöglicht. Obwohl sich die spezifischen Details des Modbus-Protokolls zwischen verschiedenen Pumpenmodellen leicht unterscheiden können, verwenden wir für diesen Artikel die Peristaltikpumpe Longer L100-1S-2 als Referenzbeispiel. Darüber hinaus führen wir Sie durch Python-Beispiele und Code-Snippets, die Sie direkt kopieren und in Ihren eigenen Skripten verwenden können, um Ihre Pumpe mühelos zu steuern.
🚨 Sie können dieselben Konzepte und Codebeispiele auf andere Longer-Pumpen anwenden, wobei Sie einige Befehle an das spezifische Protokoll Ihres Pumpenmodells anpassen müssen.
Was benötigen Sie für die Kommunikation mit Ihrer Longer-Pumpe?
Um mit einer Longer-Peristaltikpumpe über das Modbus-RTU-Protokoll zu kommunizieren, benötigen Sie Folgendes:
- Eine Longer-Pumpe mit einem Pummpenkopf und einem tube Ihrer Wahl
- Ein RS485-Steuermodul, das in den DB15-Anschluss an der Rückseite der Pumpe eingesteckt wird
- Ein serielles Kabel, das das RS485-Steuermodul mit Ihrem Computer oder Gerät verbindet
- Eine Programmierplattform (in diesem Fall Python)
- Ein grundlegendes Verständnis des Modbus-RTU-Protokolls (wird unten 👇 erläutert).
Wie richtet man den Kommunikationsport ein?
Bevor Sie Daten an die Pumpe senden und von ihr empfangen können, müssen Sie den Kommunikationsport korrekt einrichten. Hier sind die zu befolgenden Schritte:
- Schließen Sie den DB15-Stecker an den DB15-Anschluss an der Rückseite der Pumpe an.
- Schalten Sie die Pumpe ein, rufen Sie über das Tastenfeld an der Vorderseite die Fernbedienungseinstellungen auf und stellen Sie den Fernsteuerungsmodus auf „COM“ ein 🕹️
- Stellen Sie sicher, dass die Kommunikationsparameter auf Ihrer Programmierplattform mit denen des L100-1S-2 übereinstimmen (wie in der Abbildung unten zu sehen ist), welche lauten:
- 1 Startbit
- 8 Datenbits
- Parität: P-n (keine Parität), P-O (ungerade Parität) oder P-E (gerade Parität)
- Stoppbit: S-1 (1 Stoppbit) oder S-2 (2 Stoppbits)
- Baudrate: 12 (1200 Bit/s), 24 (2400 Bit/s), 48 (4800 Bit/s), 96 (9600 Bit/s), 192 (19200 Bit/s) oder 384 (38400 Bit/s).
🚨 Die Kommunikation ist nur dann gültig, wenn auf dem Display der Pumpe der Betriebsbildschirm des Kommunikationssteuerungsmodus „COM“ angezeigt wird.
Grundlegendes zum Modbus-RTU-Protokoll
Das Modbus-RTU-Protokoll ist ein weit verbreiteter Kommunikationsstandard in Industrie- und Automatisierungssystemen zum Datenaustausch zwischen Geräten. Dank seiner Einfachheit und Robustheit eignet es sich hervorragend zur Steuerung von Geräten wie Longer Schlauchpumpen. In diesem Abschnitt befassen wir uns mit den Schlüsselelementen von Modbus RTU, einschließlich des Kommunikationsformats, der zyklischen Redundanzprüfung (CRC) und der Kommunikationseinstellungen. Wir untersuchen zudem die Struktur von Modbus-RTU-Meldungen sowie den Befehlssatz, der für die effektive Steuerung von Longer Pumpen verwendet wird.
Standard-Kommunikationsformat für Modbus RTU
Das Modbus-Protokoll ist ein gängiges Kommunikations-Framework, das Master-Slave-Interaktionen zwischen intelligenten Geräten ermöglicht. Eine von einem Master an einen Slave übertragene Modbus-Meldung enthält die Adresse des Slaves, einen spezifischen Befehl (wie das Lesen oder Schreiben in ein Register), die zugehörigen Daten sowie eine Prüfsumme zur Fehlererkennung.
Dieses Nachrichtenformat wird in der folgenden Tabelle beschrieben.
| Feld | Größe | Beschreibung |
|---|---|---|
| Slave-Adresse | 1 Byte | Adresse der Pumpe. Der Bereich liegt bei 1-32; 0 wird für die Broadcast-Kommunikation verwendet. |
| Funktionscode | 1 Byte | Befehl für das Slave-Gerät: - 03H: Halteregister lesen - 06H: Einzelnes Register schreiben - 10H: Mehrere Register schreiben |
| Datenbereich | 0 – 252 Bytes | Zu übertragende Daten (variable Länge) |
| CRC-Prüfung | 2 Bytes | Zyklische Redundanzprüfung zur Fehlererkennung: - CRC low (1 Byte): Niederes Byte der CRC - CRC high (1 Byte): Höheres Byte der CRC |
CRC-Prüfung mit CRC-16 in Python
CRC (Cyclic Redundancy Check) ist eine essenzielle Technik zur Erkennung von Übertragungsfehlern. Im Folgenden zeigen wir anhand von Python, wie CRC-16 implementiert wird – jene Variante, die im amerikanischen binären synchronen System verwendet wird. Beim CRC-16 verwendet der Fehlererkennungsalgorithmus ein Polynom G(X) = X16 + X15 + X2 + 1 zur Generierung der Prüfsumme. Dieses Polynom definiert die mathematischen Operationen, die während des CRC-Berechnungsprozesses an den Bits der Nachricht durchgeführt werden. Eine Übersicht des Algorithmus ist nachfolgend detailliert aufgeführt:
- Initialisieren Sie ein 16-Bit-Register mit dem Hexadezimalwert FFFF (nur Einsen), das als CRC-Register bezeichnet wird.
- Führen Sie eine XOR-Verknüpfung der ersten 8 Bytes der Nachricht mit dem niederwertigen Byte des CRC-Registers durch. Speichern Sie das Ergebnis wieder im CRC-Register.
- Verschieben Sie das CRC-Register um ein Bit nach rechts, wobei das höchstwertige Bit (MSB) auf Null gesetzt wird.
- Überprüfen Sie das niederwertigste Bit (LSB) des CRC-Registers:
- Wenn das LSB 0 ist, wiederholen Sie Schritt 3 (Schiebeoperation).
- Wenn das LSB 1 ist, führen Sie eine XOR-Verknüpfung des CRC-Registers mit dem Polynomwert 0xA001 (1010 0000 0000 0001) durch.
- Wiederholen Sie die Schritte 3 bis 4 für insgesamt 8 Verschiebungen, um jedes Byte zu verarbeiten.
- Wiederholen Sie die Schritte 2 bis 5 für jedes Byte in der Nachricht, bis alle Bytes verarbeitet wurden.
- Der finale Inhalt des CRC-Registers entspricht dem CRC-Wert.
Kommunikationseinstellungen
Jedes Datenbyte hat eine Struktur aus 1 Startbit, 8 Datenbits, 1 Paritätsbit und 1 oder 2 Stoppbits. Die Bits werden in der Reihenfolge vom Least Significant Bit (LSB) zum Most Significant Bit (MSB) übertragen.
Bei Ganzzahlen (2 Bytes) sind die Daten so angeordnet, dass das zweite Byte zuerst und das erste Byte danach folgt. Der Hexadezimalwert 2378H wird beispielsweise als 23H 78H gesendet. Bei langen Ganzzahlen und Gleitkommazahlen (4 Bytes) ist das vierte Byte zuerst angeordnet, gefolgt vom dritten, zweiten und ersten Byte.
Modbus-RTU-Nachrichtenrahmenformat
Die Nachrichtenrahmenrate von Modbus RTU entspricht der in der folgenden Tabelle beschriebenen.
| Feld | Größe | Beschreibung |
|---|---|---|
| Start | ≥ 3,5 Zeichen | Signalisiert den Beginn der Übertragung. |
| Adresse | 8 Bits | Adresse des Slave-Geräts. |
| Funktionscode | 8 Bits | Befehl für das Slave-Gerät. |
| Daten | N x 8 Bits | Zu übertragende Daten (variable Länge, N Bytes). |
| CRC-Prüfcode | 16 Bits | Zyklische Redundanzprüfung zur Fehlererkennung. |
| Ende | ≥ 3,5 Zeichen | Signalisiert das Ende der Übertragung. |
🚨 Stellen Sie sicher, że der Nachrichtenrahmen kontinuierlich ohne Leerzeiten zwischen den Zeichen von mehr als 1,5 Zeichenzeiten übertragen wird. Unvollständige Nachrichtenrahmen, die durch übermäßige Leerzeiten gekennzeichnet sind, sollten vom empfangenden Knoten verworfen werden.
Parameterschnitt
Die folgende Tabelle zeigt die wesentlichen Parameterseinstellungen für das Modell L100-1S-2. Diese Parameter können je nach Longer-Pumpenmodell variieren, was entweder auf die verfügbaren spezifischen Funktionen oder auf die eindeutige Adresse und die mit jedem Parameter verbundenen Beschreibungen zurückzuführen ist.
| Parameter | Adresse | Datentyp | Beschreibung |
|---|---|---|---|
| Geschwindigkeit | 0x01 | uint_16 | Bereich: 1 bis 10.000, entsprechend 0,01 U/min bis 100 U/min in Schritten von 0,01 U/min. Die Pumpe zeigt die Drehzahl in U/min an. Beispiel: 100 = 0,01 U/min, 10000 = 100 U/min. |
| Flussrate | 0x02 | uint_16 | Die oberen Bytes der Flussrate. Wird in Kombination mit dem unteren Byte der Flussrate verwendet. Die Einheit der Flussrate ist 1 nL/min. Beispiel: 02 FA F0 80H = 50,0 mL/min. |
| 0x03 | uint_16 | Die unteren Bytes der Flussrate. Wird in Kombination mit dem oberen Byte der Flussrate verwendet. Die Einheit der Flussrate ist 1 nL/min. Beispiel: 02 FA F0 80H = 50,0 mL/min. | |
| Pumpenstatus | 0x04 | uint_16 | Das untere Byte ist gültig. BIT0: Start/Stopp (0 = Stopp, 1 = Start). BIT1: Höchstgeschwindigkeit (0 = Normalgeschwindigkeit, 1 = Höchstgeschwindigkeit). BIT2: Drehzahl-/Flussratenanzeige. BIT3: Reserviert. BIT4: Drehrichtung (0 = im Uhrzeigersinn, 1 = gegen den Uhrzeigersinn) |
| Pumpenadresse | 0x05 | uint_16 | Das untere Byte ist gültig. Gültiger Bereich: 1-32 |
| Baudrate | 0x06 | uint_16 | Das untere Byte ist gültig. 01H: 1200 bps 02H: 2400 bps 03H: 4800 bps 04H: 9600 bps 05H: 19200 bps 06H: 38400 bps |
| Parität | 0x07 | uint_16 | Das untere Byte ist gültig. 01H: Keine Parität 02H: Ungerade Parität 03H: Gerade Parität |
| Stoppbit | 0x08 | uint_16 | Das Low-Byte ist gültig. 01H: 1 Stoppbit 02H: 2 Stoppbits |
| Tastensperre | 0x09 | uint_16 | Low-Byte: Aktiviert die Funktion der Tastensperre. 01H: Deaktiviert 02H: Aktiviert High-Byte: Verzögerung vor dem Sperren. 00H: 30s 01H: 60s 02H: 180s 03H: 300s 04H: 480s 05H: 600s |
💡 Wichtige Hinweise:
- Das Longer Modbus RTU-Protokoll unterstützt ausschließlich die Funktionscodes 03H (Register lesen), 06H (einzelnes Register schreiben) und 10H (mehrere Register schreiben).
- Bei Verwendung des Funktionscodes 06H arbeitet die Pumpe basierend auf dem zuletzt empfangenen Befehl, wobei die Drehzahl als Drehzahlparameter und die Flussrate als Flussratenparameter angezeigt wird.
- Um die Flussrate einzustellen, müssen sowohl das High-Byte als auch das Low-Byte gleichzeitig angegeben werden. Die Einheit für die Flussrate beträgt 1 nL/min (z. B. entspricht der Befehl 02 FA F0 80H 50,0 mL/min).
- Wenn die Flussrate oder die Drehzahl den zulässigen Bereich überschreitet, zeigt die Pumpe den Maximal- oder Minimalwert an, ohne eine Warnung auszugeben.
Umrechnungsrelation zwischen Flussrate und Drehzahl
Das Verhältnis zwischen Flussrate und Drehzahl für die L100-1S-2 lässt sich durch folgende Gleichung beschreiben: Q = V x f
Wobei Q die Flussrate in mL/min, V die Drehzahl in U/min (rpm) und f der in mL/U gemessene Flussratenkoeffizient ist, der standardmäßig auf 1 gesetzt ist.
Der Standardwert f = 1 weist unter Standardbedingungen auf eine direkte Korrelation zwischen Drehzahl und Flussrate hin. Diese Einfachheit macht es für Bediener unkompliziert, die Pumpeinstellungen für ihre spezifischen Anwendungen zu optimieren.
Wie kommuniziert man mit der L100-1S-2 über Python?
In diesem Abschnitt wird eine grundlegende Python-Bibliothek vorgestellt, die entwickelt wurde, um die Kommunikation und Steuerung von Longer Peristaltikpumpen über das Modbus RTU-Protokoll zu erleichtern. Sie kapselt wesentliche Funktionalitäten wie das Einstellen von Pumpendrehzahl, Flussrate und Drehrichtung sowie das einfache Starten und Stoppen der Pumpe.
Diese Bibliothek wurde speziell basierend auf dem Protokoll der Longer L100-1S-2 Peristaltikpumpe geschrieben und dient als modifizierbares Beispiel. Durch Anpassen der Befehle und Parameter bei Bedarf können Benutzer sie an das Modbus RTU-Protokoll ihres spezifischen Longer Pumpenmodells anpassen.
🚨🚨🚨 Wichtiger Hinweis
- When viewing this code, please be aware that <, >, and & symbols might not display correctly due to formatting issues. These should appear as standard Python code syntax, so make sure to interpret < as <, > as >, and & as &.
'''
-------------------------------------------------------------
Longer Peristaltic Pump Control Library Using Modbus Protocol
-------------------------------------------------------------
'''
import serial
import time
#------------------------------------------------------#
# LIBRARY MANAGING THE COMMUNICATION WITH THE PUMP #
#------------------------------------------------------#
class Longer_Pump:
# Initialize the class with serial communication parameters
def __init__(self, port, address=1, baudrate=9600, parity=serial.PARITY_NONE, bytesize=8, stopbits=1, timeout=1):
"""
Parameters:
port (str): The COM port for serial communication.
address (int): Modbus address of the pump (default is 1).
baudrate (int): The baud rate (default is 9600).
parity (str): Parity for serial communication (default is none).
bytesize (int): Number of data bits (default is 8).
stopbits (int): Number of stop bits (default is 1).
timeout (int): Timeout for serial communication (default is 1s).
"""
self.ser = serial.Serial(port=port, baudrate=baudrate, parity=parity, bytesize=bytesize, stopbits=stopbits, timeout=timeout)
self.address = address
# Open the serial port for communication with the pump
def connect(self):
if not self.ser.is_open:
self.ser.open()
# Close the serial port to end communication with the pump
def disconnect(self):
if self.ser.is_open:
self.ser.close()
# Calculate the CRC for Modbus communication
def _calculate_crc(self, data):
"""
Parameters:
data (bytearray): The data for which to calculate the CRC.
Returns:
bytes: The calculated CRC as a 2-byte value.
"""
crc = 0xFFFF
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 0x0001:
crc >>= 1
crc ^= 0xA001
else:
crc >>= 1
return crc.to_bytes(2, byteorder='little')
# Send a command to the pump using the Modbus protocol
def _send_command(self, function_code, register_address, data):
"""
Parameters:
function_code (int): e.g., 0x03 for read, 0x06 for write.
register_address (int): to read from or write to.
data (list or int): to be sent (for writing registers).
Returns:
bytes: The response from the pump.
"""
# Prepare the command payload for Modbus
payload = bytearray([self.address, function_code])
payload.extend(register_address.to_bytes(2, byteorder='big'))
if isinstance(data, list):
# For multi-register commands (function code 0x10)
number_of_registers = len(data)
payload.extend(number_of_registers.to_bytes(2, byteorder='big'))
payload.append(len(data) * 2) # Byte count for the data
for value in data:
payload.extend(value.to_bytes(2, byteorder='big'))
else:
# For single-register commands (function code 0x06)
payload.extend(data.to_bytes(2, byteorder='big'))
# Append CRC
crc = self._calculate_crc(payload)
payload.extend(crc)
# Send the command to the pump
self.ser.write(payload)
response = self.ser.read(8) # Adjust this based on expected response length
return response
# Set the pump speed in RPM (0.01 RPM increments)
def set_speed(self, speed_rpm):
"""
Parameters:
speed_rpm (float): The desired speed in RPM.
"""
speed_value = int(speed_rpm * 100) # 0.01 RPM increments
response = self._send_command(0x06, 0x01, speed_value)
print(f"Set speed response: {response.hex()}")
# Set the pump flow rate in mL/min (combined high/low bytes)
def set_flow_rate(self, flow_rate_ml_min):
"""
Parameters:
flow_rate_ml_min (float): The desired flow rate in mL/min.
"""
flow_rate_nl_min = int(flow_rate_ml_min * 1_000_000) # Convert mL/min to nL/min
high_byte = (flow_rate_nl_min >> 16) & 0xFFFF
low_byte = flow_rate_nl_min & 0xFFFF
response = self._send_command(0x10, 0x02, [high_byte, low_byte])
print(f"Set flow rate response: {response.hex()}")
# Start the pump and set the display mode to either 'speed' (RPM) or 'flow_rate' (mL/min)
def start(self, display_mode="speed"):
"""
Parameters:
display_mode (str): 'speed' or 'flow_rate'.
"""
if display_mode == "speed":
pump_state = 0b00000001 # Run + Display Speed
elif display_mode == "flow_rate":
pump_state = 0b00000101 # Run + Display Flow Rate
else:
raise ValueError("Invalid display_mode. Use 'speed' or 'flow_rate'.")
response = self._send_command(0x06, 0x04, pump_state)
print(f"Start pump response: {response.hex()}")
# Stop the pump and set the display mode to either 'speed' (RPM) or 'flow_rate' (mL/min)
def stop(self, display_mode="speed"):
"""
Parameters:
display_mode (str): 'speed' or 'flow_rate'.
"""
if display_mode == "speed":
pump_state = 0b00000000 # Stop + Display Speed
elif display_mode == "flow_rate":
pump_state = 0b00000100 # Stop + Display Flow Rate
else:
raise ValueError("Invalid display_mode. Use 'speed' or 'flow_rate'.")
response = self._send_command(0x06, 0x04, pump_state)
print(f"Stop pump response: {response.hex()}")
# Set the pump direction (CW or CCW)
def set_direction(self, direction):
"""
Parameters:
direction (str): 'CW' for clockwise, 'CCW' for counter-clockwise.
"""
direction_value = 0x0010 if direction.upper() == 'CCW' else 0x0000
response = self._send_command(0x06, 0x04, direction_value)
print(f"Set direction response: {response.hex()}")
# Custom function: Run the pump at the specified speed for a certain amount of time and then stop
def run(self, speed_rpm, run_time_s, direction='CW'):
"""
Parameters:
speed_rpm (float): The speed at which to run the pump in RPM.
run_time_s (int): The time to run the pump in seconds.
direction (str): 'CW' or 'CCW'.
"""
try:
self.set_speed(speed_rpm)
self.set_direction(direction)
self.start(display_mode="speed")
# Run the pump for the specified time
for remaining_time in range(run_time_s, 0, -1):
print(f"Running... {remaining_time} seconds remaining")
time.sleep(1)
finally:
self.stop(display_mode="speed")
#-----------------------------------------------------------------------#
# EXAMPLES ON HOW TO USE THE DEFINED CLASS TO CONTROL A LONGER PUMP #
#-----------------------------------------------------------------------#
pump = Longer_Pump(port='COM7', address=1) # Adjust port and address as needed
pump.connect()
# Run the pump at 40 rpm
pump.set_speed(40.00) # Speed in RPM
pump.start(display_mode="speed")
pump.stop(display_mode="speed")
# Set direction to counter-clockwise
pump.set_direction('CCW')
# Run the pump in flow rate mode at 35 mL/min
pump.set_flow_rate(35) # Flow rate in mL/min
pump.start(display_mode="flow_rate")
pump.stop(display_mode="flow_rate") # Stop the pump
# Run the pump counter-clockwise at 10 RPM for 25 seconds
pump.run(speed_rpm=10.0, run_time_s=25, direction='CCW')
# Disconnect the pump
pump.disconnect()
Fazit
In diesem Blogbeitrag haben wir behandelt, wie Longer Peristaltikpumpen über das Modbus RTU-Protokoll gesteuert werden, Einblicke in das Kommunikationsformat gegeben und eine Python-Bibliothek bereitgestellt, die Ihnen den Einstieg erleichtert. Unabhängig davon, ob Sie mit dem Modell L100-1S-2 arbeiten oder den Code für eine andere Pumpe anpassen, hoffen wir, dass dieser Leitfaden eine wertvolle Ressource darstellt.
Seien Sie gespannt auf weitere Tutorials und praktische Anwendungen in zukünftigen Beiträgen. Bis dahin viel Erfolg beim Pumpen und Programmieren! 💻
📧 Bei Fragen oder Anmerkungen können Sie uns gerne kontaktieren unter support@darwin-microfluidics.com.

