quinta-feira, 13 de março de 2014

Controlando motor de Disco Rígido


Olá,

Outro dia um colega estava desmontando um disco rígido defeituoso atrás dos ímãs de neodímio e ia jogar todo o restante fora. Foi aí que eu me lembrei de alguns vídeos que eu vi no YouTube de "Hard Disk POV". Vídeos como o do link abaixo:

http://www.youtube.com/watch?v=6dygwdisUj0#aid=P9R6_GgRM2I

Então eu pensei; "Taí um projeto muito bacana". Eu peguei o restante do HD que ia para o lixo e comecei a trabalhar para tentar fazer o motor do HD girar. A minha idéia era a de fazer um relógio de ponteiro usando um HD para deixar o bicho paradinho em minha escrivaninha rodando e mostrando a hora indefinidamente. Já posso adiantar que eu descobri que os motores de discos rígidos demandam muita energia para rotacionarem e que isto me desestimulou para fazer o projeto como eu queria. Afinal não é vantajoso você ter um relógio de ponteiro que consuma no final do mês muitos kW/h e acabei por fim jogando "todo o restante do hd fora". Mas não antes de eu fazer alguns testes e de aprender bastante sobre motores BLDC (motores CC sem escova) e sobre circuitos de controle com malha fechada. E é sobre isto o assunto desta matéria.

Para fazer meus testes eu usei um MSP430 launchpad Texas Instruments em conjunto com o software chamado Energia. Eu já descrevi o que é o Energia e o MSP430 lauchpad em mensagens anteriores. Basicamente o MSP430 launchpad é uma placa de testes e prototipagem muito parecida com as placas arduínos (mas não é compatível o arduíno) e o Energia é um ambiente de desenvolvimento muito parecido com o ambiente do arduino (mas não é compatível) no qual permite a você escrever programas também chamados sketchs e programa-los nas placas launchpad.

O disco rígido de teste possuí três bobinas que eu vou chamar durante o resto deste texto de "fases". Estas fases estão interligadas a um ponto comum. Portanto o motor do meu disco rígido possuía 4 contatos. Um contato para o ponto comum e um contato para cada fase. Havia algumas inscrições no motor mas eu não encontrei qualquer referência ou informação técnica na internet. Com um ohmímetro eu descobri que do ponto comum para cada fase existe uma resistência de 1,2 Ohms e entre as fases existe uma resistência de 2,4 Ohms. Com isto eu descobri quem era o ponto comum e quem eram as fases.   O contato do ponto comum ficava numa extremidade e eu deduzi que a ordem de acionamento das fases seguiriam a sequência dos contatos. Eu mantive esta dedução até o final e depois eu obtive a confirmação de que esta dedução estava certa por outros meios que eu vou explicar mais a frente.

Para acionar as fases eu liguei o ponto comum a uma fonte de alimentação de 12Vdc (apesar de não ter informações sobre o motor do HD me pareceu natural o uso deste valor de tensão). Cada fase eu liguei no dreno de um power mosfet canal N IRF840 e a fonte do mosfet eu liguei no terra. Como a tensão de limiar do gate do IRF840 está acima de 4V e o launchpad trabalha com tensão de 3,3V eu tive de usar um circuito auxiliar para comandar o power mosfet. Então eu usei um outro mosfet canal n, o BS270, para ajudar a elevar um pouco mais a tensão de gate do IRF840 quando acionado. Este tipo de configuração para acionamento de cargas é conhecido em inglês como "low side load driving". O circuito em sí não me parece muito importante agora, mas sim os resultados que eu obtive.

Eu comecei a tentar fazer o motor girar simplesmente acionando as fases do motor em sequência e gradativamente diminuindo o tempo de acionamento entre as fases para aumentar gradativamente a velocidade de rotação do motor . O comportamento do circuito foi muito fraco. Na maioria das vezes o motor simplesmente balançava para um lado e para o outro depois ficava estático. Algumas vezes o motor começava a girar e depois de algum tempo parava. E em outras vezes o motor girava lentamente e se eu aplicasse qualquer carga sobre o motor (Ex.: colocando levemente o dedo sobre o disco) o motor parava e não retornava a girar. Girar o motor com as mãos ao iniciar o acionamento elétrico do motor trazia pouca ou nenhuma ajuda. Um outro problema que eu detectei é que das vezes que o motor mantinha a rotação, a velocidade não era igual, i.e., as vezes o motor girava mais rápido e em outras vezes o motor girava mais rápido. Com isto ficou claro para mim que acionar as fases sem ter um controle efetivo da polaridade e da posição do eixo do motor é até possível mas é muito difícil e ineficiente.

Para controlar a posição do eixo e desta forma controlar o acionamento correto do motor há duas formas (pelo menos até aonde eu pude apurar das minhas pesquisas na internet): usando sensores de efeito hall e detectando a força eletromagnética reversa (back EMF). Eu decidi por tentar detectar a força magnética reversa e para isto eu modifiquei o meu circuito de controle para o circuito abaixo:


A ideia do circuito é simples: uma tensão de 3,3V no gate do transistor Q1 faz com que corrente circule na fase. Com o motor em rotação e sem termos corrente circulando na fase faz com que surja um DDP nos terminais da fase que é proporcional a posição do eixo do motor com relação a fase. Ou seja, a tensão será máxima se os pólos dos magnetos do eixo estiverem alinhados com a bobina da fase em questão. Usando as entradas ADC do MSP430 eu posso ler o nível de tensão das fases com o motor já em movimento e nos momentos aonde as três fases não estão sendo acionadas e desta forma acionar as fases de acordo com a posição correta do eixo.

Foi surpreendente a melhoria no comportamento do motor. Com esta última configuração ainda há o problema de "como fazer o motor começar a girar". Mas uma vez que o motor começa a girar eu posso garantir que ele não para mais. Eu posso aplicar carga sobre o motor (pressionando o dedo sobre o disco em movimento) que apesar do motor diminuir a sua rotação ele não mais para. Eu posso ajudar o motor girando o disco com as mãos que com certeza ele vai manter a rotação. E eu posso garantir que em todas as vezes o motor girava sempre na mesma rotação (em torno de 800 rpm). Um outro detalhe curioso é que se eu mudasse a ordem de acionamento das fases o motor ou girava mais lentamente ou não girava o que confirmou a minha suposição inicial sobre a ordem correta de acionamento das fases.

O código do sketch que eu usei nos testes está listado abaixo. Este código eu escrevi sem qualquer planejamento ou pretensão. Foi um código construído por meio de tentativa e erro e com certeza podia ter sido melhor escrito mas como eu não queria levar o projeto adiante eu simplesmente me dei por satisfeito.

//definição das variáveis locais
byte _step;
unsigned long time;
int time_count_on;
int time_count_off;
unsigned long key_pressed_count;
boolean motor_active;
boolean motor_start;
int phase1_level;
int phase2_level;
int phase3_level;

//definição das constantes do sketch
const int PHASE1_SWITCH=P2_0;
const int PHASE2_SWITCH=P2_1;
const int PHASE3_SWITCH=P2_2;
const int PHASE1_LEVEL=A0;
const int PHASE2_LEVEL=A1;
const int PHASE3_LEVEL=A2;

const int START_TIME_ON=15;
const int MIN_TIME_ON=1;
const int START_TIME_OFF=40;
const int MIN_TIME_OFF=1;
const int KEY_PRESSED_TIME=500;

void setup()
{
  // put your setup code here, to run once:
  pinMode(PHASE1_SWITCH,OUTPUT);
  pinMode(PHASE2_SWITCH,OUTPUT);
  pinMode(PHASE3_SWITCH,OUTPUT);
 
  pinMode(PUSH2,INPUT_PULLUP);

  analogReference(INTERNAL1V5);
 
  _step=1;
  time_count_on=START_TIME_ON;
  time_count_off=START_TIME_OFF;
  time=0;
  key_pressed_count=0;
  motor_active=false;
  motor_start=false;
  digitalWrite(PHASE1_SWITCH,LOW);
  digitalWrite(PHASE2_SWITCH,LOW);
  digitalWrite(PHASE3_SWITCH,LOW);
}

void loop()
{
  // put your main code here, to run repeatedly:
  if(digitalRead(PUSH2)==LOW){
    if(key_pressed_count==0){
      key_pressed_count=millis()+KEY_PRESSED_TIME;
    } else {
      if(key_pressed_count<millis()){
        motor_active=!motor_active;
        if(motor_active==true){
          motor_start=true;
        }
        key_pressed_count=millis()+5000;
      }
    }
  } else {
    key_pressed_count=0;
  }
  if(motor_active==true && motor_start==true){
    digitalWrite(PHASE1_SWITCH,HIGH);
    delay(150);
    digitalWrite(PHASE1_SWITCH,LOW);
//    delay(300);
 
    digitalWrite(PHASE2_SWITCH,HIGH);
    delay(100);
    digitalWrite(PHASE2_SWITCH,LOW);
//    delay(300);
 
    digitalWrite(PHASE3_SWITCH,HIGH);
    delay(80);
    digitalWrite(PHASE3_SWITCH,LOW);
//    delay(300);

    digitalWrite(PHASE1_SWITCH,HIGH);
    delay(60);
    digitalWrite(PHASE1_SWITCH,LOW);
//    delay(150);
 
    digitalWrite(PHASE2_SWITCH,HIGH);
    delay(60);
    digitalWrite(PHASE2_SWITCH,LOW);
//    delay(100);
 
    digitalWrite(PHASE3_SWITCH,HIGH);
    delay(60);
    digitalWrite(PHASE3_SWITCH,LOW);
//    delay(50);
    motor_start=false;
  }   

  if(motor_active==true && time==0){
    switch(_step){
      case 2:
        digitalWrite(PHASE1_SWITCH,HIGH);
        digitalWrite(PHASE2_SWITCH,LOW);
        digitalWrite(PHASE3_SWITCH,LOW);
        time=millis()+time_count_on;
        _step++;
        break;
      case 1:
      case 3:
      case 5:
        if(time_count_off!=0){
          digitalWrite(PHASE1_SWITCH,LOW);
          digitalWrite(PHASE2_SWITCH,LOW);
          digitalWrite(PHASE3_SWITCH,LOW);
          time=millis()+time_count_off;
        } else {
          time=millis();
        }
        delay(1);
        phase1_level=analogRead(PHASE1_LEVEL);
        phase2_level=analogRead(PHASE2_LEVEL);
        phase3_level=analogRead(PHASE3_LEVEL);
        if(phase1_level>phase2_level && phase1_level>phase3_level){
          _step=4;
        } else {
          if(phase2_level>phase1_level && phase2_level>phase3_level){
            _step=6;
          } else {
            _step=2;
          }
        }
        break;
      case 4:
        digitalWrite(PHASE1_SWITCH,LOW);
        digitalWrite(PHASE2_SWITCH,HIGH);
        digitalWrite(PHASE3_SWITCH,LOW);
        time=millis()+time_count_on;
        _step++;
        break;
      default:
        digitalWrite(PHASE1_SWITCH,LOW);
        digitalWrite(PHASE2_SWITCH,LOW);
        digitalWrite(PHASE3_SWITCH,HIGH);
        time=millis()+time_count_on;
        _step=1;
    };
    if(time_count_off>MIN_TIME_OFF){
      if(_step==1){
        time_count_off--;
      }
    }
    if(time_count_off<time_count_on){
      if(time_count_on>MIN_TIME_ON){
        time_count_on=time_count_off;
      }
    }
  }
  if(motor_active==true && time<millis()){ 
    time=0;
  }
  if(motor_active==false){
    time=0;
    time_count_on=START_TIME_ON;
    time_count_off=START_TIME_OFF;
    _step=1;
    digitalWrite(PHASE1_SWITCH,LOW);
    digitalWrite(PHASE2_SWITCH,LOW);
    digitalWrite(PHASE3_SWITCH,LOW);
  }
}

Com o código acima eu consigo manter o rotação constante em torno de 800 rpm apesar de que é possível perceber um flutuação na velocidade inicial. É possível eliminar esta flutuação usando as técnicas de controle PID que são o pesadelo de qualquer aluno de engenharia elétrica. Além disto o algoritmo para iniciar a rotação do motor não está bom e precisa ser melhorado. Mas com o circuito e o código acima eu consegui testar vários conceitos interessantes. E é na esperança de que as informações acima sejam de alguma utilidade para alguém que eu termino esta mensagem.

Eu realmente não quis concluir o meu projeto. Nos momentos iniciais de rotação do motor o circuito chega a consumir em torno de 3A e com o motor estabilizado em 800 rpm o circuito consome 1A. Daí dá para perceber que se o motor estiver rodando na velocidade máxima em que ele foi projetado que é 5200 rpm o consumo de energia diminui bastante. Por outro lado é impossível ou extremamente difícil controlar com precisão o acionamento de leds 86 vezes por segundo usando um microcontrolador trabalhando a 16Mhz. Lembrando que este mesmo microcontrolador teria que controlar também o acionamento das fases, ler de tempos em tempos botões para verificar se o usuário não quer interagir com o aparelho e se comunicar de tempos em tempos com um CI RTC tipo o DS1307. Simplesmente muita complexidade para um "projetinho simples" e eu perdi o interesse em continuar na pesquisa.

Mas de qualquer forma aí está a idéia para quem quiser continuar a pesquisar e construir o projeto.

Um abraço,


José Paulo

segunda-feira, 10 de março de 2014

Amplificador para fone de ouvido



 Olá,

Já faz um tempão que eu não escrevo nada no blog! Falta de tempo e de paciência também. Mas ei, eu agora estou de férias e pretendo recuperar o tempo perdido.

Um projetinho rápido que eu fiz a pedido de um amigo foi um amplificador estéreo para fone de ouvido. A idéia é bem simples: Um amplificador de baixa potência, alimentado pela rede elétrica, simples de usar, com controle de volume e que tenha uma boa qualidade de áudio.

Para a tarefa eu selecionei o C.I. TDA2822M que é um amplificador estéreo com encapsulamento DIP ou SMD de 8 pinos. Este C.I. é o 555 dos amplificadores de áudio. É um C.I. que vários fabricantes o produzem e em qualquer lojinha de eletrônica você acha fácil. Na configuração estéreo você consegue colocar para fora algo em torno de 0,6W e em configuração ponte (áudio mono) você consegue uma potência de 1,2W aproximadamente. Além disto a distorção harmônica fica em torno de 0,5% o que é muito bom. E se não bastasse todas as vantagens, ainda é um componente relativamente barato custando em lojas do ramo algo em torno de R$ 2,00 cada um. O link com o datasheet segue listado abaixo:

http://www.unisonic.com.tw/datasheet/TDA2822.pdf

Uma das premissas do projeto é que o amplificador fosse alimentado pela rede elétrica. Eu não queria embutir uma fonte de alimentação na mesma caixa do amplificador com receio que isto fosse gerar ruídos na saída de áudio devido a interferências eletromagnéticas. Com isto eu decidi usar fontes externas. Eu tenho o costume - não sei muito bem o porquê - de guardar as fontes de alimentação de equipamentos que eu descarto. Com isto eu tenho várias e várias fontes de alimentação com saída AC e DC e nas mais variadas tensões e correntes de operação. Então eu decidi por adotar um Jack DC J4 como porta de entrada para alimentação.

Um outro cuidado que eu tomei foi em usar uma caixa metálica ao invés de uma caixa plástica com o objetivo e a esperança que a caixa metálica funcionasse como uma gaiola de Faraday isolando o circuito de ruídos externos. A placa de circuito impresso é preso por um único parafuso à base da caixa que está ligado ao terra do circuito. Desta forma a base da caixa tem o mesmo potêncial que o terra do circuito, porém, eu inicialmente não tomei nenhum cuidado com a tampa da caixa. Quando eu testei o circuito eu percebi que ruído vindo de celulares e monitores próximos "vazava" no áudio e isto era uma coisa bastante irritante. Depois eu tive a idéia de raspar a tinta que faz o contato da base da caixa com a tampa. Para minha agradável surpresa, a interferência cessou completamente. Ao ponto de eu poder apoiar meu celular em cima da caixa do amplificador e não ouvir mais nenhuma interferência vinda do celular. Santo Faraday!

 Pelo incrível que pareça eu fiz duas revisões deste projeto: revisão A e revisão B. Na revisão A o TDA2822M é o único componente ativo. O problema da revisão A é que se você ligasse o aparelho com o fone fechado em sua orelha você escuta um som forte de "POC" que chegava a machucar e isto não era legal. Nada demais, basta você ligar o amplificador e depois colocar o fone de ouvido e tudo funcionaria ok. Mas com o sucesso da primeira versão mais pessoas me pediram para fazer o amplificador, então eu decidi que na próxima revisão eu iria atacar este problema. A solução foi a seguinte: Ao invés de ligar o TDA2822M direto á alimentação  eu liguei a alimentação do C.I. a um transistor NPN em configuração "seguidor de emissor" e coloquei um circuito RC na base do transistor de forma que quando a alimentação fosse ligada, a tensão de alimentação do C.I. subisse gradativamente. Posso dizer que este problema foi resolvido totalmente.

E é isto! Segue abaixo o link com o projeto do kicad.

https://dl.dropboxusercontent.com/u/62498964/Phone%20Amplifier.zip

Até breve,

José Paulo