Calculadora pizarra

CALCULINO

 

Introducción

Nuestra idea para el proyecto se centra en el desarrollo de un brazo robótico que escriba las operaciones que introduzcamos mediante un teclado, el mismo programa calcula el resultado de la operación y hace que nuestro robot lo escriba en una pizarra.

¿Por qué un brazo robótico?

Nuestro proyecto va destinado a la enseñanza de los más pequeños. Con nuestro brazo podemos enseñarles a realizar problemas aritméticos de forma dinámica, fácil y competitiva. 
 
En nuestro programa podemos cambiar el tiempo que el brazo tarda en resolver una operación para darle tiempo a los niños a resolverlo antes que el brazo robótico, de esta forma, el aprendizaje se hace más llevadero dando la sensación de compañía para los más pequeños. 

Materiales y presupuesto

Montaje

Creación de la estructura del brazo. Nuestro primer paso es realizar un primer prototipo del brazo robótico con el que realizaríamos las primeras pruebas de funcionamiento y calibración de los servomotores. Y así, después, poder crear el prototipo final.

Para crear el brazo utilizamos 5 palos de madera unidos por sus extremos mediante un nudo de alambre para crear las articulaciones. El soporte del rotulador se hizo con alambre dándole una forma circular del diámetro del rotulador para que quedara bien sujeto.

Para que el brazo hiciera bien el movimiento, ajustamos los nudos de las articulaciones para lograr un movimiento fluido en los codos, además de calibrar los servomotores para que cada parte del brazo se moviera en su totalidad (90º).

Para que el brazo dejara espacios al escribir, incluimos un tercer servomotor para realizar el movimiento de izado del rotulador.
 
Montaje del circuito: el primer paso que realizamos fue el de conectar los servomotores de los 2 brazos para calibrarlos y dejarlos en la posición correcta de salida. El siguiente paso fue conectar el siguiente servomotor para realizar el izado del rotulador y por último, conectar el keypad que usamos para introducir los datos al programa.
 
Montaje del prototipo final: como paso final construimos la estructura de soporte del brazo, que además nos servirá para ocultar los componentes. Para construir la estructura utilizamos 2 bloques de madera fijos a la base, para tener el soporte para la pizarra, y un tercer bloque de madera móvil, que es el que, con ayuda del servomotor, izará el brazo al acabar de escribir.
Una vez terminada la estructura procedimos a pegar los servomotores en sus respectivas posiciones:
 
  • El servomotor del izado lo unimos al bloque de madera móvil mediante un hilo y un brazo del servomotor.
  • Los dos servomotores restantes los pegamos a la parte superior del bloque de madera móvil y también los unimos a sus respectivas partes del brazo.

Esquema Hardware

 

Mejoras
 
  • Insertar un borrador para que elimine las operaciones tras realizarlas.
  • Materiales de mejor calidad. 
  • Un pegamento más persistente a la hora de pegar las piezas. 
  • Precisión en los movimientos del brazo al levantarse. 
  • Realizar operaciones más complejas.
 
 
#include <Key.h>
#include <Keypad.h>
#include <Servo.h>

//#define CALIBRACION
#define SERVOFAKTOR 650
/* En modo de calibración, ajuste los valores NULL para que los brazos de los servos esten en todo momento paralelos Ya sea al eje X o Y */
#define SERVOLEFTNULL 1290
#define SERVORIGHTNULL 620

#define SERVOPINELEVADOR  2       //  Pin 2 conexión del servo elevador 
#define SERVOPINIZQUIERDO  3      //  Pin 3 conexión del servo izquierdo
#define SERVOPINDERECHA 4         //  Pin 4 conexión del servo derecho

//Pin de los servos:
//Marron = negativo
//Rojo = 5V
//Naranja = pin


// definir posiciones del servo elevador
#define LIFT0 1600  // en la superficie de dibujo
#define LIFT1 10    // elevación entre escritura de numeros

// velocidad de brazo elevador, un número mayor es más lento
#define VELOCIDADELEVADOR 1500

// longitud de los brazos
#define L1 35
#define L2 60
#define L3 13.2

// puntos de origen de servo izquierda y derecha
#define O1X 22
#define O1Y -25
#define O2X 47
#define O2Y -25

int servoLift = 1500;

Servo servo1;  
Servo servo2;   
Servo servo3;    

volatile double lastX = 75;
volatile double lastY = 47.5;

int last_min = 0;

const byte filas = 4;
const byte columnas = 4;
byte pinsFilas[filas] = {13, 12, 11, 10};
byte pinsColumnas[columnas] = {9, 8, 7, 6};
char operacion[4];

int iniciox=0;
int inicioy=25;

char teclas [filas] [columnas]= {
  {'1','2','3','+'},
  {'4','5','6','-'},
  {'7','8','9','*'},
  {'.','0','=','/'}  
};

Keypad teclado = Keypad(makeKeymap(teclas), pinsFilas, pinsColumnas, filas, columnas);
char tecla;

void setup() 
{ 
  drawTo(0,25);
  lift(0);
  servo1.attach(SERVOPINELEVADOR);    //  servo elevador 
  servo2.attach(SERVOPINIZQUIERDO);   //  servo izquierdo
  servo3.attach(SERVOPINDERECHA);     //  servo derecho
  delay(1000);

  Serial.begin(9600);
} 

void loop() 
{ 
  
#ifdef CALIBRACION

// los brazos de los servos tendran 90 ° entre los movimientos, paralelo al eje X e Y
  drawTo(-3, 28);
  delay(500);
  drawTo(74.1, 28);
  delay(500);

#else 

  if (!servo1.attached()) servo1.attach(SERVOPINELEVADOR);
  if (!servo2.attached()) servo2.attach(SERVOPINIZQUIERDO);
  if (!servo3.attached()) servo3.attach(SERVOPINDERECHA);
  int i=0;
  tecla = teclado.getKey();
  while(i<4){
    if(tecla == NO_KEY){
    }
    else{
      lift(0);
      Serial.print(tecla);
      operacion[i]=tecla;
      int tecla2 = (int) tecla-48;
      number(iniciox, inicioy, tecla2, 0.9);
      iniciox=iniciox+10;
      i++;
    }
    tecla = teclado.getKey();
  }
    if(i==4){
      int a1 = (int) operacion[0]-48;
      int a2 = (int) operacion[2]-48;
      switch (operacion[1]) {
        case '+':
          if((a1+a2)<10){
            number(iniciox, inicioy, a1+a2, 0.9);
          }
          else{
            int resultado = (a1+a2)/10;
            number(iniciox, inicioy, resultado, 0.9);
            resultado = (a1+a2)%10;
            iniciox=iniciox+10;
            number(iniciox, inicioy, resultado, 0.9);
          }
          break;
        case '-':
          if((a1-a2)>=0){
            number(iniciox, inicioy, a1-a2, 0.9);
          }
          else{
            int resultado = abs(a1-a2);
            number(iniciox, inicioy, -3, 0.9);
            iniciox=iniciox+10;
            number(iniciox, inicioy, resultado, 0.9);
          }
          break;
        case '*':
          if(a1*a2<10){
            number(iniciox, inicioy, a1*a2, 0.9);
          }
          else{
            int resultado = a1*a2/10;
            number(iniciox, inicioy, resultado, 0.9);
            resultado = a1*a2%10;
            iniciox=iniciox+10;
            number(iniciox, inicioy, resultado, 0.9);
          }
          break;
        case '/':
          number(iniciox, inicioy, a1/a2, 0.9);
          break;
      }
      i=0;
    }

#endif
} 

// El punto de partida es (bx,by). La escala 1 es igual a una fuente de 20 mm.
void number(float bx, float by, int num, float scale) {

  switch (num) {

  case 0:
      lift(1);
      drawTo(bx + 12 * scale, by + 6 * scale);
      lift(0);
      bogenGZS(bx + 7 * scale, by + 10 * scale, 10 * scale, -0.8, 6.7, 0.5);
      break;
    
  case 1:
      lift(1);
      drawTo(bx + 3 * scale, by + 15 * scale);
      lift(0);
      drawTo(bx + 10 * scale, by + 20 * scale);
      drawTo(bx + 10 * scale, by + 0 * scale);
      break;
    
  case 2:
      lift(1);
      drawTo(bx + 2 * scale, by + 13 * scale);
      lift(0);
      bogenUZS(bx + 8 * scale, by + 14 * scale, 6 * scale, 3, -0.8, 1);
      drawTo(bx + 1 * scale, by + 0 * scale);
      drawTo(bx + 12 * scale, by + 0 * scale);
      break;
    
  case 3:
      lift(1);
      drawTo(bx + 2 * scale, by + 17 * scale);
      lift(0);
      bogenUZS(bx + 5 * scale, by + 15 * scale, 7 * scale, 3, -2, 1);
      bogenUZS(bx + 5 * scale, by + 5 * scale, 7 * scale, 1.57, -3, 1);
      break;
    
  case 4:
      lift(1);
      drawTo(bx+1*scale,by+20*scale);
      lift(0);
      drawTo(bx+1*scale,by+10*scale);
      drawTo(bx+7*scale,by+10*scale);
      drawTo(bx+7*scale,by+20*scale);
      drawTo(bx+7*scale,by+0*scale);
      break;
    
  case 5:
      lift(1);
      drawTo(bx + 2 * scale, by + 5 * scale);
      lift(0);
      bogenGZS(bx + 5 * scale, by + 6 * scale, 6 * scale, -2.5, 2, 1);
      drawTo(bx + 5 * scale, by + 20 * scale);
      drawTo(bx + 12 * scale, by + 20 * scale);
      break;
    
  case 6:
      lift(1);
      drawTo(bx + 2 * scale, by + 10 * scale);
      lift(0);
      bogenUZS(bx + 7 * scale, by + 6 * scale, 7 * scale, 2, -4.4, 1);
      drawTo(bx + 11 * scale, by + 20 * scale);
      break;
    
  case 7:
      lift(1);
      drawTo(bx + 0 * scale, by + 20 * scale);
      lift(0);
      drawTo(bx + 13 * scale, by + 20 * scale);
      drawTo(bx + 0 * scale, by + 0);
      break;
    
  case 8:
      lift(1);
      drawTo(bx + 5 * scale, by + 10 * scale);
      lift(0);
      bogenUZS(bx + 5 * scale, by + 15 * scale, 5 * scale, 4.7, -1.6, 1);
      bogenGZS(bx + 5 * scale, by + 5 * scale, 5 * scale, -4.7, 2, 1);
      break;

  case 9:
      lift(1);
      drawTo(bx + 9 * scale, by + 11 * scale);
      lift(0);
      bogenUZS(bx + 7 * scale, by + 15 * scale, 8 * scale, 4, -0.5, 1);
      drawTo(bx + 5 * scale, by + 0);
      break;

  case -1:  // División
      lift(1);
      drawTo(bx+10*scale, by+20* scale);
      lift(0);
      drawTo(bx, by);
      break;
  
  case -3:  // Resta
      lift(1);
      drawTo(bx+1*scale, by+10*scale);
      lift(0);
      drawTo(bx + 11 * scale, by + 10 * scale);
      break;
    
  case -5:  // Suma
      lift(1);
      drawTo(bx+1*scale, by+10*scale);
      lift(0);
      drawTo(bx + 11 * scale, by + 10 * scale);
      lift(1);
      drawTo(bx+5*scale, by+15*scale);
      lift(0);
      drawTo(bx + 5 * scale, by + 5 * scale);
      break;
      
  case -6:  // Multiplicación
      lift(1);
      drawTo(bx+5* scale, by+10*scale);
      lift(0);
      bogenGZS(bx + 7 * scale, by + 15 * scale, 8 * scale, 4, -0.5, 1);
      break;
      
  case 13:  // Igual
      lift(1);
      drawTo(bx+1*scale, by+13*scale);
      lift(0);
      drawTo(bx + 11 * scale, by+13*scale);
      lift(1);
      drawTo(bx+1*scale, by+7*scale);
      lift(0);
      drawTo(bx + 11 * scale, by+7*scale);
      break;
  }
}



void lift(char lift) {
  switch (lift) {

  case 0:
      if (servoLift >= LIFT0) {
      while (servoLift >= LIFT0) 
      {
        servoLift--;
        servo1.writeMicroseconds(servoLift);        
        delayMicroseconds(VELOCIDADELEVADOR);
      }
    } 
    else {
      while (servoLift <= LIFT0) {
        servoLift++;
        servo1.writeMicroseconds(servoLift);
        delayMicroseconds(VELOCIDADELEVADOR);
      }
    }
    break;

  case 1: 
    if (servoLift >= LIFT1) {
      while (servoLift >= LIFT1) {
        servoLift--;
        servo1.writeMicroseconds(servoLift);
        delayMicroseconds(VELOCIDADELEVADOR);
      }
    } 
    else {
      while (servoLift <= LIFT1) {
        servoLift++;
        servo1.writeMicroseconds(servoLift);
        delayMicroseconds(VELOCIDADELEVADOR);
      }
    }
    break;
  }
}


void bogenUZS(float bx, float by, float radius, int start, int ende, float sqee) {
  float inkr = -0.05;
  float count = 0;

  do {
    drawTo(sqee * radius * cos(start + count) + bx,
    radius * sin(start + count) + by);
    count += inkr;
  } 
  while ((start + count) > ende);

}

void bogenGZS(float bx, float by, float radius, int start, int ende, float sqee) {
  float inkr = 0.05;
  float count = 0;

  do {
    drawTo(sqee * radius * cos(start + count) + bx,
    radius * sin(start + count) + by);
    count += inkr;
  } 
  while ((start + count) <= ende);
}


void drawTo(double pX, double pY) {
  double dx, dy, c;
  int i;

  dx = pX - lastX;
  dy = pY - lastY;
  c = floor(4 * sqrt(dx * dx + dy * dy));

  if (c < 1) c = 1;

  for (i = 0; i <= c; i++) {
    set_XY(lastX + (i * dx / c), lastY + (i * dy / c));

  }

  lastX = pX;
  lastY = pY;
}

double return_angle(double a, double b, double c) {
  return acos((a * a + c * c - b * b) / (2 * a * c));
}

void set_XY(double Tx, double Ty) 
{
  delay(1);
  double dx, dy, c, a1, a2, Hx, Hy;
  
  dx = Tx - O1X;
  dy = Ty - O1Y;

  c = sqrt(dx * dx + dy * dy); 
  a1 = atan2(dy, dx); 
  a2 = return_angle(L1, L2, c);

  servo2.writeMicroseconds(floor(((a2 + a1 - M_PI) * SERVOFAKTOR) + SERVOLEFTNULL));

  a2 = return_angle(L2, L1, c);
  Hx = Tx + L3 * cos((a1 - a2 + 0.621) + M_PI);
  Hy = Ty + L3 * sin((a1 - a2 + 0.621) + M_PI);

  dx = Hx - O2X;
  dy = Hy - O2Y;

  c = sqrt(dx * dx + dy * dy);
  a1 = atan2(dy, dx);
  a2 = return_angle(L1, (L2 - L3), c);

  servo3.writeMicroseconds(floor(((a1 - a2) * SERVOFAKTOR) + SERVORIGHTNULL));
}

También te podría gustar...

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *