Motor DC y puente en H

Motor DC y puente en H

Vamos a explicar como funciona un motor de corriente continua (CC) o DC (Direct Current), como funciona un motor paso a paso, (o Stepper Motor), y como usar un motor DC con un puente en H.

Motor DC o CC:

Es una máquina que convierte energía eléctrica en mecánica, provocando un movimiento rotatorio, gracias a la acción de un campo magnético.

Generalmente tiene devanados que se mueven en un campo magnético que fluctua de norte a sur, varias veces por revolución. Cuando por los cables del devanado circula corriente eléctrica se desarrolla una fuerza siguiendo la ecuación de Lorentz. Esta fuerza es proporcional a la corriente y al campo magnético.

Las ventajas de este tipo de motores son:

  • Son más silenciosos
  • Operación libre de vibraciones
  • Buena eficiencia
  • Muy fáciles de controlar: Aceleran si la tensión aumenta, y se vuelven más lentos si la tensión se reduce.

Motor paso a paso o Stepper Motor:

Son motores que convierten impulsos eléctricos en desplazamientos angulares discretos, es decir, giran una cantidad de grados (pasos) dependiendo de sus entradas de control.

Sus ventajas principales son:

  • Precisión
  • Repetitividad en cuanto al posicionamiento

Al igual que los motores DC, los paso a paso están formados por 2 partes:

El estator , que como su nombre indica, es la parte que se queda estática y donde están las bobinas. y es la parte que no se mueve (, de ahí el nombre de estator). La diferencia con el de corriente continua, es que en el caso de los paso a paso, el estator tiene unas muescas que van a quedar imantadas cuando circule la corriente por las bobinas.

La parte que gira se llama rotor, y está formado por unos imanes que se alternan entre norte/sur.

La idea fundamental es que cuando se imantan las bobinas, los imanes son atraídos por las muescas, y el motor queda firme en su posición.

Un ejemplo muy claro para este tipo de motores, son las impresoras 3D.

Ejemplo de uso motores DC:

En nuestro caso, hemos decidido utilizar 2 motores DC para mover un robot. Hemos querido usar motores corriente continua porque nos permiten avanzar más rápido, y no requerimos de tanta precisión en la posición.

Sin embargo, en el circuito que vamos a preparar para usarlos, no disponemos de tensiones negativas, por lo que sólo podriamos hacer girar los motores en un sentido, y por tanto sólo podriamos avanzar el robot en una dirección. Para solventar esto vamos a usar un puente en H. El nombre proviene de la típica representación gráfica del circuito.

PuenteH_Esquema

Un puente H se construye con 4 interruptores (mecánicos o mediante transistores).Cuando S1 y S4 están cerrados, se aplica una tensión positiva en el motor, haciéndolo girar en un sentido.

PuenteH_Esquema-sentido1

Mientras que si los que están cerrados son S2 y S3, la corriente circulará en sentido contrario, de tal manera que el giro del motor será en sentido opuesto al de la figura anterior.

PuenteH_Esquema-sentido2

En esta entrada vamos a utilizar el puente en H njm2670d2, puesto que nos permite controlar desde el mismo encapsulado 2 motores DC simultaneamente.

Tiene el siguiente esquema:

DC_Motors_H_Bridge

El programa en Python para utilizar ambos motores, y el puente en H puede quedar del siguiente modo:

# -*- coding: utf-8 -*-
#################################################
#						                                    #
# Motors control module				                  #
# Authors: Ismael Tobar and Raquel Muñoz        #
#						                                    #
#################################################

#----Libraries
import sys
import RPi.GPIO as GPIO
import threading
from time import sleep

MAX_DUTY = 100
MIN_DUTY = 30  #It's 30 because with a lower voltage the motors don't move
POWER_VOLTAGE = 0.7		#constant to convert percentage (or pwm duty) to voltage
FREQ = 50

#Motor pins
INA1 = 20  
INA2 = 21
INB1 = 12  
INB2 = 16
EN_A = 9
EN_B = 10

#pwm signals of each input of the motors
pwm_ina1 = 0
pwm_ina2 = 0
pwm_inb1 = 0
pwm_inb2 = 0
motors_not_used = True
initial = 0

#status variables
DISCONNECTED = 0
CONNECTED_OK = 1
CONNECTED_ERROR = 2

status = DISCONNECTED

def setup():
  global initial
  global status
  try:
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(INA1, GPIO.OUT)
    GPIO.setup(INA2, GPIO.OUT)
    GPIO.setup(INB1, GPIO.OUT)
    GPIO.setup(INB2, GPIO.OUT)
    GPIO.setup(EN_A, GPIO.OUT)
    GPIO.setup(EN_B, GPIO.OUT)
    if initial == 0:
      print("Motors: Setup")
      initial = 1
    status = CONNECTED_OK
  except Exception as e:
    print("Motors: Error in setup.")
    status = CONNECTED_ERROR

#Forward Instruction
def fd(power):
  global pwm_ina1
  global pwm_ina2
  global pwm_inb1
  global pwm_inb2
  global status
  try:
    d = powerToDuty(power)
    if MIN_DUTY <= d <= MAX_DUTY:
      setup()
      GPIO.output(EN_A, True)
      GPIO.output(EN_B, True)
      pwm_ina2 = GPIO.PWM(INA2, FREQ)
      pwm_inb1 = GPIO.PWM(INB1, FREQ)
      pwm_ina1 = GPIO.PWM(INA1, FREQ)
      pwm_inb2 = GPIO.PWM(INB2, FREQ)
      pwm_ina2.start(d)
      pwm_inb1.start(d)
      pwm_ina1.start(0)
      pwm_inb2.start(0)
  except Exception as e:
    clean()
    print("Motors: Error fordward thread")
    status = CONNECTED_ERROR
#Backward Instruction
def bd(power):
  global pwm_ina1
  global pwm_ina2
  global pwm_inb1
  global pwm_inb2
  global status
  try:
    d = powerToDuty(power)
    print(power)
    if MIN_DUTY <= d <= MAX_DUTY:
      setup()
      GPIO.output(EN_A, True)
      GPIO.output(EN_B, True)
      pwm_ina1=GPIO.PWM(INA1, FREQ)
      pwm_inb2=GPIO.PWM(INB2, FREQ)
      pwm_ina2 = GPIO.PWM(INA2, FREQ)
      pwm_inb1 = GPIO.PWM(INB1, FREQ)
      pwm_ina1.start(d)
      pwm_inb2.start(d)
      pwm_ina2.start(0)
      pwm_inb1.start(0)
  except Exception as e:
    clean()
    print("Motors: Error backward thread")
    status = CONNECTED_ERROR

#Turn left Instruction
def lt(power):
  global pwm_ina1
  global pwm_ina2
  global pwm_inb1
  global pwm_inb2
  global status
  try:
    d = powerToDuty(power)
    if MIN_DUTY <= d <= MAX_DUTY:
      setup()
      GPIO.output(EN_A, True)
      GPIO.output(EN_B, True)
      pwm_ina2=GPIO.PWM(INA2, FREQ)
      pwm_inb2=GPIO.PWM(INB2, FREQ)
      pwm_ina1=GPIO.PWM(INA1, FREQ)
      pwm_inb1=GPIO.PWM(INB1, FREQ)
      pwm_ina2.start(d)
      pwm_inb2.start(d)
      pwm_ina1.start(0)
      pwm_inb1.start(0)
  except Exception as e:
    clean()
    print("Motors: Error left thread")
    status = CONNECTED_ERROR

#Turn right Instruction
def rt(power):
  global pwm_ina1
  global pwm_ina2
  global pwm_inb1
  global pwm_inb2
  global status
  try:
    d = powerToDuty(power)
    if MIN_DUTY <= d <= MAX_DUTY:
      setup()
      GPIO.output(EN_A, True)
      GPIO.output(EN_B, True)
      pwm_ina1 =GPIO.PWM(INA1, FREQ)
      pwm_inb1=GPIO.PWM(INB1, FREQ)
      pwm_ina2=GPIO.PWM(INA2, FREQ)
      pwm_inb2=GPIO.PWM(INB2, FREQ)
      pwm_ina1.start(d)
      pwm_inb1.start(d)
      pwm_ina2.start(0)
      pwm_inb2.start(0)
  except Exception as e:
    clean()
    print("Motors: Error right thread")
    status = CONNECTED_ERROR
#It cleans the GPIO of the enines and stops the pwm signals
def clean_and_ENA_setup():
  global pwm_ina1
  global pwm_ina2
  global pwm_inb1
  global pwm_inb2
  pwm_ina1.stop()
  pwm_ina2.stop()
  pwm_inb1.stop()
  pwm_inb2.stop()
  GPIO.setup(EN_A, GPIO.OUT)
  GPIO.setup(EN_B, GPIO.OUT)
  GPIO.output(EN_A, False)
  GPIO.output(EN_B, False)
  GPIO.cleanup(EN_A)
  GPIO.cleanup(EN_B)
  GPIO.cleanup(INA1)
  GPIO.cleanup(INA2)
  GPIO.cleanup(INB1)
  GPIO.cleanup(INB2)
#It only stops the pwm signals
def clean():
  global pwm_ina1
  global pwm_ina2
  global pwm_inb1
  global pwm_inb2
  global motors_not_used
  motors_not_used = False
  pwm_ina1.stop()
  pwm_ina2.stop()
  pwm_inb1.stop()
  pwm_inb2.stop()
  GPIO.output(EN_A, False)
  GPIO.output(EN_B, False)

def turn_left_90():
  tim = 0.0
  left(52)
  while (tim < 2):
    sleep(0.1)
    tim += 0.1
  stop()

def turn_right_90():
  right(52)
  tim = 0.0
  while (tim < 2):
    sleep(0.1)
    tim += 0.1
  stop()

#convert power indicated to pwm duty of the signal
def powerToDuty(p):
  if 0 <= p <= 100:
    return (p*POWER_VOLTAGE + MIN_DUTY)

def rt_90():
  global status
  try:
    h = threading.Thread(target=turn_right_90)
    h.start()
  except Exception as e:
    clean_and_ENA_setup()
    print("Motors: Error starting turn_right_90 thread")
    status = CONNECTED_ERROR

def lt_90():
  global status
  try:
    h = threading.Thread(target=turn_left_90)
    h.start()
  except Exception as e:
    clean_and_ENA_setup()
    print("Motors: Error starting turn_left_90 thread")
    status = CONNECTED_ERROR

def forward(power):
  global status
  try:
    h = threading.Thread(target=bd, args=(power, ))
    h.start()
    print("Motors: forward", power)
  except Exception as e:
    clean_and_ENA_setup()
    print("Motors: Error starting backward thread")
    status = CONNECTED_ERROR

def backward(power):
  global status
  try:
    h = threading.Thread(target=fd, args=(power, ))
    h.start()
    print("Motors: backward", power)
  except Exception as e:
    print("Motors: Error starting forward thread")
    status = CONNECTED_ERROR

def left(power):
  global status
  try:
    h = threading.Thread(target=lt, args=(power, ))
    h.start()
    print("Motors: left", power)
  except Exception as e:
    print("Motors: Error starting left thread")
    status = CONNECTED_ERROR

def right(power):
  global status
  try:
    h = threading.Thread(target=rt, args=(power, ))
    h.start()
    print("Motors: fright", power)
  except Exception as e:
    print("Motors: Error starting right thread")
    status = CONNECTED_ERROR

def stop():
  clean_and_ENA_setup()
  print("Motors: stop")

if __name__ == "__main__":
  terminate = False	#finish the while()
    # if run directly we'll just create an instance of the class and output
  option = 6
  while terminate == False:
    sleep(0.1)
    option = input('Enter: 1 -> Forward; 2 -> Backward; 3 -> Right; 4 -> Left; 5 -> Stop  (0 to exit) : ')
    if option == 0:
      clean_and_ENA_setup()
      terminate = True
    elif (1 <= option <= 4):
      power = input('Enter power (1 to 100) : ')	#the  power is asked
      if option == 1:
        forward(power)
      elif option == 2:
        backward(power)
      elif option == 3:
        right(power)
      else:
        left(power)
    elif option == 5:
      stop()
  GPIO.cleanup()
  print('Motors: Exit motors')

Si te ha interesado esta entrada, puedes ver nuestro vehículo robotizado que hemos desarrollado utilizando estos motores.