Controlando um motor DC com driver TB6612FNG e RaspberryPi

Desde que foi lançado há alguns anos, o “computador do tamanho de um cartão de crédito” Raspberry Pi, tem conquistado a imaginação e criatividade de designers, hobbystas, engenheiros, estudantes, etc.
Com um generoso poder de processamento, memória, facilidade para conexão com dispositivos externos (sensores, motores e outros circuitos, só para mencionar alguns) a placa RaspberryPi pode ser usada em uma infinidade de projetos para estudos e novas tecnologias.
Entre as aplicações mais comuns estão a automação e robótica. Aproveitando esse contexto, a seguir veremos como controlar motores DC usando a Raspberry Pi com um circuito driver e a técnica PWM.

Para acompanhar esse post você precisa de alguns conhecimentos mínimos:

  • Eletrônica básica;
  • RaspberryPi: configurações, acesso ssh, instalação de pacotes;
  • Python;

Antes de passarmos para o circuito e software usados, vamos ver alguns pontos importantes sobre o controle do motor em dois aspectos: método de controle e hardware.

PWM – Pulse width modulation (modulação por largura de pulso)

Para o controle do motor vamos modular a aplicação de tensão sobre o mesmo.
Simplicando ao extremo,  a modulação PWM permite controlar a tensão média sobre uma carga aumentando ou diminuindo a largura de um ciclo ativo. Para isso aplicamos sobre a carga uma tensão com valor e frequência constantes. Ao modificarmos o período da aplicação da tensão (largura do pulso) modificamos o valor médio da tensão sobre a carga. O efeito, no caso do motor, é uma aceleração ou desaceleração do giro do eixo do motor.

O driver TB6612FNG

Fig 1 – Driver TB6612FNG

Trata-se de um circuito integrado com duas pontes H internas usando transistores MOSFET. O TB6612FNG pode controlar dois motores DC (motores pequenos usados em pequenas caixas de redução, brinquedos e outros aparelhos eletrônicos) independentemente.

A principal vantagem e indicação para o uso desses circuitos é a conexão protegida entre o(s) motor(es) e o microcontrolador/RPi. Visto que motor(es) consome(m) muita corrente há o risco de danos nas portas de I/O do microcontrolador, no nosso caso a GPIO da RPi.

Você pode encontrar mais detalhes aqui: https://www.pololu.com/product/713

O circuito

Fig 2 – Disposição dos terminais do circuito driver.

No circuito vamos usar as seguintes portas (GPIO) da RaspberryPi para a conectarmos ao driver:

  • GPIO 16 -> STBY
  • GPIO 19 -> PWM
  • GPIO 21 -> AIN_1
  • GPIO 22 -> AIN_2

Do driver, por sua vez, faremos a conexão com o motor DC. Na figura 2 podemos ver a disposição dos terminais do driver. Encontramos dois canais PWM: cada um pode controlar um motor DC, independentemente.  O canal 1 pode ser identificado pelo número “1” nas entradas (AIN1, AIN2) e nas saídas (AO1, AO2). O mesmo acontece para o canal 2.
Note a presença de um terminal “VMOT”. Nele vamos aplicar a tensão que o motor precisa para funcionar. O driver aceita tensões de até 12V.
Variando a largura do pulso em canais diferentes podemos acelerar 2 motores diferentes o que pode ser útil em aplicações mecânicas e/ou robóticas, como fazer uma plataforma girar em torno do próprio eixo.

Escrevendo o software

Para o controle do motor o script Python precisa acessar a biblioteca GPIO da Rpi. Essa biblioteca concede acesso ao hardware do dispositivo permitindo que seu programa interaja com os terminais de I/O, e, por conseguinte, com o hardware conectado neles. Assim você poderá ler informações provenientes de sensores ou enviar comandos para o hardware.

Para instalar o lib de acesso a GPIO, digite os seguintes comandos no terminal da RPi:

sudo apt-get update
sudo apt-get install rpi.gpio

Depois disso podemos usar um editor de texto comum (nano, leafpad, vi, vim) para editar o código:

nano pwm_motor.py

Nosso programa começa com alguns imports.

#coding: utf-8

import time
import RPi.GPIO as GPIO # API de acesso ao hardware GPIO
import sys
import traceback
(...)

Depois, definimos os terminais de I/O nos quais vamos conectar o driver.

# Niveis de tensao
HIGH = 1
LOW = 0

# Terminais
STBY = 16
PWM_PIN = 19

DIRECOES = {
    'AIN_1': 21,
    'AIN_2': 22
}

(...)

Nas duas primeiras linhas do código acima definimos constantes para os níveis de tensão usados no programa/circuito.
A própria GPIO já possui variáveis para esse fim: HIGH e LOW. Mas, para fins didáticos usaremos a definição acima. Isso vai permitir que o restante de código abaixo seja mais compreensível.

Em seguida especificamos os terminais que usaremos para enviar os sinais de STBY (Standby) e o sinal PWM; respectivamente 16 e 19. Esses terminais serão usados para aplicarmos o sinal de freio (break) e sinal de modulação PWM.

Finalmente, usamos um dicionário para definirmos as direções (esquerda/direita) de giro do motor: DIRECOES.

Controles do driver

Fig 4 – Controles do driver

Para funcionar corretamente há especificações de níveis de tensão que devem ser aplicados nos terminais do driver TB6612FNG.
Na Figura 4 encontramos uma tabela que especifica como operar o driver.
O que o nosso script precisa fazer é enviar os sinais corretos para o driver de acordo com o que desejamos fazer com o motor; por exemplo, giro para a esquerda ou direita, acelerar (PWM) e parar.

 

Assim, defiremos um conjunto de funções que serão responsáveis para cada uma das operações.

# "Liga" o dispositivo
def turn_on():
    print ">>> STBY on [LIGANDO...]"
    GPIO.output(STBY,HIGH)

# "Desliga" o dipositivo
def turn_off():
    print ">>> STBY off [DESLIGANDO...]"
    GPIO.output(STBY,LOW)

# Habilita o giro do motor no sentido anti-horário: direita
def ccw():
    GPIO.output(DIRECOES['AIN_2'],HIGH)
    GPIO.output(DIRECOES['AIN_1'],LOW)

# Habilita o giro do motor no sentido horário: esquerda
def cw():
    GPIO.output(DIRECOES['AIN_1'],HIGH)
    GPIO.output(DIRECOES['AIN_2'],LOW)
# "Freio"
def short_break():
    GPIO.output(DIRECOES['AIN_1'],HIGH)
    GPIO.output(DIRECOES['AIN_2'],HIGH)

Em geral o que as funções acima fazem é aplicar cada linha da tabela da figura 4 na GPIO.

Por fim,  o nosso programa, que será dotado de um loop infinito, vai precisar apenas chamar cada função para operar o motor.

O clico básico consiste em:

  1. Liga o motor (turn_on);
  2. Gira sentido anti-horário/horário (ccw/cw);
  3. Para o motor (shor_break);
  4. Desliga (turn_off);
  5. Tempo
  6. Retorna ao passo 1

Uma observação: o loop principal não é obrigado a implementar todas as chamadas de funções acima. O loop vai ser algo semelhante a:

turn_on() # funcao que "liga" o motor
while count < 100:
       ccw() # eixo do motor para a esquerda
       PWM.ChangeDutyCycle(count) # envia o sinal PWM (varia a largura do pulso PWM, (des)acelera o motor)
       time.sleep(0.1)
       count += 1
       print '>>> Ciclo: {ciclo}'.format(ciclo=count)
turn_off() # funcao que "desliga" o motor

Repare que na linha,

 while count < 100:
    (...)

configuramos o loop para ser executado 100 vezes. Se desejarmos um loop permanente (o que inspira cuidados visto que podemos “travar” o programa) podemos fazer:

 while 1:
    (...)

Outro detalhe importante no código acima, é a linha:

 PWM.ChangeDutyCycle(count) # envia o sinal PWM (varia a largura do pulso PWM, (des)acelera o motor)

Esse trecho de código apresenta o comando que altera a largura do ciclo ativo do sinal PWM. Fazendo isso, o programa altera o valor médio da tensão sobre o motor (carga) aumentando a velocidade de giro do eixo.

Antes do script invocar as funções de controle/operação do motor precisamos configurar os canais da GPIO como canais de saída. O trecho de código a seguir executa essa função:

def setup():
    GPIO.setmode(GPIO.BOARD) # configura o modo de operação da GPIO

    # setup ports
    GPIO.setup(STBY,GPIO.OUT)
    GPIO.setup(PWM_PIN,GPIO.OUT)
    GPIO.setup(DIRECOES['AIN_1'],GPIO.OUT)
    GPIO.setup(DIRECOES['AIN_2'],GPIO.OUT)

Abaixo o código completo em Python 2.7

#coding: utf-8

import time
import RPi.GPIO as GPIO
import sys
import traceback

# Niveis de tensao
HIGH = 1
LOW = 0

# Terminais
STBY = 16
PWM_PIN = 19

PWM = object

DIRECOES = {
'AIN_1': 21,
'AIN_2': 22
}

# Configuramos as portas
def setup():
    GPIO.setmode(GPIO.BOARD)
    # setup ports
    GPIO.setup(STBY,GPIO.OUT)
    GPIO.setup(PWM_PIN,GPIO.OUT)
    GPIO.setup(DIRECOES['AIN_1'],GPIO.OUT)
    GPIO.setup(DIRECOES['AIN_2'],GPIO.OUT)

def turn_on():
    print ">>> STBY on [LIGANDO...]"
    GPIO.output(STBY,HIGH)

def turn_off():
    print ">>> STBY off [DESLIGANDO...]"
    GPIO.output(STBY,LOW)

def ccw():
    GPIO.output(DIRECOES['AIN_2'],HIGH)
    GPIO.output(DIRECOES['AIN_1'],LOW)

def cw():
    GPIO.output(DIRECOES['AIN_1'],HIGH)
    GPIO.output(DIRECOES['AIN_2'],LOW)

def short_break():
    GPIO.output(DIRECOES['AIN_1'],HIGH)
    GPIO.output(DIRECOES['AIN_2'],HIGH)

def main():
    setup()
    count = 0
    turn_on()
    PWM = GPIO.PWM(PWM_PIN,100)
    PWM.start(50)

    while count < 100:
        ccw()
        PWM.ChangeDutyCycle(count)
        time.sleep(0.1)
        count += 1
        print '>>> Ciclo: {ciclo}'.format(ciclo=count)
    turn_off()

    try:
        main()
    except:
        traceback.print_exc(file=sys.stdout)
    finally:
        GPIO.cleanup()
    print 'Close everthing. END'

Funcionamento

Depois de revisarmos as conexões no protoboard, conectarmos a Rpi, e acessar o terminal, podemos rodar o script:

sudo python pwm_motor.py

Abaixo um breve vídeo com o resultado:

Referências

Sobre o driver TB6612FNG – https://www.pololu.com/product/713/pictures

Artigo muito bem escrito e detalhado sobre PWM: https://www.embarcados.com.br/pwm-raspberry-pi-python/

Detalhes importantes, manuais e mais um monte coisas sobre RaspberryPi: https://www.raspberrypi.org/