viernes, 18 de mayo de 2018

Arduino DIY centrifuge

Now I am working on a DIY mini centrifuge.

For this project I use a hard disk motor. This motor is brushless, so it produces little friction and can reach higher speeds than standard motors. Furthermore, it is very easy to recycle one from an old hard disk.

I make the centrifuge enclosure with layers of Wood. I carved out different shapes to make space for the electronic components inside, as shown in the picture.




The centrifuge will be controlled by an Arduino micro controller. I will use an infrared sensor to count how fast the motor spins.

I have an old lab centrifuge which I bought in a second hand market. I put a tachometer, based also on an arduino, into that apparatus. Then, I realized that the centrifuge speed tended to change progressively. Its speed was unstable.

In this mini centrifuge, the arduino will hopefully regulate the engine speed if that differs from the speed set by the arduino. I use a special electronic component: "Electronic Speed Control", or ESC, which is used to control brushless drone or helicopter motors, too. That device allows the arduino to control the motor easily.

Using a little screen and three buttons, it will be possible to program the speed and time of working of the centrifuge.



People in Italki had helped me whit this text


Finally...

Arduino code, for not lose it.

/*
Centrifuga.
T. Espinosa. 2018.
*/

//######################################################
//# LIBRERIAS ##########################################
//######################################################
#include  <Wire.h>
#include  <LiquidCrystal_I2C.h>
#include <Servo.h>

//######################################################
//# VARIABLES Y ETC ####################################
//######################################################

//GND de fuente y Arduino siempre conectados. OJO!

//------------------------------------------------------
//- MOTOR   --------------------------------------------
//------------------------------------------------------
Servo servo;
Servo servoBrazo;
int servoPos = 0;

//------------------------------------------------------
//- variables   --------------------------------------------
//------------------------------------------------------

 unsigned long tiempo = 60;//Tiempo base

//------------------------------------------------------
//- TACOMETRO  --------------------------------------------
//------------------------------------------------------
float rev=0;

int rpm2;
int oldtime=0;
int timex;

void isr(){//funcion que llama la inerrupcion
rev++;//incrementa revoluciones en 1
}

/*
 Valores verificados empiricamente:
 servo 85. 14vps -- 840rpm
 servo 95. 30vps -1800rpm
 servo 105. 44 vps--2640 rpm
 servo 110. 60 vps-- 3600rpm. 

 Las interrupciones cuentan de más, supongo que por el tipo de lectura, prefiero ajustar empiricamente y ya está.
  */

//------------------------------------------------------
//- LCD ------------------------------------------------
//------------------------------------------------------

// Aqui se configuran los pines asignados a la pantalla del PCF8574
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
//Pines: SCL ->A0, SDA ->A1. Son estandart.


//------------------------------------------------------
//- BOTONES --------------------------------------------
//------------------------------------------------------

const int bot_blue = 6;//BOTON AZUL
const int bot_up = 3;
const int bot_down = 4;

//------------------------------------------------------
//- BUZZER --------------------------------------------
//------------------------------------------------------

const int buzzer = 5;
void s_entrada()
{
  for(int i =0 ;i<2;i++)
  {
  tone(buzzer, 3800, 80);//frecuencia, milisegundos
  delay(120);
  tone(buzzer, 3800, 80);//frecuencia, milisegundos
  delay(120);
  }
}
//-----------------------
void sonido_fin()
{
   int trono=300;
  
      for (int x=0;x<12; x++)
      {
         tone(buzzer, trono, 100);     
         delay(130);
         trono=trono+200;
       }
}


//######################################################
//# SETUP  #############################################
//######################################################

void setup()
{
   Serial.begin(9600);
  attachInterrupt(0,isr,RISING); //para poner en setup ¿?¿? 0 es pin 2, 1 es pin 3.
 servoBrazo.write(0);//emieza con motor apagado

  lcd.begin(16, 2);// Indica  LCD 16x2

  pinMode(bot_blue, INPUT);  //BOTONES
  pinMode(bot_up, INPUT); 
  pinMode(bot_down  , INPUT); 
 servoBrazo.attach(9);//donde va el motor

  for(int i = 0; i< 3; i++)//3 PARPADEOS DE LUZ DE PANTALLA
  {
    lcd.backlight();
    delay(150);
    lcd.noBacklight();
    delay(150);
     tone(buzzer, 4800, 80);//frecuencia, milisegundos
  }
   lcd.backlight();
  delay(400);
  // Mover el cursor a la primera posición de la pantalla (0, 0)
  lcd.setCursor ( 0, 0 );
  lcd.print("---CENTRIFUGA---");
  // Mover el cursor a la segunda linea (1) primera columna
  lcd.setCursor ( 0, 1 );
  // Imprimir otra cadena en esta posicion
  lcd.print("Pulsa Boton Azul");

}

//######################################################
//# INICIO  #############################################
//######################################################

void loop()
{

  int boton_azul = digitalRead(bot_blue);

  while(boton_azul == LOW) //espera que se apriete azul
    {   
      boton_azul = digitalRead(bot_blue);
      delay(100);
     }
    
   tone(buzzer, 3000, 100);//frecuencia, milisegundos
   delay(500);
   lcd.clear();//limpia pantalla
  
 boton_azul = digitalRead(bot_blue);  //lectura digital de
 int boton_up = digitalRead(bot_up);
 int boton_down = digitalRead(bot_down);

 int revol = 2000;

 s_entrada();//sonido al entrar
while(boton_azul == LOW) //PREGUNTA RPM ------------------------------------------
    {
     lcd.setCursor ( 0, 0 );
     lcd.print("RPM:     Ajuste");
     lcd.setCursor ( 4, 0 );
     lcd.print("    ");
     lcd.setCursor ( 4, 0 );
     lcd.print(revol);
     lcd.setCursor ( 0, 1 );        
     lcd.print("Salir Pulsa Azul");

     int boton_up = digitalRead(bot_up);
     int boton_down = digitalRead(bot_down);

     if (boton_up == HIGH)
          {
          tone(buzzer, 2000, 100);//frecuencia, milisegundos
          delay(80);
          revol=revol+25;
          if (revol > 9500){revol = 9500;}
          boton_up = digitalRead(bot_up);
          }
     if (boton_down == HIGH)
          {
          tone(buzzer, 2000, 100);//frecuencia, milisegundos
          delay(80);
          revol=revol-25;
         if (revol < 0){revol = 0;}
          boton_down = digitalRead(bot_down);
            }
               
     delay(50);
    
    boton_azul = digitalRead(bot_blue); 
    }
       lcd.clear();//limpia pantalla
        boton_azul = LOW; 

  tiempo=60;

   s_entrada();//sonido al entrar
   delay(500);
  
    while(boton_azul == LOW) //PREGUNTA TIEMPO------------------------
    {
     lcd.setCursor ( 0, 0 );
     lcd.print("Time:    Ajuste");
     lcd.setCursor ( 5, 0 );
     lcd.print("    ");
     lcd.setCursor ( 5, 0 );
     lcd.print(tiempo);
     lcd.setCursor ( 0, 1 );        
     lcd.print("Salir Pulsa Azul");

     int boton_up = digitalRead(bot_up);
     int boton_down = digitalRead(bot_down);

     if (boton_up == HIGH)
          {
          tone(buzzer, 2000, 100);//frecuencia, milisegundos
          delay(100);
         tiempo=tiempo+10;
          boton_up = digitalRead(bot_up);
          }
     if (boton_down == HIGH)
          {
          tone(buzzer, 2000, 100);//frecuencia, milisegundos
          delay(100);
           tiempo=tiempo-10;
        if (tiempo > 100000){tiempo = 0;}
          boton_down = digitalRead(bot_down);
            }
       
     delay(80);
    
    boton_azul = digitalRead(bot_blue); 
    }
   
  lcd.clear();//limpia pantalla
  boton_azul = LOW; 
  delay(500);

   s_entrada();//sonido al entrar
 while(boton_azul == LOW) //RESULTADOS------------------------
    {
     lcd.setCursor ( 0, 0 );
     lcd.print("RPM: ");
     lcd.setCursor ( 4, 0 );
     lcd.print(revol);
     lcd.setCursor ( 10, 0 );
     lcd.print("T: ");
     lcd.setCursor ( 12, 0 );
     lcd.print(tiempo);

     lcd.setCursor ( 0, 1 );        
     lcd.print("Start Pulsa Azul");

   // lcd.scrollDisplayLeft();
    //lcd.scrollDisplayRight();
    //delay (200);
               
     delay(100);
 
    boton_azul = digitalRead(bot_blue); 
    }

  
//#################################################
//EJECUCION #######################################
//------------------------------------------------
 
int autoajuste = 0; //contador para autoajuste
int velo_ini; //Velocidad mapeada de variable revol, preguntada antes
int ajuste; //Variable que usara en servo()

velo_ini = map(revol, 0, 10000, 0,9); //mapeo las revoluciones introducidas
                                      //iniciamos el motor a una velocidad de servo

switch (velo_ini) //+++pendiente ajuste empirico de valores+++
{
 case 0: //0-1000
   ajuste = 80;
   servoBrazo.write(ajuste);
    break;

 case 1://1000-2000
   ajuste = 90;
   servoBrazo.write(ajuste);
    break;

 case 2://2000-3000
   ajuste = 100;
   servoBrazo.write(ajuste);
    break;

 case 3://3000-4000
   ajuste = 110;
   servoBrazo.write(ajuste);
    break;

 case 4://4000-5000
   ajuste = 120;
   servoBrazo.write(ajuste);
    break;

 case 5://5000-6000
   ajuste = 130;
   servoBrazo.write(ajuste);
    break;

 case 6://6000-7000
   ajuste = 140;
   servoBrazo.write(ajuste);
    break;

 case 7://7000-8000
   ajuste = 150;
   servoBrazo.write(ajuste);
    break;

 case 8://8000-9000
   ajuste = 160;
   servoBrazo.write(ajuste);
    break;

 case 9://9000-10000
   ajuste = 170;
   servoBrazo.write(ajuste);
    break;
}//fin de switch---------


//Pantalla De ejecucion-----------
/*
  X|0123456789A12345
  ------------------
  0|RPM:10000 T:
  1|AC:    AC:
*/

  lcd.clear();//limpia pantalla
  s_entrada();//sonido al entrar
  delay(500);

 //Cosas fijas en pantalla:

     lcd.setCursor ( 0, 0 ); //Revoluciones+++++
     lcd.print("RPM: "); 
     lcd.setCursor ( 4, 0 );
     lcd.print(revol);

     lcd.setCursor ( 10, 0 );//Tiempo++++
     lcd.print("T: ");
     lcd.setCursor ( 12, 0 );
     lcd.print(tiempo);


     //MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMm
     //FASE DE AJUSTE------------------
     //mmmmmMMMMMmmmmmmmMMMMMmmmMMMmmmMMMMmmMMM
    
int histeresis_bruta = 150;

     while(!(rpm2 > (revol - histeresis_bruta) && rpm2 < (revol + histeresis_bruta)))
     {
if (rpm2 < (revol - histeresis_bruta)){ajuste = ajuste + 2;}
if (rpm2 > (revol + histeresis_bruta)){ajuste = ajuste - 2;}
if (ajuste >180){ajuste = 180;} 
   servoBrazo.write(ajuste);
     lcd.setCursor ( 0, 1 );
     lcd.print("# AJUSTANDO");
        lcd.setCursor ( 12, 1 );
    // lcd.print(ajuste);
         lcd.print(rpm2);
    delay(80);
     lcd.setCursor ( 0, 1 );
    lcd.print("  AJUSTANDO");
    delay(80);

 //.....tacometro --->

  delay(300); //este tiempo es el que cuenta la interrupcion
  detachInterrupt(0); //anula la interrupcion
  timex = millis()-oldtime;
  rpm2=(rev/timex)*60000; //da las revoluciones por minuto.  De milisegundos a minuto

  rpm2=rpm2/2.8;  //ajuste empirico

  oldtime=millis(); //pone tiempo a 0
  rev=0; //pone revoluciones a 0
    
  attachInterrupt(0,isr,RISING); //Volvemos a activar la interrupcción

  //....fin tacometro---<

      }

     // Fin ajsute------mMMMmMMMmmmMMMmmmmMMmmmmMMmm

     lcd.setCursor ( 0, 1 );
     lcd.print("                ");
     lcd.setCursor ( 0, 1 );
     lcd.print("AC: ");
     lcd.setCursor ( 9, 1 );
     lcd.print("AC: ");
    

//Temporizacion---------------------
  
 unsigned long inicio;//temporizador
 unsigned long fin_ciclo;
   inicio = millis();
   fin_ciclo = tiempo*1000; //segundos x 1000

while( millis() < (inicio + fin_ciclo)) //BUCLE TIEMPO XXXXXXXXXXXXXXXXXXXXXXXXXXX

{

  //PANTALLA variable----
  lcd.setCursor ( 4, 1 );
  lcd.print("     ");//Borra 5 espacios
  lcd.setCursor ( 4, 1 );
  lcd.print(rpm2);//Revoluciones actuales

  lcd.setCursor ( 12, 1 );
  lcd.print("    ");//Borra 3 espacios
    int resta =(inicio + fin_ciclo - millis())/1000;
  lcd.setCursor ( 12, 1 );
  lcd.print(resta);//Tiempo actual

  //.....tacometro --->

  delay(300); //este tiempo es el que cuenta la interrupcion
  detachInterrupt(0); //anula la interrupcion
  timex = millis()-oldtime;
  rpm2=(rev/timex)*60000; //da las revoluciones por minuto.  De milisegundos a minuto

  rpm2=rpm2/2.8;  //ajuste empirico

  oldtime=millis(); //pone tiempo a 0
  rev=0; //pone revoluciones a 0
    
  attachInterrupt(0,isr,RISING); //Volvemos a activar la interrupcción

  //....fin tacometro---<

servoBrazo.write(ajuste);//Envia dato a motor

//--autoajuste---
//Ajusta rpm real con el programado

int histeresis = 50;
autoajuste++;
if (autoajuste > 4)//se autoajuta cada x bucles
{
autoajuste=0;
if (rpm2 < (revol - histeresis)){ajuste = ajuste + 1;}
if (rpm2 > (revol + histeresis)){ajuste = ajuste - 1;}
if (ajuste >180){ajuste = 180;}
}

//--fin autoajuste--

// VERIFICACIONES ++++++++++
Serial.print("Revol: ");//verificamos dato en serial para ajuste---------
Serial.print(revol);
Serial.print(". ajuste mapeado: ");
Serial.print(ajuste);
Serial.print(". RPM: ");
Serial.println(rpm2);

Serial.print("inicio: ");
Serial.print(inicio);
Serial.print(". fin ciclo(tx1000): ");
Serial.print(fin_ciclo);
Serial.print(". millis(): ");
Serial.println(millis());

// FIN VERIFICACIONES ++++++++++

 } //FIN BUCLE TIEMPO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

//Se ha cumplido el tiempo y sale del bucle----------------

//PANTALLA FINALxxxxxxxxxxxxxxxxxxxxxxxxxxx

   /*  lcd.setCursor ( 0, 0 ); //Revoluciones+++++
     lcd.print("RPM: "); 
     lcd.setCursor ( 4, 0 );
     lcd.print(revol);

     lcd.setCursor ( 10, 0 );//Tiempo++++
     lcd.print("T: ");
     lcd.setCursor ( 12, 0 );
     lcd.print(tiempo);
*/
lcd.setCursor ( 15, 0 );
  lcd.print("-- - - - - - -");
     lcd.setCursor ( 0, 1 );
     lcd.print("FIN PROGRAMA   - Pulsa Azul -");
servoBrazo.write(0);
sonido_fin();
boton_azul = LOW;

while(boton_azul == LOW) //Se queda aqui siempre
{

 //tone(buzzer, 5000, 150);//f 
   lcd.scrollDisplayLeft();
    delay(250);

    boton_azul = digitalRead(bot_blue); 

}


boton_azul = LOW;
  tone(buzzer, 2400, 600);//f 
         lcd.clear();//limpia pantalla
  delay(1000);   

rpm2=0; //ponemos a 0
while(boton_azul == LOW) //Se queda aqui siempre
{
    lcd.setCursor ( 0, 0 );
     lcd.print("Nuevo programa?");

     lcd.setCursor ( 0, 1 );        
     lcd.print("   Pulsa Azul");
     delay(200);

    boton_azul = digitalRead(bot_blue); 
}
 
}

No hay comentarios: