Mostrando entradas con la etiqueta Inventos. Mostrar todas las entradas
Mostrando entradas con la etiqueta Inventos. Mostrar todas las entradas

lunes, 13 de mayo de 2019

Micromanipulator and 3 axis joystick, Arduino based

c








Arduino code

/* MICROMANIPULADOR
 
  90 parado
  Menor de 90, giro a la derecha
  Mayor 90 giro a la izquierda
  
   [##] --> derecha (menor 90)
  +----------+
  |          |
  |          |
  +----------+

  LED 3
 
 */


//Librerias

#include <Servo.h>

Servo servo_x;  // crea el objeto servo
 Servo servo_y;  // crea el objeto servo
  Servo servo_z;
  const int pot_x = A0;
  const int pot_y = A1;
  const int pot_z = A2;
 int pos_x; //Variables lectura
   int pos_y;
    int pos_z;

const int led = 3;
 
int paro = 90; //valor paro servo
int margen_sup = 55;//valores medios 52,53
int margen_inf = 45;
//##########################
//SETUP#####################

void setup() {
   Serial.begin(9600);
   servo_x.attach(9);  // vincula el servo al pin digital 9
     servo_y.attach(10);
       servo_z.attach(11);
       pinMode(led , OUTPUT);
}

void loop() {

 pos_x = map(analogRead(pot_x), 0, 1023, 0, 100);  // lee entrada analogica y trans a %
pos_y = map(analogRead(pot_y), 0, 1023, 0, 100);
pos_z = map(analogRead(pot_z), 0, 1023, 0, 100); 

Serial.print( pos_x);
 Serial.print(" ");
 Serial.print( pos_y);

 Serial.print(" ");
 Serial.println( pos_z);
             

 digitalWrite(led , LOW);
if(pos_x > margen_sup ){ servo_x.write(98);   }//98
if(pos_x > margen_sup + 15){ servo_x.write(180); digitalWrite(led , HIGH);}//180
if(pos_x < margen_inf){ servo_x.write(84); }//85
if(pos_x < margen_inf - 15){ servo_x.write(0); digitalWrite(led , HIGH);}//0

if(pos_x >= margen_inf && pos_x <= margen_sup){ servo_x.write(paro); }


if(pos_y > margen_sup){ servo_y.write(85); }//85
if(pos_y > margen_sup + 15){ servo_y.write(0);digitalWrite(led , HIGH); }//0
if(pos_y < margen_inf){ servo_y.write(98); }//98
if(pos_y < margen_inf - 15){ servo_y.write(180); digitalWrite(led , HIGH);}//180
if(pos_y >= margen_inf && pos_y <= margen_sup){ servo_y.write(paro); }

if(pos_z > margen_sup ){ servo_z.write(97); }
if(pos_z > margen_sup + 15){ servo_z.write(180); digitalWrite(led , HIGH);}

if(pos_z < margen_inf){ servo_z.write(84); }
if(pos_z < margen_inf - 15){ servo_z.write(0);  digitalWrite(led , HIGH);}
if(pos_z >= margen_inf && pos_z <= margen_sup){ servo_z.write(paro); }

  delay(100);


}

martes, 4 de diciembre de 2018

Tissue Processor II

Last year I built a DIY tissue processor based on Arduino


This device helps to dehydrate samples dipping them into increasing alcoholic baths. Despite its construction was a rewarding challenge for me and I am proud of this device, I think it is excessively complex. Due to that I don't see it like a reliable machine.

So I am going to build a second version based more in mechanics than in electronics. I will use mechanisms like the four bar arm linkage, a cams system and a Geneva wheel.

So I am going to build a second version replacing motors and sensor for more mechanical systems like a four bar arm linkage, cams systems and a Geneva wheel. That mechanisms would make this new tissue processor much more reliable than the previous one because it will need very few motors and sensors.


Auto apuntes

 -(05/12/2018). Los siguientes pasos serían:
  • Mejorar el diseño de la Rueda de Ginebra, utilizando software CAD y hacer más pruebas en madera contrachapada.
  • Hacer pruebas de material (metacrilato) y de anclaje de las ruedas a una base.
  • Redimensionar el diseño para hacerlo los más pequeño posible (tamaño de un libro grande). La idea es que pueda guardarse en una estantería. Este punto es más importante de lo que parece para la utilidad práctica del procesador (de nada servirá si se ha de guardar en un almacén inaccesible)

-(06/12/2018). Sobre la Rueda de Ginebra.



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); 
}
 
}

sábado, 21 de octubre de 2017

Aluminium basket for samples

I have designed a tiny basket for samples for my tissue processor. It is built by drilling and threading a 8mm aluminium bar.
 
Process

 6 mm inside

1 mm, holes


sábado, 5 de agosto de 2017

Planos del procesador con LibreCAD

He estado trasteando con un programa de CAD (computer-aided design), tal vez les suene el famoso AUTOCAD. Se trata programas de dibujo industrial o arquitectónico. 
Esta es la primera vez que hago algo con uno. He utilizado el LibreCAD para rediseñar el carrusel del procesador de tejidos que tengo entre manos.

En vez de "dibujar" he preferido indicarle al "CAD" los comandos para que fuera más preciso. Sin embargo, tienes que saber los puntos donde le vas a decir que dibuje lo que sea. Ej: círculo con centro en (0,0) y radio 15.

El carrusel tiene 12 agujeros, la única dificultat es la de hallar los centros para los agujeros que no estan sobre los ejes Y o X. Para ello téngase en cuenta la siguiente imagen.

Los agujeros iran a 30º y 60º, por lo que por trigonometria \(radio*sen(alfa)=Y\) y \(radio*cos(alfa)=X\). Para trazar la línea que corta el círculito (para poder taladrar el agujero) se ha procedido encontrando dos puntos alineados con el centro de este, con el mismo método.

Bueno, si esto es raro de entender, es porque esta raro explicado. Solo son apuntes. En el fondo (y en la superficie) lo que quiero es poner el dibujito de mi plano y ya está. Pues eso es todo. Arte, arte... esto si que es arte: 



jueves, 3 de agosto de 2017

Pruebas con procesador de tejidos DIY




Sirva esto como anotación personal.

Próximos pasos:
  • Probar el servo, que ha de ir a un Pin PWM. Hacía cosas raras al iniciarse, tal vez debiera colocarle un relé. 
  • Terminar el menú que ha de constar de las siguientes secciones:
    • Preprogramas: Son las rutinas básicas como:
      • Baños de deshidratación
      • Deshidratación y xilol
      • Deshidratación, xilol y parafina
      • Solo parafina,
      • Etc.
    • Programación
      • Le especificamos que ha de hacer
    • Utilidades
      • Permite mover los motores independientes y otras acciones. Para hacer pruebas sin tener que modificar el software de la máquina.
  • Hacer la caja. En principio sería de aluminio y metacrilato. Se compondría de dos partes, inferior y superior. La parte de arriba se quitaría como una tapa dejando al descubierto el brazo con el carrusel  y los controles. El brazo y el carrusel serían fácilmente extraíbles de la carcasa.
  • Perfeccionar el sistema de “encoder” óptico. Tendría que hacer un optoacoplador especial a partir de dos de ellos y usar solo un disco de posición en vez de dos. El sensor tendrá que ser móvil y ajustable con palomilla.
  • Pruebas con el porta-cables. Una vez se tenga la caja hay que ver cómo encaja todo.