Controlando servo motores no Arduino Nano (parte 2)

Desenvolvimento

Embarcados comentários

por eduardo em 02/01/2012 22:52:49




Continuando minhas aventuras com o Arduino Nano (veja o post anterior clicando aqui), resolvi explorar um pouco mais a API para controle de motores servos, movimentando minha engenhoca com a ajuda de um joystick que eu tinha encostado em algum lugar aqui de casa. Esta etapa irá me ajudar no futuro a movimentar uma câmera remotamente em um projeto que estou trabalhando, mas por ora meu objetivo é controlar os dois motores servos através de um joystick tendo o meu notebook como "meio de campo" entre o Arduino e o controle.

Do primeiro post eu aproveitei as conexões na protoboard dos motores com o Arduino. Nesta etapa precisei implementar um aplicação em Python para capturar os eventos do joystick e enviar as coordenadas ao Arduino, que teve seu firmware alterado para receber as informações e movimentar os servos de acordo com as mesmas. O joystick que utilizei foi um Leadership Pilot Pro, mas você pode usar qualquer outro que tenha interface de comunicação com seu computador.

*Meu ambiente de desenvolvimento roda em cima do Ubuntu, então este post pode ser direcionado em alguns momentos para o sistema operacional Linux.

A aplicação em Python

Meu primeiro desafio foi encontrar a forma mais fácil de capturar as coordenadas dos eixos do meu joystick. Escolhi desenvolver uma aplicação em Python por conhecer a existência de uma biblioteca de nome pygame que abstrai muito do trabalho que eu teria se fosse utilizar uma linguagem de mais baixo nível. Caso você esteja em um Ubuntu, basta executar a seguinte linha no shell para instalar a biblioteca:

sudo apt-get install python-pygame

Além disso, esbarrei na internet com um código em Python no Principia Labs com o propósito bem semelhante ao proposto neste post e que eu acabei utilizando como referência. Você pode acessá-lo clicando aqui. Após algumas alterações para adequar o código ao uso de dois motores servos, tenho o seguinte programa:

#!/usr/bin/env python
#coding: utf-8

import serial, pygame, struct

joy = []
usbport = "/dev/ttyUSB0"
arduino = serial.Serial(usbport, 9600)

def handleJoyEvent(e):
    if e.type == pygame.JOYAXISMOTION:
        axis = "unknown"
        if (e.dict['axis'] == 0):
            axis = "X"

        if (e.dict['axis'] == 1):
            axis = "Y"

        if (e.dict['axis'] == 2):
            axis = "Throttle"

        if (e.dict['axis'] == 3):
            axis = "Z"

        if (axis == "X") or (axis == "Y"):
            pos = e.dict['value']
            move = round(pos * 90, 0)
            if (move < 0):
              servo = int(90 + abs(move))
            else:
              servo = int(90 - move)
            toSend = struct.pack("BB", ord(axis), servo)
            arduino.write(toSend)
            print axis, servo

    elif e.type == pygame.JOYBUTTONDOWN:
        if (e.dict['button'] == 0):
            arduino.close()
            quit()
    else:
        pass

def joystickControl():
    while True:
        e = pygame.event.wait()
        if (e.type == pygame.JOYAXISMOTION or e.type == pygame.JOYBUTTONDOWN):
            handleJoyEvent(e)

def main():
    pygame.joystick.init()
    pygame.display.init()
    if not pygame.joystick.get_count():
        print "Por favor, conecte um joystick e tente novamente."
        quit()
    print "%d joystick(s) detectado(s)." % pygame.joystick.get_count()
    for i in range(pygame.joystick.get_count()):
        myjoy = pygame.joystick.Joystick(i)
        myjoy.init()
        joy.append(myjoy)
        print "Joystick %d: " % (i) + joy[i].get_name()  
    print "Pressione o gatilho (botão 0) para sair."

    joystickControl()

if __name__ == "__main__":
    main()  

 Este código inicia e monitora as ações de todos os joysticks conectados ao computador e configura a porta /dev/ttyUSB0 para comunicação serial 8N1 a 9600bps. Esta é a porta que será utilizada para enviar dados ao Arduino (mais a frente explicarei como esta comunicação serial ocorre).

Quando um evento é detectado no joystick que tenho conectado ao notebook, a função handleJoyEvent é chamada para tratá-lo e uma verificação de qual eixo ou botão disparou o evento é realizada. Quando os eixos X e Y são alterados, dois bytes são enviados ao Arduino. O primeiro byte representa o eixo movimentado (caractere 'X' ou caractere 'Y') e o segundo byte representa a posição do eixo já convertida para um ângulo entre 0 e 180. Quando o botão 0 é pressionado (o gatilho no caso do meu controle), a aplicação é encerrada.

O firmware do Arduino

Por último precisei escrever um programa para que o Arduino recebesse através de comunicação serial as coordenadas X e Y para movimentação dos servos. Antes de continuar, preciso dizer que o cabo USB do Arduino comporta-se como um adaptador serial, disponibilizando em minha máquina o dispositivo /dev/ttyUSB0, já mencionado. O código ficou assim:

#include <Servo.h> 

Servo servoX;
Servo servoY;

void setup() 
{
  servoX.attach(3);
  servoY.attach(2);
  
  Serial.begin(9600);
} 
 
void loop() 
{
  if (Serial.available() >= 2)
  {
             char axis = Serial.read();
    unsigned char grau = Serial.read();
    
    if (axis == 'X')
    {
      servoX.write(grau);
    }
    else if (axis == 'Y')
    {
      if (grau > 170)
        grau = 170;
      if (grau < 20)
        grau = 20;
      servoY.write(grau);
    }
  }
}

 A utilização da biblioteca Servo já foi explicada no post anterior. O que temos de novidade no setup é a configuração da comunicação serial com a velocidade 9600bps. No loop temos a verificação da disponibilidade de dois bytes ou mais para leitura na serial e quando esta condição for verdadeira é realizada a captura do nome do eixo a ser movimentado (variável axis) e seu ângulo (variável grau). Perceba que coloquei uma limitação para a movimentação do servo responsável pelo eixo Y. Acontece que eu devo ter cometido algum erro na montagem do pan tilt (componente mecânico com dois servos instalados e que pode ser visto no meu post anterior), por isso tem um parafuso impedindo que o servo se posicione em ângulos muito abertos (menores que 20 e maiores que 170 graus). Problema "contornado", segue abaixo o vídeo que gravei com os dois programas rodando (perdoem a qualidade, estou providenciando outra câmera):

 


Na próxima etapa conectarei o Arduino a um NAS modificado para que seja possível movimentar os servos de forma remota. Nos próximos dias postarei alguns conteúdos relacionados ao NAS, preparando-o para a conexão com o Arduino.

Um abraço.



sobre Eduardo Carneiro

Bacharel em Ciências da Computação, programador C para microcontroladores e corintiano nato!


veja o perfil de Eduardo Carneiro no entrebits


Você também pode se interessar por:


Comentários

blog comments powered by Disqus

lolbits.tumblr

I <3 angry...

perfect!...

seems...

I want!...

A Ball of Cards....

kylethacker:

The...

=] feliz natal...

cool!...

A História de...