Las bombas peristálticas desempeñan un papel crucial en la investigación microfluídica y el diagnóstico médico, ofreciendo un control preciso de fluidos con un riesgo mínimo de contaminación. Entre las muchas opciones disponibles, las bombas Longer, fabricadas por Longer Precision Pump Co., Ltd., se han ganado una reputación por su fiabilidad, precisión y versatilidad.
Una de las características más destacadas de las bombas peristálticas Longer es su capacidad para ser controladas de forma remota desde un ordenador, lo que permite a los usuarios ejecutar programas de bombeo complejos que implican bucles, pausas y caudales variables con mayor flexibilidad y comodidad.
En esta entrada del blog, profundizaremos en el control de las bombas peristálticas Longer utilizando el protocolo Modbus RTU, un protocolo de comunicación serie ampliamente utilizado que permite enviar comandos y recibir respuestas de la bomba. Aunque los detalles específicos del protocolo Modbus pueden variar ligeramente entre los diferentes modelos de bombas, para este artículo utilizaremos la bomba peristáltica Longer L100-1S-2 como ejemplo de referencia. También le guiaremos a través de ejemplos en Python y fragmentos de código que puede copiar directamente y utilizar en sus propios scripts para controlar fácilmente su bomba.
🚨 Puede aplicar los mismos conceptos y ejemplos de código a otras bombas Longer, realizando ajustes en algunos comandos según el protocolo específico de su modelo de bomba.
¿Qué necesita para comunicarse con su bomba Longer?
Para comunicarse con una bomba peristáltica Longer utilizando el protocolo Modbus RTU, necesitará lo siguiente:
- Una bomba Longer con un cabezal de bomba y el tube de su elección
- Un módulo de control RS485 que se conecta al puerto DB15 de la parte posterior de la bomba
- Un cable serie que conecta el módulo de control RS485 a su ordenador o dispositivo
- Una plataforma de programación (Python en este caso)
- Una comprensión básica del protocolo Modbus RTU (explicada a continuación 👇).
¿Cómo configurar el puerto de comunicación?
Antes de comenzar a enviar y recibir datos de la bomba, debe configurar el puerto de comunicación correctamente. Siga estos pasos:
- Conecte el conector DB15 al puerto DB15 situado en la parte posterior de la bomba
- Encienda la bomba y utilice el teclado en el panel frontal de la misma para acceder a la interfaz de configuración de control remoto y establecer el modo de control remoto en "COM" 🕹️
- Asegúrese de que los parámetros de comunicación de su plataforma de programación coincidan con los de la L100-1S-2 (como se puede ver en la siguiente figura), los cuales son:
- 1 bit de inicio
- 8 bits de datos
- Paridad: P-n (sin paridad), P-O (paridad impar) o P-E (paridad par)
- Bit de parada: S-1 (1 bit de parada) o S-2 (2 bits de parada)
- Velocidad en baudios: 12 (1200 bits/s), 24 (2400 bits/s), 48 (4800 bits/s), 96 (9600 bits/s), 192 (19200 bits/s) o 384 (38400 bits/s).
🚨 La comunicación es válida únicamente cuando la bomba muestra la pantalla de ejecución del modo de control de comunicación "COM".
Comprender el protocolo Modbus RTU
El protocolo Modbus RTU es un estándar de comunicación ampliamente adoptado que se utiliza en sistemas industriales y de automatización para intercambiar datos entre dispositivos. Conocido por su simplicidad y solidez, es ideal para controlar equipos como las bombas peristálticas Longer. En esta sección, profundizaremos en los elementos clave de Modbus RTU, incluido su formato de comunicación, la comprobación de redundancia cíclica (CRC) y la configuración de comunicación. También exploraremos la estructura de los mensajes Modbus RTU y el conjunto de comandos utilizado para controlar eficazmente las bombas Longer.
Formato de comunicación estándar de Modbus RTU
El protocolo Modbus es un marco de comunicación de uso común que facilita las interacciones maestro-esclavo entre dispositivos inteligentes. Un mensaje Modbus transmitido de un maestro a un esclavo incluye la dirección del esclavo, un comando específico (como leer o escribir en un registro), los datos adjuntos y una suma de verificación para la comprobación de errores.
El formato de este mensaje se describe en la tabla siguiente.
| Campo | Tamaño | Descripción |
|---|---|---|
| Dirección del esclavo | 1 Byte | Dirección de la bomba. El rango es de 1 a 32; el 0 se utiliza para la comunicación de difusión (broadcast). |
| Código de función | 1 Byte | Instrucción para el dispositivo esclavo: - 03H: Leer registros de retención - 06H: Escribir en un solo registro - 10H: Escribir en múltiples registros |
| Área de datos | 0 – 252 Bytes | Datos a transmitir (longitud variable) |
| Comprobación CRC | 2 Bytes | Comprobación de redundancia cíclica para la detección de errores: - CRC bajo (1 byte): Byte inferior del CRC - CRC alto (1 byte): Byte superior del CRC |
Comprobación CRC con CRC-16 en Python
El CRC (Comprobación de redundancia cíclica) es una técnica fundamental para detectar errores en la transmisión de datos. A continuación, mostraremos cómo implementar CRC-16, el utilizado en el sistema síncrono binario americano, utilizando Python. En CRC-16, el algoritmo de detección de errores emplea un polinomio G(X) = X16 + X15 + X2 + 1 para generar la suma de comprobación. Este polinomio define las operaciones matemáticas realizadas en los bits del mensaje durante el proceso de cálculo del CRC. A continuación se detalla una descripción general del algoritmo:
- Inicialice un registro de 16 bits con el valor hexadecimal FFFF (todos en uno), denominado registro CRC.
- Realice una operación XOR entre los primeros 8 bytes del mensaje y el byte bajo del registro CRC. Almacene el resultado nuevamente en el registro CRC.
- Desplace el registro CRC un bit hacia la derecha, con el bit más significativo (MSB) establecido en cero.
- Compruebe el bit menos significativo (LSB) del registro CRC:
- Si el LSB es 0, repita el paso 3 (operación de desplazamiento).
- Si el LSB es 1, realice una operación XOR entre el registro CRC y el valor polinómico 0xA001 (1010 0000 0000 0001).
- Repita los pasos 3 a 4, para un total de 8 desplazamientos, para procesar cada byte.
- Repita los pasos 2 a 5 para cada byte del mensaje hasta que se hayan procesado todos los bytes.
- El contenido final del registro CRC es el valor CRC.
Configuración de comunicación
Cada byte de datos presenta una estructura compuesta por 1 bit de inicio, 8 bits de datos, 1 bit de paridad y 1 o 2 bits de parada. Los bits se transmiten en orden desde el bit menos significativo (LSB) hasta el bit más significativo (MSB).
Para los enteros (2 bytes), los datos se organizan colocando primero el segundo byte seguido del primer byte. Por ejemplo, el valor hexadecimal 2378H se transmite como 23H 78H. Para los enteros largos y los números de punto flotante (4 bytes), los datos se organizan colocando primero el cuarto byte, seguido del tercero, el segundo y el primer byte.
Formato de trama de mensajes Modbus RTU
La tasa de tramas de mensajes Modbus RTU es la descrita en la tabla siguiente.
| Campo | Tamaño | Descripción |
|---|---|---|
| Inicio | ≥ 3.5 caracteres | Indica el inicio de la transmisión. |
| Dirección | 8 bits | Dirección del dispositivo esclavo. |
| Código de función | 8 bits | Instrucción para el dispositivo esclavo. |
| Datos | N x 8 bits | Datos a transmitir (longitud variable, N bytes). |
| Código de verificación CRC | 16 bits | Comprobación de redundancia cíclica para la detección de errores. |
| Fin | ≥ 3.5 caracteres | Indica el fin de la transmisión. |
🚨 Asegúrese de que la trama de mensajes se transmita de forma continua, sin espacios de inactividad entre caracteres superiores a 1.5 tiempos de carácter. Las tramas de mensajes incompletas, indicadas por un espacio de inactividad excesivo, deben ser descartadas por el nodo receptor.
Configuración de parámetros
La tabla siguiente detalla la configuración de parámetros esencial para el modelo L100-1S-2. Estos parámetros pueden variar entre los distintos modelos de bombas Longer, ya sea debido a las funciones específicas disponibles o a la dirección y las descripciones únicas asociadas a cada parámetro.
| Parámetro | Dirección | Tipo de datos | Descripción |
|---|---|---|---|
| Velocidad | 0x01 | uint_16 | Rango: de 1 a 10 000, correspondiente de 0,01 rpm a 100 rpm, en incrementos de 0,01 rpm. La bomba muestra la velocidad en rpm. Ejemplo: 100 = 0,01 rpm, 10000 = 100 rpm. |
| Caudal | 0x02 | uint_16 | Los bytes altos del caudal. Se utilizan junto con el byte bajo del caudal. La unidad de caudal es 1 nL/min. Ejemplo: 02 FA F0 80H = 50,0 mL/min. |
| 0x03 | uint_16 | Los bytes bajos del caudal. Se utilizan junto con el byte alto del caudal. La unidad de caudal es 1 nL/min. Ejemplo: 02 FA F0 80H = 50,0 mL/min. | |
| Estado de la bomba | 0x04 | uint_16 | El byte bajo es válido. BIT0: Marcha/Parada (0 = parada, 1 = marcha). BIT1: Velocidad máxima (0 = velocidad normal, 1 = velocidad máxima). BIT2: Visualización de velocidad/caudal. BIT3: Reservado. BIT4: Dirección (0 = sentido horario, 1 = sentido antihorario) |
| Dirección de la bomba | 0x05 | uint_16 | El byte bajo es válido. Rango válido: 1-32 |
| Velocidad de transmisión (Baudios) | 0x06 | uint_16 | El byte bajo es válido. 01H: 1200 bps 02H: 2400 bps 03H: 4800 bps 04H: 9600 bps 05H: 19200 bps 06H: 38400 bps |
| Paridad | 0x07 | uint_16 | El byte bajo es válido. 01H: Sin paridad 02H: Paridad impar 03H: Paridad par |
| Bit de parada | 0x08 | uint_16 | El byte bajo es válido. 01H: 1 bit de parada 02H: 2 bits de parada |
| Bloqueo de teclado | 0x09 | uint_16 | Byte bajo: Habilita la función de bloqueo del teclado. 01H: Deshabilitado 02H: Habilitado Byte alto: Retraso antes del bloqueo. 00H: 30s 01H: 60s 02H: 180s 03H: 300s 04H: 480s 05H: 600s |
💡 Notas importantes:
- El protocolo Modbus RTU de Longer solo admite los códigos de función 03H (lectura de registros), 06H (escritura de un solo registro) y 10H (escritura de múltiples registros).
- Al utilizar el código de función 06H, la bomba opera según el último comando recibido, mostrando la velocidad mediante un parámetro de velocidad y el caudal mediante un parámetro de caudal.
- Para configurar el caudal, se deben especificar simultáneamente tanto el byte alto como el byte bajo. La unidad de caudal es 1 nL/min (p. ej., el comando 02 FA F0 80H corresponde a 50,0 mL/min).
- Si el caudal o la velocidad superan el rango permitidos, la bomba muestra el valor máximo o mínimo sin emitir ninguna advertencia.
Relación de conversión entre caudal y velocidad
La relación entre el caudal y la velocidad para el modelo L100-1S-2 se puede describir mediante la ecuación: Q = V x f
Donde Q representa el caudal en mL/min, V denota la velocidad en rpm, y f es el coeficiente de caudal medido en mL/r, cuyo valor predeterminado es 1.
El valor predeterminado f = 1 indica una correlación directa entre la velocidad y el caudal bajo condiciones estándar. Esta simplicidad facilita que los operadores optimicen los parámetros de la bomba para sus aplicaciones específicas.
¿Cómo comunicarse con el L100-1S-2 utilizando Python?
En esta sección se presenta una biblioteca básica de Python diseñada para facilitar la comunicación y el control de las bombas peristálticas Longer mediante el protocolo Modbus RTU. Esta encapsula funcionalidades esenciales, como el ajuste de la velocidad de la bomba, el caudal y la dirección, así como el inicio y la detención de la bomba con facilidad.
Esta biblioteca está escrita específicamente basándose en el protocolo de la bomba peristáltica Longer L100-1S-2 y sirve como ejemplo que puede modificarse. Al ajustar los comandos y parámetros según sea necesario, los usuarios pueden adaptarla para que se ajuste al protocolo Modbus RTU de su modelo específico de bomba 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()
Conclusión
En esta entrada del blog, hemos abordado cómo controlar las bombas peristálticas Longer mediante el protocolo Modbus RTU, ofreciendo información detallada sobre el formato de comunicación y proporcionando una biblioteca de Python para ayudarle a empezar. Tanto si trabaja con el modelo L100-1S-2 como si adapta el código para otra bomba, esperamos que esta guía le sea de gran utilidad.
Permanezca atento para más tutoriales y aplicaciones prácticas en futuras publicaciones. Hasta entonces, ¡feliz bombeo y programación! 💻
📧 Si tiene alguna pregunta o comentario, no dude en contactarnos en support@darwin-microfluidics.com.

