Control del motor principal de una lavadora (motor universal) con SBC y Python

Artículo extenso y paso a paso con vídeos ilustrativos sobre el control del motor universal de una lavadora con una placa de desarrollo embebido de arquitectura RISC-V concretamente la VisionFive 2 programada en Python

SISTEMAS EMBEBIDOS

Biblioman

5/19/20247 min read

Introducción

En el mundo de la ingeniería eléctrica, el motor monofásico universal es un dispositivo ampliamente utilizado debido a su versatilidad y eficiencia en diversas aplicaciones, por ejemplo el motor de una lavadora. En este primer vídeo veremos los elementos eléctricos que forman una lavadora y la placa de desarrollo embebido y componentes auxiliares que utilizaremos para el control del motor principal.

Si queremos crear un driver de un dispositivo hardware por ejemplo un display para un programa escrito en C o en Python lo primero que tenemos que hacer es conocer su funcionamiento al detalle para ello acudimos al manual de características técnicas o datasheet, igualmente si queremos hacer un programa que controle el motor principal (motor universal) de una lavadora debemos de conocer al detalle los componentes que lo forman, su funcionamiento y el esquema de conexiones, en el siguiente video se muestra todo esto y el primer test del motor probando su funcionamiento tanto en corriente continua y corriente alterna (230 V 50 Hz)

Para que nuestro motor de lavadora sea funcional debemos saber como cambiarle el sentido de marcha y comprender porque el motor universal es capaz de funcionar tanto en CC como en CA y sin necesidad de cambiar ninguna conexión, en el siguiente vídeo se explica paso a paso estos conceptos que serán imprescindibles de entender antes de desarrollar nuestro primer programa en Python en la VisionFive 2 para su control

Esquema de conexiones CA (control por TRIAC):

Una vez entendido y probado el funcionamiento del motor universal es el momento de empezar a automatizar sus funciones diseñando el hardware que vamos a utilizar y escribiendo nuestro primer programa de Test en Python con la VisionFive 2

El código en Python del primer test de control en la VisionFive2 lo tenéis aquí:

# -*- coding: utf-8 -*-
"""
--------------------------------------------------
Primer test control motor lavadora con VisionFive2 v.1
Autor: Biblioman09
YouTube: https://www.youtube.com/@biblioman09
Blog
: https://aquihayapuntes.com/
-------------------------------------------------

Conexiones
motor.
-----------------------------------------
_____PWM_________Pin Number_____Pin Name
Positive 22 GPIO50
Negative 6 GND

_____RELES_________Pin Number_____Pin Name

Conexiones reles.
on_off 40 GPIO44
r1 38 GPIO61
r2 36 GPIO44
-----------------------------------------

"""
import time
import VisionFive.gpio as GPIO
control_motor = 22
on_off = 40
r1 = 38
r2 = 36

def initMotor():
# Set gpio modo 'BOARD'.
GPIO.setmode(GPIO.BOARD)

# Configuracion pines reles como salidas
GPIO.setup(on_off, GPIO.OUT)
GPIO.setup(r1, GPIO.OUT)
GPIO.setup(r2, GPIO.OUT)

# Configuracion pin PWM.
GPIO.setup(control_motor, GPIO.OUT)
# Configuro a nivel alto el voltaje de salida.
GPIO.output(control_motor, GPIO.HIGH)
GPIO.output(on_off, GPIO.HIGH)
GPIO.output(r1, GPIO.HIGH)
GPIO.output(r2, GPIO.HIGH)

global p
# Configuro la frecuencia del motor a 50Hz.
p = GPIO.PWM(control_motor, 50)
# Inicializo el duty (Ton) a 0.
p.start(0)

def iniciar_sentido_horario():
GPIO.output(on_off, GPIO.HIGH)
time.sleep(1)
GPIO.output(r1, GPIO.HIGH)
GPIO.output(r2, GPIO.HIGH)
p.start(15)
time.sleep(1)
GPIO.output(on_off, GPIO.LOW)
print("Motor iniciado en sentido horario")

def iniciar_sentido_anti_horario():
GPIO.output(on_off, GPIO.HIGH)
time.sleep(1)
GPIO.output(r1, GPIO.LOW)
GPIO.output(r2, GPIO.LOW)
p.start(15)
time.sleep(1)
GPIO.output(on_off, GPIO.LOW)
print("Motor iniciado en sentido anti-horario")

def variar_velocidad():
dc = input("Introduce el valor de la velocidad entre 15 y 50 ")
p.ChangeDutyCycle(float(dc))
time.sleep(1)
print("Cambio de velocidad efectuado")

def rpm_motor():
print("Revoluciones del motor: ")

def parar_motor():
p.start(0)
GPIO.output(on_off, GPIO.HIGH)
print("Motor detenido")

# Menú principal
def mostrar_menu():
print("\n--- Menu ---")
print("1) Puesta en marcha motor giro sentido horario")
print("2) Puesta en marcha motor giro sentido anti-horario")
print("3) Variar velocidad")
print("4) Parar motor")
print("5) RPM del motor")
print("6) Salir de la aplicacion")

# Ejecucion del programa
if name == '__main__':

initMotor()

while True:
mostrar_menu()
opcion = input("Elige una opcion: ")

if opcion == '1':
iniciar_sentido_horario()
elif opcion == '2':
iniciar_sentido_anti_horario()
elif opcion == '3':
variar_velocidad()
elif opcion == '4':
parar_motor()
elif opcion == '5':
rpm_motor()
elif opcion == '6':
print("Saliendo de la aplicacion...")
break
else
:
print("Opcion no valida. Por favor, elige una opcion del 1 al 6.")

El controlador comercial utilizado en el anterior vídeo para la regulación de velocidad del motor tiene las siguientes limitaciones:

  • El TRIAC utilizado BT138 funciona bien para cargas resistivas e incluso para el funcionamiento del motor de lavadora en vacío (sin carga) como se vio en el vídeo anterior, pero se queda escaso para utilizar el motor con carga.

  • El filtro Snubber que incorpora no es el idóneo para la carga inductiva del motor universal utilizado en el vídeo.

  • Utiliza un microcontrolador con código cerrado, por lo que no tenemos acceso al código fuente.

Decidí que era importante tener un controlador de velocidad mas adecuado para el motor universal de la lavadora y disponer del código fuente del microcontrolador, así que me puse manos a la obra para diseñar mi propio regulador de velocidad para ello utilice el editor de PCB Flux tenéis un vídeo sobre el aquí . En el siguiente vídeo tenéis el test de la nueva controladora de velocidad:

Esquema nueva controladora de velocidad:

Placa terminada:

Componentes de la placa:

  • Node MCU ESP8266: donde cargaremos el programa para la detección del paso por cero de la tensión de 230V AC y la generación de la señal PWM para el control del ciclo de trabajo del TRIAC.

  • TRIAC BTA41 800B: IT(RMS) 40A, VDRM/VRRM 600/800V IGT (Q1 ) 50 mA, descarga del datasheet aquí.

  • Rectificador DB207

  • MOC3021

  • PC817C

  • Filtro Snubber: imprescindible para trabajar con cargas inductivas formado por un condensador 104j/630V y una resistencia 500 Ohmios/2W en serie (puede ser necesario ajustar estos valores según la inductancia de las bobinas de la carga)

Software:

Se divide en dos partes. La primera el firmware del ESP8266 utilizando las librerías RBDDimmer cuyo código programaremos con el IDE de Arduino y cuya función será doble 1) detectar el paso por cero de la tensión de red 230V AC y 2) generar una señal PWM sincronizada con la tensión de red para que a través del controlador MOC3021 ajustar el ciclo de trabajo del TRIAC y variar de esa forma la potencia entregada al motor . La segunda parte estará formada por el código en Python que se ejecutará en la VisionFive 2 y que presentará el menú principal del programa y enviará los comandos de control a través del puerto COM virtual creado a partir del convertidor USB-Serial de la placa Node MCU ESP8266.

Código ESP8266

#include "RBDdimmerESP8266.h"//

#define outPin 13 //Salida PWM GPIO13 (pin D7)
#define ZCPin 12 // Entrada detección de paso por cero GPIO12 (pin D6)

dimmerLampESP8266 dimmer(outPin, ZCPin); //inicialización dimmer

int outVal = 0;

void setup() {
Serial.begin(9600);
dimmer.begin(NORMAL_MODE, ON); //dimmer inicializado: name.begin(MODE, STATE)
Serial.println("Dimmer Program is starting...");
Serial.println("Set value");
}

void printSpace(int val)
{
if ((val / 100) == 0) Serial.print(" ");
if ((val / 10) == 0) Serial.print(" ");
}

void loop() {
int preVal = outVal;

if (Serial.available())
{
int buf = Serial.parseInt();
if (buf != 0) outVal = buf;
delay(200);
}
dimmer.setPower(outVal); // setPower(0-100%);

if (preVal != outVal)
{
Serial.print("% lampValue -> ");
printSpace(dimmer.getPower());
Serial.print(dimmer.getPower());

}
delay(50);

}

Código Python:

# -*- coding: utf-8 -*-
"""
--------------------------------------------------
Control del tacometro para seguridad de marcha
/paro y sobrevelocidad v.2
Autor: Biblioman09
YouTube: https://www.youtube.com/@biblioman09
Blog
: https://aquihayapuntes.com/
-------------------------------------------------
Conexiones
motor.
------------------------------------------------

_____RELES_________Pin Number_____Pin Name

Conexiones reles.
on_off 40 GPIO44
r1 38 GPIO61
r2 36 GPIO44
-----------------------------------------

"""
import serial
import time
import VisionFive.gpio as GPIO

on_off = 40
r1 = 38
r2 = 36
uart_port = "/dev/ttyUSB0"
serie = serial.Serial(uart_port, baudrate=9600)

def initMotor():
# Set gpio modo 'BOARD'.
GPIO.setmode(GPIO.BOARD)

# Configuracion pines reles como salidas
GPIO.setup(on_off, GPIO.OUT)
GPIO.setup(r1, GPIO.OUT)
GPIO.setup(r2, GPIO.OUT)

# configuro a nivel alto el voltaje de salida.
GPIO.output(on_off, GPIO.HIGH)
GPIO.output(r1, GPIO.HIGH)
GPIO.output(r2, GPIO.HIGH)

def iniciar_sentido_horario():
parar_motor()
time.sleep(1)
GPIO.output(r1, GPIO.HIGH)
GPIO.output(r2, GPIO.HIGH)
serie.write(b'15')
time.sleep(1)
GPIO.output(on_off, GPIO.LOW)
print("Motor iniciado en sentido horario")


def iniciar_sentido_anti_horario():
parar_motor()
time.sleep(1)
GPIO.output(r1, GPIO.LOW)
GPIO.output(r2, GPIO.LOW)
serie.write(b'15')
time.sleep(1)
GPIO.output(on_off, GPIO.LOW)
print("Motor iniciado en sentido anti-horario")


def variar_velocidad():
dc = input("Introduce el valor de la velocidad entre 1-99 ")
# Convertir la entrada a bytes antes de enviar por la UART
dc_bytes = dc.encode('utf-8')
serie.write(dc_bytes)
print("Cambio de velocidad efectuado")


def rpm_motor():
print("Revoluciones del motor: ")


def parar_motor():
serie.write(b'1')
time.sleep(1)
GPIO.output(on_off, GPIO.HIGH)
print("Motor detenido")


# Menu principal
def mostrar_menu():
print("\n--- Menu ---")
print("1) Puesta en marcha motor giro sentido horario")
print("2) Puesta en marcha motor giro sentido anti-horario")
print("3) Variar velocidad")
print("4) Parar motor")
print("5) RPM del motor")
print("6) Salir de la aplicacion")


# Ejecucion del programa
if name == '__main__':

initMotor()

while True:

mostrar_menu()
opcion = input("Elige una opcion: ")

if opcion == '1':
iniciar_sentido_horario()
elif opcion == '2':
iniciar_sentido_anti_horario()
elif opcion == '3':
variar_velocidad()
elif opcion == '4':
parar_motor()
elif opcion == '5':
rpm_motor()
elif opcion == '6':
print("Saliendo de la aplicacion...")
serie.close()
break
else
:
print("Opcion no valida. Por favor, elige una opcion del 1 al 6.")

Nota: el código es muy similar al utilizado con el controlador comercial, la diferencia está en que antes teníamos que generar una señal PWM desde la VisiónFive2. Ahora le enviamos el comando a través del puerto serie y el ESP8266 se encarga de interpretar el comando con la velocidad deseada y generar la señal PWM que le enviará al MOC3021.

Formas de onda:

Puedes descargarte los archivos Gerber de la placa desde aquí

Implementación de seguridades

Debemos de implementar como mínimo dos seguridades:

  1. Impedir que el motor se ponga en marcha si el rotor no está completamente parado

  2. Estos motores tienden a embalarse cuando trabajan en vacío y se les aplica la tensión de red, según el fabricante para este motor en concreto no se debe sobrepasar las 14.000 rpm, hay que impedir que eso ocurra.

Utilizaremos el tacómetro que lleva incorporado en el eje para implementar esas seguridades, si tienes interés en el tema puedes dejar tus comentarios en YouTube

Saludos