Le pompe peristaltiche svolgono un ruolo cruciale nella ricerca microfluidica e nella diagnostica medica, offrendo un controllo preciso dei fluidi con un rischio minimo di contaminazione. Tra le molte opzioni disponibili, le pompe Longer, prodotte da Longer Precision Pump Co., Ltd., si sono guadagnate una reputazione di affidabilità, precisione e versatilità.
Una delle caratteristiche distintive delle pompe peristaltiche Longer è la capacità di essere controllate a distanza da un computer, consentendo agli utenti di eseguire programmi di pompaggio complessi che includono cicli, pause e portate variabili con maggiore flessibilità e praticità.
In questo articolo del blog, analizzeremo il controllo delle pompe peristaltiche Longer tramite il protocollo Modbus RTU, un protocollo di comunicazione seriale ampiamente utilizzato che consente di inviare comandi e ricevere risposte dalla pompa. Sebbene i dettagli del protocollo Modbus possano variare leggermente tra i diversi modelli di pompa, per questo articolo useremo come esempio di riferimento la pompa peristaltica Longer L100-1S-2. Vi guideremo inoltre attraverso esempi in Python e frammenti di codice, che potrete copiare direttamente e utilizzare nei vostri script per controllare agevolmente la pompa.
🚨 È possibile applicare gli stessi concetti ed esempi di codice ad altre pompe Longer, apportando modifiche ad alcuni comandi in base allo specifico protocollo del proprio modello di pompa.
Di cosa hai bisogno per comunicare con la tua pompa Longer?
Per comunicare con una pompa peristaltica Longer utilizzando il protocollo Modbus RTU, è necessario disporre di quanto segue:
- Una pompa Longer dotata di una testata e di un tube a scelta
- Un modulo di controllo RS485 che si collega alla porta DB15 sul retro della pompa
- Un cavo seriale che collega il modulo di controllo RS485 al computer o al dispositivo
- Una piattaforma di programmazione (Python in questo caso)
- Una comprensione di base del protocollo Modbus RTU (spiegato di seguito 👇).
Come configurare la porta di comunicazione?
Prima di poter iniziare a inviare e ricevere dati dalla pompa, è necessario configurare correttamente la porta di comunicazione. Ecco i passaggi da seguire:
- Collegare il connettore DB15 alla porta DB15 sul retro della pompa
- Accendere la pompa e utilizzare il tastierino sul pannello frontale per accedere all'interfaccia di configurazione del controllo remoto, impostando la modalità di controllo remoto su "COM" 🕹️
- Assicuratevi che i parametri di comunicazione sulla vostra piattaforma di programmazione corrispondano a quelli del modello L100-1S-2 (come illustrato nella figura sottostante), ovvero:
- 1 bit di start
- 8 bit di dati
- Parità: P-n (nessuna parità), P-O (parità dispari) o P-E (parità pari)
- Bit di stop: S-1 (1 bit di stop) o S-2 (2 bit di stop)
- Baud rate: 12 (1200 bit/s), 24 (2400 bit/s), 48 (4800 bit/s), 96 (9600 bit/s), 192 (19200 bit/s) o 384 (38400 bit/s).
🚨 La comunicazione è valida esclusivamente quando la pompa mostra la schermata operativa della modalità di controllo della comunicazione "COM".
Comprendere il protocollo Modbus RTU
Il protocollo Modbus RTU è uno standard di comunicazione ampiamente adottato nei sistemi industriali e di automazione per lo scambio di dati tra dispositivi. Rinomato per la sua semplicità e robustezza, risulta ideale per il controllo di apparecchiature quali le pompe peristaltiche Longer. In questa sezione, analizzeremo gli elementi chiave del Modbus RTU, tra cui il formato di comunicazione, il controllo di ridondanza ciclica (CRC) e le impostazioni di comunicazione. Esploreremo inoltre la struttura dei messaggi Modbus RTU e il set di comandi utilizzato per controllare efficacemente le pompe Longer.
Formato di comunicazione standard Modbus RTU
Il protocollo Modbus è un framework di comunicazione comunemente impiegato che agevola le interazioni master-slave tra dispositivi intelligenti. Un messaggio Modbus trasmesso da un master a uno slave comprende l'indirizzo dello slave, un comando specifico (come la lettura o la scrittura su un registro), i dati associati e un codice di controllo per la verifica degli errori.
Questo formato di messaggio è descritto nella tabella sottostante.
| Campo | Dimensione | Descrizione |
|---|---|---|
| Indirizzo Slave | 1 Byte | Indirizzo della pompa. L'intervallo è compreso tra 1 e 32; lo 0 è riservato alla comunicazione in broadcast. |
| Codice funzione | 1 Byte | Istruzione per il dispositivo slave: - 03H: Lettura registri di mantenimento (Holding Registers) - 06H: Scrittura registro singolo - 10H: Scrittura registri multipli |
| Area dati | 0 – 252 Byte | Dati da trasmettere (lunghezza variabile) |
| Controllo CRC | 2 Byte | Controllo di ridondanza ciclica (CRC) per il rilevamento degli errori: - CRC low (1 Byte): Byte inferiore del CRC - CRC high (1 Byte): Byte superiore del CRC |
Controllo CRC con CRC-16 in Python
Il CRC (Cyclic Redundancy Check) è una tecnica fondamentale per il rilevamento degli errori nella trasmissione dei dati. Di seguito, mostreremo come implementare il CRC-16, utilizzato nel sistema sincrono binario americano, tramite Python. Nel CRC-16, l'algoritmo di rilevamento degli errori impiega un polinomio G(X) = X16 + X15 + X2 + 1 per generare il checksum. Questo polinomio definisce le operazioni matematiche eseguite sui bit del messaggio durante il processo di calcolo del CRC. Una panoramica dell'algoritmo è dettagliata di seguito:
- Inizializzare un registro a 16 bit con il valore esadecimale FFFF (tutti uno), indicato come registro CRC.
- Eseguire uno XOR tra i primi 8 byte del messaggio e il byte inferiore del registro CRC. Memorizzare nuovamente il risultato nel registro CRC.
- Scorrere il registro CRC di un bit verso destra, impostando a zero il bit più significativo (MSB).
- Verificare il bit meno significativo (LSB) del registro CRC:
- Se l'LSB è 0, ripetere il passaggio 3 (operazione di shift).
- Se l'LSB è 1, eseguire uno XOR tra il registro CRC e il valore polinomiale 0xA001 (1010 0000 0000 0001).
- Ripetere i passaggi da 3 a 4, per un totale di 8 shift, per elaborare ciascun byte.
- Ripetere i passaggi da 2 a 5 per ogni byte nel messaggio finché tutti i byte non saranno stati elaborati.
- Il contenuto finale del registro CRC corrisponde al valore CRC.
Impostazioni di comunicazione
Ciascun byte di dati presenta una struttura composta da 1 bit di start, 8 bit di dati, 1 bit di parità e 1 o 2 bit di stop. I bit vengono trasmessi in ordine, dal bit meno significativo (LSB) al bit più significativo (MSB).
Per i numeri interi (2 byte), i dati sono disposti con il secondo byte per primo, seguito dal primo byte. Ad esempio, il valore esadecimale 2378H viene trasmesso come 23H 78H. Per i numeri interi lunghi e i float (4 byte), i dati sono disposti con il quarto byte per primo, seguito dal terzo, dal secondo e dal primo byte.
Formato del frame di messaggi Modbus RTU
Il frame rate dei messaggi Modbus RTU è quello descritto nella tabella sottostante.
| Campo | Dimensione | Descrizione |
|---|---|---|
| Start | ≥ 3,5 caratteri | Indica l'inizio della trasmissione. |
| Indirizzo | 8 Bit | Indirizzo del dispositivo slave. |
| Codice funzione | 8 Bit | Istruzione per il dispositivo slave. |
| Dati | N x 8 bit | Dati da trasmettere (lunghezza variabile, N byte). |
| Codice di controllo CRC | 16 bit | Controllo di ridondanza ciclica per il rilevamento degli errori. |
| Fine | ≥ 3,5 caratteri | Indica la fine della trasmissione. |
🚨 Assicurarsi che il frame del messaggio venga trasmesso in modo continuo, senza intervalli di inattività tra i caratteri superiori a 1,5 tempi carattere. I frame di messaggio incompleti, indicati da un tempo di inattività eccessivo, devono essere scartati dal nodo ricevente.
Impostazione dei parametri
La tabella seguente riassume le impostazioni dei parametri essenziali per il modello L100-1S-2. Tali parametri possono variare tra i diversi modelli di pompe Longer, a causa delle specifiche funzioni disponibili o degli indirizzi e delle descrizioni univoci associati a ciascun parametro.
| Parametro | Indirizzo | Tipo di dato | Descrizione |
|---|---|---|---|
| Velocità | 0x01 | uint_16 | Range: 1-10.000, corrispondente da 0,01 rpm a 100 rpm, con incrementi di 0,01 rpm. La pompa visualizza la velocità in rpm. Esempio: 100 = 0,01 rpm, 10000 = 100 rpm. |
| Portata | 0x02 | uint_16 | I byte alti della portata. Utilizzati insieme al byte basso della portata. L'unità di misura della portata è 1 nL/min. Esempio: 02 FA F0 80H = 50,0 mL/min. |
| 0x03 | uint_16 | I byte bassi della portata. Utilizzati insieme al byte alto della portata. L'unità di misura della portata è 1 nL/min. Esempio: 02 FA F0 80H = 50,0 mL/min. | |
| Stato della pompa | 0x04 | uint_16 | Il byte basso è valido. BIT0: Avvio/Arresto (0 = arresto, 1 = avvio). BIT1: Massima velocità (0 = velocità normale, 1 = massima velocità). BIT2: Visualizzazione velocità/portata. BIT3: Riservato. BIT4: Direzione (0 = CW, 1 = CCW) |
| Indirizzo della pompa | 0x05 | uint_16 | Il byte basso è valido. Intervallo valido: 1-32 |
| Baud Rate | 0x06 | uint_16 | Il byte basso è valido. 01H: 1200 bps 02H: 2400 bps 03H: 4800 bps 04H: 9600 bps 05H: 19200 bps 06H: 38400 bps |
| Parità | 0x07 | uint_16 | Il byte basso è valido. 01H: Nessuna parità 02H: Parità dispari 03H: Parità pari |
| Bit di stop | 0x08 | uint_16 | Il byte basso è valido. 01H: 1 bit di stop 02H: 2 bit di stop |
| Blocco della tastiera | 0x09 | uint_16 | Byte basso: Abilita la funzione di blocco della tastiera. 01H: Disabilitato 02H: Abilitato Byte alto: Ritardo prima del blocco. 00H: 30s 01H: 60s 02H: 180s 03H: 300s 04H: 480s 05H: 600s |
💡 Note importanti:
- Il protocollo Modbus RTU di Longer supporta esclusivamente i codici funzione 03H (lettura registri), 06H (scrittura registro singolo) e 10H (scrittura registri multipli).
- Quando si utilizza il codice funzione 06H, la pompa opera in base all'ultimo comando ricevuto, mostrando la velocità tramite un apposito parametro e la portata tramite un parametro di portata.
- Per impostare la portata, è necessario specificare simultaneamente sia il byte alto che il byte basso. L'unità di misura per la portata è 1 nL/min (ad es., il comando 02 FA F0 80H corrisponde a 50.0 mL/min).
- Se la portata o la velocità superano l'intervallo consentito, la pompa visualizza il valore massimo o minimo senza emettere alcun avviso.
Relazione di conversione tra portata e velocità
La relazione tra portata e velocità per il modello L100-1S-2 può essere descritta dall'equazione: Q = V x f
Dove Q rappresenta la portata in mL/min, V indica la velocità in rpm e f è il coefficiente di portata misurato in mL/r, il cui valore predefinito è 1.
Il valore predefinito f = 1 indica una correlazione diretta tra velocità e portata in condizioni standard. Tale semplicità agevola gli operatori nell'ottimizzazione delle impostazioni della pompa per le loro specifiche applicazioni.
Come comunicare con il modello L100-1S-2 utilizzando Python?
In questa sezione viene presentata una libreria Python di base progettata per facilitare la comunicazione e il controllo delle pompe peristaltiche Longer tramite il protocollo Modbus RTU. Essa racchiude funzionalità essenziali, come l'impostazione della velocità della pompa, della portata e della direzione, oltre ad avviare e arrestare la pompa con semplicità.
Questa libreria è scritta specificamente sulla base del protocollo della pompa peristaltica Longer L100-1S-2 e funge da esempio modificabile. Modificando i comandi e i parametri secondo necessità, gli utenti possono adattarla al protocollo Modbus RTU del proprio modello specifico di pompa Longer.
🚨🚨🚨 Nota importante
- 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()
Conclusione
In questo post del blog abbiamo trattato come controllare le pompe peristaltiche Longer tramite il protocollo Modbus RTU, offrendo approfondimenti sul formato di comunicazione e fornendo una libreria Python per iniziare subito. Che stiate lavorando con il modello L100-1S-2 o adattando il codice per un'altra pompa, ci auguriamo che questa guida costituisca una risorsa preziosa.
Rimanete sintonizzati per ulteriori tutorial e applicazioni pratiche nei prossimi post. Fino ad allora, buon lavoro con il pompaggio e la programmazione! 💻
📧 Per qualsiasi domanda o riscontro, non esitate a contattarci all'indirizzo support@darwin-microfluidics.com.

