Tag: python

  • 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/