TAP, Máquina Expendedora

Introducción

TAP es una máquina expendedora que en vez de soltar los objetos que guarda metiendo dinero lo hace mediante una serie de preguntas de cultura general, que deberás  ir respondiendo para poder obtener una recompensa del interior de la máquina. 

Autoría

  • Tarik Saghouani Ben-Khalek
  • Ana Tongtong Xu
  • Pablo Sánchez Gómez

Componentes utilizados

  • Arduino Mega: 14 €
  • 2 Proto placas
  • Sensor de ultrasonido
  • 4 motores DC: 3,80 €
  • Pantalla LCD
  • Pantalla táctil: 13 €
  • Zumbador
  • Leds azules
  • Resistencia variable
  • Transistores 2n222: 1,20 €
  • Alambre metálico
  • Pila 9V: 1,10 €
  • Plástico transparente
  • Láminas de madera: 9,54 €
  • Pintura en spray: 3,95 €
  • Silicona: 0,60 €
  • Cinta aislante
  • Soldador
  • Cables: 0,60 €
  • Imanes: 0,74 €
  • Bisagras: 0,54 €

Presupuesto total : 49,07 €


Esquema principal

Para poder realizar este proyecto hemos tenido que investigar cómo funcionaba el mecanismo de espirales de las máquinas expendedoras.

Como queríamos incluir en la maquina tanto una pantalla LCD (para que el usuario sepa en todo momento cuantos puntos tiene en esa partida) como una pantalla táctil en la se mostraran las preguntas y sus distintas opciones. El usuario solo tiene que pulsar en aquella que crea correcta y el zumbador hará un sonido u otro en función si la respuesta que ha dado era la correcta o no, si lo es se le sumará al contador un punto (pantalla LCD) y si no lo es el juego terminara y le caerá uno de los productos si ha obtenido suficientes puntos.

Nuestro proyecto tiene una fuente de alimentación adicional aparte del Arduino ya que este no era capaz de suministrar suficiente energía a los motores que elegimos.

Debido a ello tuvimos que incluir una pila de 9V.

Estructura del hardware

Cómo se hizo

Primero medimos, construimos y pintamos la estructura inicial de la caja, luego hicimos un falso fondo que soportara las espirales y escondiera los motores y sus cables, después hicimos la puerta y la colocamos con dos bisagras al resto de la máquina y finalmente instalamos las pantallas y todo el cableado consiguiente.

Diseño del circuito

En este esquema se establecen las conexiones de todos los elementos excepto la pantalla TFT para más claridad en el esquema.
Correspondencia de pines entre el Arduino y pantalla TFT

Código de TAP

Para el mejor entendimiento del código se divide en varios ficheros:

maquina.ino : contiene el programa principal.

#include"maquina.h"
void setup() {
  pinMode(R1,OUTPUT);
  pinMode(R2,OUTPUT);
  pinMode(R3,OUTPUT);
  pinMode(R4,OUTPUT);
  pinMode(1,OUTPUT);
  digitalWrite(1,HIGH);
  Serial.begin(9600);
  Serial.print("Starting...");
  randomSeed(analogRead(0));
  insertPreguntas();
  lcd.begin(16, 2);
  tft.reset();
  tft.begin(0x9341);
  tft.setRotation(1);
  tft.fillScreen(BLACK);
  drawInicio();
}
void loop() {
  empieza();
  if(start){
    contador();
    juego();
    drawFin();
    caePremio();
  }
}

maquina.h: contiene las funciones y las librerías que utiliza el programa para el correcto funcionamiento de este.

#include "pregunta.h"
#include <Elegoo_GFX.h>
#include <Elegoo_TFTLCD.h>
#include <TouchScreen.h>
#include<LiquidCrystal.h>
#include "SR04.h"

/******Pines TFT LCD****************************/
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin

/*******Pines Ultrasonido ********************/
#define TRIG_PIN 34 //blanco
#define ECHO_PIN 36 //morado 

/*******Pines LCD **************************/
/* The circuit:
   LCD RS pin to digital pin 22
   LCD Enable pin to digital pin 24
   LCD D4 pin to digital pin 26
   LCD D5 pin to digital pin 28
   LCD D6 pin to digital pin 30
   LCD D7 pin to digital pin 32
*/
/***********Pines Buzzer***************/
#define BUZZER 20
/***********Pines motores*************/
#define R1 46
#define R2 48
#define R3 52
#define R4 50

// Assign human-readable names to some common 16-bit color values:
#define BLACK   0x0000
#define RED     0xF800
#define WHITE   0xFFFF
#define YELLOW  0XFFE0
#define ILI9341_BLUE        0x001F      /*   0,   0, 255 */
#define ILI9341_RED         0xF800      /* 255,   0,   0 */
#define ILI9341_WHITE       0xFFFF      /* 255, 255, 255 */
#define ILI9341_GREENYELLOW 0xAFE5      /* 173, 255,  47 */

#define MINPRESSURE 10
#define MAXPRESSURE 1000

#define TEXT_X 0
#define TEXT_Y 10
#define TEXT_W 320
#define TEXT_H 80
#define TEXT_TSIZE 2

#define YP A2  
#define XM A3  
#define YM 8  
#define XP 9  

#define TS_MINX 116
#define TS_MAXX 951
#define TS_MINY 100
#define TS_MAXY 905
#define T_INICIAL 60

SR04 sr04 = SR04(ECHO_PIN, TRIG_PIN);
LiquidCrystal lcd(22, 24, 26, 28, 30, 32);
Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

/*****Variables globales****/
bool start = false;
static int cont = T_INICIAL;
static int puntos = 0;
static int respuesta = 0;
bool falla = false;
bool pulsado = false;
bool buttonEnabled = true;
Pregunta *preguntas[41]; //preguntas como puntero

void drawInicio() {
  //Ready
  tft.drawRect(0, 0, 319, 240, WHITE);
  tft.setCursor(100, 30);
  tft.setTextColor(WHITE);
  tft.setTextSize(4);
  tft.print("READY");
  //GO!
  tft.setCursor(80, 100);
  tft.setTextColor(RED);
  tft.setTextSize(4);
  tft.print("GO!");
  //Creacion botton rojo
  tft.fillRect(60, 180, 200, 40, RED);
  tft.drawRect(60, 180, 200, 40, WHITE);
  tft.setCursor(80, 188);
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.print("START");
}
void empieza() {
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
  digitalWrite(13, LOW);
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);
  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
    p.x = map(p.x, TS_MAXX, TS_MINX, 320, 0);
    p.y = map(p.y, TS_MAXY, TS_MINY, 260, 0);
    Serial.print("X = "); Serial.println(p.x);
    Serial.print("\tY = "); Serial.println(p.y);
    if (p.x > 60 && p.x < 260 && p.y > 204 && p.y < 245 && buttonEnabled) {
      tft.fillScreen(BLACK); //Limpieza de pantalla
      buttonEnabled = false;
      start =  true;
    }
  }
}

void contador() {
  lcd.setCursor(0, 0);
  lcd.print("Puntos: ");lcd.print(puntos);
  Serial.print("Puntos: ");Serial.println(puntos);
}

/*Con la memoria que tenemos solo nos deja insertar hasta 41 preguntas*/

void  insertPreguntas() {
  preguntas[0] = new Pregunta("A que continente pertenece Suazilandia?", "Europa", "Africa", "Asia", "America", false, 2);
  preguntas[1] = new Pregunta("Cuantos sangre tiene un ser humano exactamente?", "4-6L", "1L", "7L", "10L", false, 1);
  preguntas[2] = new Pregunta("Donde está Guyana?", "Africa", "Asia", "America", "Oceania", false, 3);
  preguntas[3] = new Pregunta("Quien es el mascota de SEGA?", "Ryu", "Mario", "Pac Man", "Sonic", false, 4);
  preguntas[4] = new Pregunta("Cuantos colores tenia la primera tarjeta grafica?", "3", "1", "2", "0", false, 3);
  preguntas[5] = new Pregunta("En que anyo se produjo el accidente Chernobyl?", "1976", "1980", "1986", "1990", false, 3);
  preguntas[6] = new Pregunta("En que anyo se inicio la primera guerra mundial?", "1912", "1914", "1915", "1916", false, 2);
  preguntas[7] = new Pregunta("Cual es el principal componente de la lejia", "Amoniaco", "Fluor", "Cloro", "Sodio", false, 3);
  preguntas[8] = new Pregunta("En que pais africano se encuentra el Kilimanjaro?", "Kenia", "Zambia", "Guinea", "Tanzania", false, 4);
  preguntas[9] = new Pregunta("En que anyo fallecio Fidel Castro?", "2012", "2014", "2016", "2018", false, 3);
  preguntas[10] = new Pregunta("En que pais nace el rio Danubio?", "Alemania", "Suiza", "Hungria", "Holanda", false, 1);
  preguntas[11] = new Pregunta("Cuanto dientes tiene un ninyo cuando le salen los dientes de leche?", "32", "20", "22", "36", false, 2);
  preguntas[12] = new Pregunta("En que anyo se produjo el ataque a Pearl Harbor?", "1939", "1940", "1941", "1942", false, 3);
  preguntas[13] = new Pregunta("En que anyo se publico el famoso 'Diario de Ana Frank'?", "1947", "1949", "1950", "1952", false, 1);
  preguntas[14] = new Pregunta("Con cuantos paises limita Mexico?", "2", "3", "4", "5", false, 2);
  preguntas[15] = new Pregunta("Cual es el pais mas grande del continente americano?", "EEUU", "Brasil", "Canada", "Argentina", false, 3);
  preguntas[16] = new Pregunta("Cuantos paises atraviesa la cordillera de los Andes?", "Tres", "Cinco", "Seis", "Siete", false, 4);
  preguntas[17] = new Pregunta("Cuantos metros de altura mide la Muralla China?", "3-5M", "8-9M", "6-7M", "10-12M", false, 3);
  preguntas[18] = new Pregunta("Cuantos estados tiene Estados Unidos?", "50", "51", "52", "53", false, 1);
  preguntas[19] = new Pregunta("Cuantas Islas Baleares hay?", "Siete", "Tres", "Cuatro", "Cinco", false, 4);
  preguntas[20] = new Pregunta("Que continente tiene mas paises?", "America", "Asia", "Europa", "Africa", false, 4);
  preguntas[21] = new Pregunta("Cual es el pico mas alto de la peninsula iberica?", "Veleta", "Aneto", "Teide", "Mulhacen", false, 4);
  preguntas[22] = new Pregunta("Cual es la ciudad mas grande de China?", "Beijing", "Shanghai", "Hong Kong", "Hangzhou", false, 2);
  preguntas[23] = new Pregunta("Bagdad es la capital de?", "Iran", "Siria", "Irak", "Yemen", false, 3);
  preguntas[24] = new Pregunta("Cuantos premios Nobel gano la famosa cientifica Marie Curie?", "Cero", "Uno", "Dos", "Tres", false, 3);
  preguntas[25] = new Pregunta("En que anyo termino la segunda guerra mundial?", "1918", "1939", "1940", "1945", false, 4);
  preguntas[26] = new Pregunta("Cual es el simbolo quimico de la plata?", "P", "Pl", "Ag", "Pn", false, 3);
  preguntas[27] = new Pregunta("Como se llama la reina de Reino Unido?", "Isabel II", "Luisa I", "Sofia II", "Maria I", false, 1);
  preguntas[28] = new Pregunta("En que pais se entrega el premio Nobel?", "EEUU", "Suecia", "Japon", "Italia", false, 2);
  preguntas[29] = new Pregunta("Cual es la capital de Turquia?", "Adana", "Estambul", "Ankara", "Esmirna", false, 3);
  preguntas[30] = new Pregunta("Cuantos musculos tiene el ser humano?", "100", "200", "500", "700", false, 4);
  preguntas[31] = new Pregunta("Cual es la capital de Australia?", "Sidney", "Melbourne", "Adelaida", "Canberra", false, 4);
  preguntas[32] = new Pregunta("Cuantos huesos tiene un ser humano?", "136", "282", "178", "206", false, 4);
  preguntas[33] = new Pregunta("Como se llama la agencia de inteligencia britanica?", "CIA", "KGB", "MI5", "MOSAD", false, 3);
  preguntas[34] = new Pregunta("A que pais pertenece la capital de Ottawa?", "Japon", "Canada", "EEUU", "Malasia", false, 2);
  preguntas[35] = new Pregunta("Donde se celebraron los juegos olimpicos de 2004?", "Madrid", "Buenos Aires", "Pekin", "Atenas", false, 4);
  preguntas[36] = new Pregunta("Cual es el rio mas largo de Europa?", "Ebro", "Danubio", "Volga", "Dniester", false, 3);
  preguntas[37] = new Pregunta("En que anyo entro el euro como moneda unica europea?", "2002", "2003", "2004", "2001", false, 1);
  preguntas[38] = new Pregunta("Cuantos anyos duro la guerra civil espanyola?", "6", "3", "7", "10", false, 2);
  preguntas[39] = new Pregunta("Ningun pais de Africa comienza con la letra:", "F", "L", "R", "T", false, 1);
  preguntas[40] = new Pregunta("SIDA significa Sindrome de InmunoDeficiencia humana:", "Asimilada", "Absorbida", "Alterna", "Adquirida", false, 4);
  /*preguntas[41] = new Pregunta("Que membranas cubren el cerebro?", "Timpanos", "Diafragma", "Meninges", "Trochleum", false, 3);
    preguntas[42] = new Pregunta("Cual es el objetivo mas elevado del camino budista?", "Kinsasa", "Nirvana", "Utopia", "Lhasa", false, 2);
    preguntas[43] = new Pregunta("Cual de estos paises no participo en la primera guerra mundial?", "Belgica", "Francia", "Noruega", "Polonia", false, 3);
    preguntas[44] = new Pregunta("Cual de los siguientes no es un año del calendario chino?", "Panda", "Rata", "Serpiente", "Tigre", false, 1);
    preguntas[45] = new Pregunta("Cual es el elemento quimico cuyo simbolo es Pt?", "Paladio", "Plata", "Platino", "Plomo", false, 3);
    preguntas[46] = new Pregunta("En que pais nacio el Che Guevara?", "Cuba", "Argentina", "Uruguay", "Ecuador", false, 2);
    preguntas[47] = new Pregunta("En que año llego el hombre a la luna?", "1983", "1945", "1969", "1972", false, 3);
    preguntas[48] = new Pregunta("Donde se encuentra el 'gran buda de Ushiku'?", "Japon", "Nepal", "China", "India", false, 1);
    preguntas[49] = new Pregunta("En que zona de la peninsula iberica se instalaron los celtas?", "Sur", "Noroeste", "Noreste", "Norte", false, 2);
    preguntas[50] = new Pregunta("Donde se encuentra la iglesia de santa sofia?", "Turquia", "Grecia", "Italia", "Francia", false, 1);*/
}
void mostrarPregunta(int aleatorio){
  tft.fillScreen(BLACK);
  tft.drawRect(TEXT_X, TEXT_Y, TEXT_W, TEXT_H, ILI9341_WHITE);
  tft.setCursor(TEXT_X + 2, TEXT_Y + 2);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.print(preguntas[aleatorio]->getEnunciado());
  //Boton_1
  tft.fillRoundRect(10, 110, 140, 50, 8 , ILI9341_GREENYELLOW);
  tft.drawRoundRect(10, 110, 140, 50, 8, BLACK);
  tft.setCursor(15, 115);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.print(preguntas[aleatorio]->getR1());
  //Boton_2
  tft.fillRoundRect(170, 110, 140, 50, 8, YELLOW);
  tft.drawRoundRect(170, 110, 140, 50, 8, BLACK);
  tft.setCursor(175, 115);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.print(preguntas[aleatorio]->getR2());
  //Boton_3
  tft.fillRoundRect(10, 180, 140, 50, 8, ILI9341_RED);
  tft.drawRoundRect(10, 180, 140, 50, 8, BLACK);
  tft.setCursor(15, 185);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.print(preguntas[aleatorio]->getR3());
  //Boton_4
  tft.fillRoundRect(170, 180, 140, 50, 8, ILI9341_BLUE);
  tft.drawRoundRect(170, 180, 140, 50, 8, BLACK);
  tft.setCursor(175, 185);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.print(preguntas[aleatorio]->getR4());
}

bool obtenerRespuesta() {
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
  digitalWrite(13, LOW);
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);
  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
    p.x = map(p.x, TS_MAXX, TS_MINX, 320, 0);
    p.y = map(p.y, TS_MAXY, TS_MINY, 260, 0);
    Serial.print("X = "); Serial.println(p.x);
    Serial.print("\tY = "); Serial.println(p.y);
    if (p.x > 20 && p.x < 160 && p.y > 140 && p.y < 190) { //Primer boton//
      respuesta = 1;
      Serial.println("Pulsado boton 1");
      pulsado = true;
    }
    if (p.x > 180 && p.x < 310 && p.y > 140 && p.y < 190) {//Segundo boton
      respuesta = 2;
      Serial.println("Pulsado boton 2");
      pulsado = true;
    }
    if (p.x > 20 && p.x < 160 && p.y > 210 && p.y < 250) {//Tercer boton
      respuesta = 3;
      Serial.println("Pulsado boton 3");
      pulsado = true;
    }
    if (p.x > 180 && p.x < 310 && p.y > 210 && p.y < 250) {//Cuarto boton mquina
      respuesta = 4;
      Serial.println("Pulsado boton 4");
      pulsado = true;
    }
    Serial.print("Respuesta:");Serial.println(respuesta);
  }
  return pulsado;
}

void sonidoResp(bool s) {
  const int acierto[] = {700,460, 680, 460};
  const int error[] {200, 200};
  if(s){
    for (int iTono = 0; iTono < 4; iTono++) {
      tone(BUZZER, acierto[iTono]);
      delay(100);
    }
  } else {
    for (int iTono = 0; iTono < 2; iTono++) {
      tone(BUZZER,error[iTono], 200);
      delay(250);
    }
  }
  noTone(BUZZER);
}

void actualizar(int aleatorio) {
  if (preguntas[aleatorio]->esCorrecta(respuesta)){
    puntos++;
    sonidoResp(true);
    Serial.println("Acierto");
  }
  else {
    sonidoResp(false);
    Serial.println("Fallo");
    falla = true;
    buttonEnabled = true;
    start = false;
  }
}

void juego() {
  do {
    int randomNumber = random(0, 41);
    while(preguntas[randomNumber]->getUtilizado()){
      randomNumber = random(0, 41);
    }
    Serial.print("Pregunta: ");Serial.println(randomNumber);
    mostrarPregunta(randomNumber);
    preguntas[randomNumber]->setUtilizado(true);
    pulsado = false;
    while (!pulsado){
      if (obtenerRespuesta()){
        actualizar(randomNumber);
        contador();
      }
    }
  } while (pulsado && !falla);
}

void drawFin() {
 //Score
  tft.fillScreen(BLACK);
  tft.drawRect(0, 0, 319, 240, WHITE);
  tft.setCursor(100, 30);
  tft.setTextColor(WHITE);
  tft.setTextSize(4);
  tft.print("SCORE");

  tft.setCursor(80, 100);
  tft.setTextColor(RED);
  tft.setTextSize(4);
  tft.print(puntos);
  delay(2000);
  tft.fillScreen(BLACK);
  drawInicio();
}

boolean cae() {
  long d = sr04.Distance();
  Serial.print("Ultrasonido:");Serial.println(d);
  return (d < 20);
}

void encenderMotor(int motor){
  analogWrite(motor,255);
}
void apagarMotor(int motor){
  analogWrite(motor,0);
}

void resetPreguntas(){
  for (int i = 0;i<41;i++){
    preguntas[i]->setUtilizado(false);
  }
}

void caePremio() {
  if (puntos >= 5 && puntos <= 10) {
    while (!cae()){
      encenderMotor(R1);
    }
    apagarMotor(R1);
  }
  if (puntos > 10 && puntos <= 15){
    while (!cae()){
      encenderMotor(R2);
    }
    apagarMotor(R2);
  }
  if (puntos > 15 && puntos <= 20) {
    
    while (!cae()){
      encenderMotor(R3);
    }
    apagarMotor(R3);
  }
  if (puntos > 20 && puntos <= 41){
    while (!cae()) {
     encenderMotor(R4);
    } 
    apagarMotor(R4);
  }
  falla = false;
  puntos=0;
  lcd.clear();
  resetPreguntas();

pregunta.h: archivo que contiene la clase Pregunta para realizar el sistema de preguntas.

#ifndef pregunta_h
#define pregunta_h

class Pregunta {
  public :
    String enunciado;
    String r1;
    String r2;
    String r3;
    String r4;
    bool utilizado = false;
    int respuesta;

    Pregunta(String e, String r1, String r2, String r3, String r4, bool use, int r);
    int getRespuesta();
    String getR1();
    String getR2();
    String getR3();
    String getR4();
    void setUtilizado(bool u);
    String getEnunciado();
    bool esCorrecta(int r);
    bool getUtilizado();
};
Pregunta::Pregunta(String e, String r1, String r2, String r3, String r4, bool use, int r) {
  this->enunciado = e;
  this->r1 = r1;
  this->r2 = r2;
  this->r3 = r3;
  this->r4 = r4;
  utilizado = use;
  respuesta = r;
};
int Pregunta::getRespuesta() {
  return this->respuesta;
};
String Pregunta::getR1() {
  return this->r1;
};
String Pregunta::getR2() {
  return this->r2;
};
String Pregunta::getR3() {
  return this->r3;
};
String Pregunta::getR4() {
  return this->r4;
};
void  Pregunta::setUtilizado(bool u) {
  utilizado = u;
};
String Pregunta:: getEnunciado() {
  return this->enunciado;
};
bool Pregunta:: esCorrecta(int r) {
  return this->respuesta == r;
};
bool Pregunta:: getUtilizado() {
  return this->utilizado;
};

#endif /* preguntas_h */

Resultado final

Funcionamiento

Para poder empezar a jugar tienes que pulsar el botón de START, entonces te aparecerá la primera pregunta y te seguirán apareciendo hasta que falles. En todo momento podrás ver los puntos que tienes en la pantalla LCD y sabrás si has acertado por el tono que suena cuando pulsas una de las opciones. El rango de puntos para cada una de las recompensas es el siguiente: 0-4->NINGUNO, 5-9->PRIMER PREMIO, 10-14-> SEGUNDO PREMIO, 15-19->TERCER PREMIO, 20-40: CUARTO PREMIO.

Problemas encontrados

Nos hemos encontrado cuatro problemas fundamentalmente, uno de ellos fue la dificultad de y programar la pantalla táctil tal y como nosotros queríamos, otro fue elegir unos motores que necesitaban al menos 9V para poder funcionar por lo que tuvimos que añadir una pila  ,también tuvimos que cablear todo el sistema y debido a la gran cantidad de cables y el espacio tan limitado que teníamos en la caja se  torno en una tarea sumamente costosa y pesada  , por ultimo cabe destacar que  elegimos unos motores muy poco potentes y tuvimos muchos problemas a la hora de hacer girar la espirar metálica con respecto al peso de esta y al rozamiento con las distintas partes de la máquina.

Mejoras

Inicialmente teníamos pensando crear un contador a la vez que las preguntas que añadiría presión a la hora de responder a las preguntas.

Otra mejora que haríamos seria dejar mas hueco para los cables para que no estén tan comprimidos, además eso ayudaría a poder entender mejor las conexiones a la hora de explicárselo a un tercero.

Por último, nos hubiese gustado poner unos motores más potentes ya que los que tenemos, aunque funcionan, carecen de fuerza a la hora de girar el muelle con un producto puesto encima.

También te podría gustar...

Deja un comentario

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