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

Um comentário:

  1. A forma correta de se excitar as bobinas de um motor BLDC pode ser vista neste interessante diagrama da Nidec, que fabrica motores para HDDs:

    http://www.nidec.com/en-NA/technology/motor/basic/00020/

    ResponderExcluir