Balanza escolar para medir el peso en todos los planetas del Sistema Solar.


Materiales

  • 2 Celdas de carga ó 4 (versión de 4 celdas)
  • 1 microcontrolador
  • 1 HX-711
  • 2 display de 7 segmentos TM1637
  • 2 pulsadores con leds
  • Tiras de leds WS2812b
  • Maderas y tornillos (plataforma al menos)
  • Leds, resistencias
  • 1 Chip de registro de desplazamiento 74hc595n o similar (TPIC6b595).

Celdas de carga y conexiones al HX-711

Cada celda soporta 50 kg por lo que usaremos solo dos para pesar cargas que no exceden de los 100 kg.

Los cambios que estos sensores experimentan con la presión son tan pequeños que necesitamos un amplificador que nos entregue valores que puedan ser manejados por el microcontrolador. Para ello emplearemos el HX-711 muy adecuado para esta tarea. Dispone de 6 pines de entrada marcados como E+, E-, A-, A+, B- y B+. 

Para nuestro propósito usaremos solo los pines E+, E-, A-, A+ de la manera que detallamos a continuación, pues los restantes se usan para seleccionar otro nivel de ganancia.

Cables de las celdas de carga (rojo, blanco y negro).

Como verás, las celdas de carga poseen 3 cables (rojo, negro y blanco), que corresponden a los medios puentes Wheatstone. 

Con dos celdas de carga conseguimos formar un puente Wheatstone completo, que nos permite obtener los datos exactos de variación despreciando las condiciones ambientales con una enorme precisión.

Puente Wheatstone

Estos datos son amplificados por el HX-711 que inyecta voltaje en las celdas y es capaz de comparar la pequeña variación que producen las resistencias variables de carga en la salida y envía los valores al microcontrolador. 

Cada celda está compuesta de 2 resistencias internas de 1k ohm cada una. El cable rojo suele ser el que está conectado al división de tensión mientras que el negro y el blanco se conectan a los extremos (como podemos apreciar en la imagen siguiente). 

Conexiones de 2 celdas de cargas al HX-711

Estas resistencias y por tanto el orden de los cables puedes determinarlos con cualquier polímetro midiendo las resistencias. De tal forma que si mides 2Kohms es porque has encontrado los cables de los extremos, mientras que si obtienes 1K en la medición es que has encontrado el que se conecta al divisor de tensión.

Cables de colores de las celdas de cargas y sus respectivas resistencias de 1K (una de ellas variable por presión).

Como verás, al tratarse solo de dos resistencias, tienes delante medio puente Wheatstone, por lo que necesitarás otras dos resistencias equivalentes (puedes usar dos de 1K fijas si solo dispones de una celda de carga) que corresponden a las dos resistencias de la otra celda, para completar el puente.

Amplificador HX-711

Por su lado, el amplificador HX-711 se conecta al microcontrolador con dos pines digitales y alimentación de 5 voltios. En mi caso usaré el pin A0 para DT, y el A1 para el reloj a pesar de ser analógicos desempeñarán la función de entradas digitales.

Si lo que quieres es usar 4 celdas de carga que te permita pesar menos 200kg, el esquema cambia ligeramente. 

Conexiones entre el HX711 y 4 celdas de carga.

Hora de probar que todo funciona. Subimos un código básico de la librería <HX711.h> incluida en el IDE de arduino y probamos.

#include "HX711.h"

const int LOADCELL_DOUT_PIN = A0;
const int LOADCELL_SCK_PIN = A1;
HX711 scale;

void setup() {
  Serial.begin(57600);
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  scale.tare(20);
}

void loop() {
  if (scale.is_ready()) {
    long reading = scale.read();
    Serial.print("HX711 reading: ");
    Serial.println(reading);
  } else {
    Serial.println("HX711 not found.");
  }
  delay(1000);
}

Abrimos el serial ploter para observar gráficamente las variaciones y ponemos la velocidad en 57600 bps. Veremos como cambian los valores bruscamente cuando presionamos alguna de las dos celdas de carga en los picos de la gráfica.

Tara

Como todo peso, necesitamos establecer el punto de tara que en pocas palabras equivaldría a calibrarlo. Para ello, en la programación, usaremos los dos pulsadores presionados a la vez en el arranque para tal propósito y así nos ahorramos un pulsador más.

begin(byte PinData, byte PinClock)

Inicializa el HX711, se puede trabajar con cualquiera de los pines, incluidos analógicos.

tare(byte n);

Establece el peso actual como el peso de tara, n indica el número de lecturas que se realizan para obtener la tara, por defecto n=10;

set_scale(float scale);

Establece el valor de la escala, que es el factor de conversión para convertir valor de lectura en un valor con unidades de peso. Por defecto es scale=1;

read()

Espera hasta que el dispositivo esté listo y devuelve la lectura del ADC del HX711

read_average(byte n)

Realiza n veces la lectura del ADC y devuelve el promedio

get_value(byte n)

Devuelve el valor actual restando el peso de tara. Equivalente a (read_average() – OFFSET) . Si se especifica un valor de n, devuelve el promedio de n lecturas.

get_units(byte n)

Devuelve el valor actual restado del peso de tara y dividido por la escala. Es equivalente a (get_value()/SCALE). Si se especifica un valor de n, devuelve el promedio de n lecturas.

Calibración y escalado.

Observamos unos valores extremadamente altos, pues son la lectura bruta del ADC. Para convertir estos valores a escala de kilogramos debemos dividir el valor obtenido entre el peso que hay en la balanza. Para ello usaremos un valor conocido por ejemplo 1kilo de garbanzos. De esta manera, tendremos que dividir el valor obtenido entre 1kg. Por consiguiente el valor que debemos poner en la escala es el valor obtenido con un kilo de garbanzos en la balanza.

Lo expresaremos como «balanza.set_scale(40699);» en mi caso.

Por último tener en cuenta la tara, que expresaremos «balanza.tare(20);» para que el peso de la propia tabla se considere cero, hará 20 medidas y calculará la media. Por supuesto hay que realizar esta tara sin elementos sobre el soporte de la báscula.


Soportes para las celdas

Fabricaremos unas carcasas para albergar las celdas de carga y que el trabajo quede más curioso y profesional aunque podríamos ponerlas directamente sobre la tabla del peso.

Medidas standar de las celdas de carga

Dejo a continuación los modelos en STL que imprimiré en material resistente como es el ABS y usaré 2 tornillos de 2mm para la unión. Estas carcasas se atornillarán a un taco de madera más adelante.

Actualización: Aquí dejo otra versión de sujeción para celdas de carga para otros modelos.

Tras imprimir las carcasas, cortaremos dos tacos de madera de 60x50x45mm para las patas exteriores de la tabla. Sobre ellas atornillamos las celdas de carga.


Cubre cables

Presentamos los cables de las celdas para que conecten a la caja que contiene el HX711 y los embellecedores para ocultar los cables.

Vista inferior donde se aprecian las celdas de carga y la caja contenedora del amplificador HX711.

Actualización: Versión de 4 celdas.

Tras varias pruebas me he dado cuenta que hace falta más precisión en el peso, pues con dos celdas el peso no se repartía como era necesario. Supongo que nivelar la plataforma ayudaría, pero dejo aquí una nueva versión de la estructura de los cables para el que decida que la mejor opción es la de 4 celdas de carga.

Versión de 4 celdas de carga.

Displays

Para mostrar los valores usaremos dos displays de 4 dígitos y 7 segmentos leds controlados por el chip TM1637 y la librería  (página del autor) del mismo nombre que hemos usados ya en algunos proyectos anteriores como el  Termómetro de paredTemporizador para soldador con Arduino. 

En el display1 mostraremos el peso en la tierra y en el display2 mostraremos el peso en el planeta seleccionado en ese momento.

Estos módulos se conectan a 5 voltios y necesitan de dos pines digitales para funcionar. El Display1 lo controlaremos con los pines D2 para CLK y D3 para DIO. Mientras que el Display 2 irá conectado al D4 y D5.

Displays y conexciones

Para incrustar los displays en el panel frontal, usaremos unos embellecedores con los rótulos adecuados. La tornillería es un poco más específica, pues usaré unas tuercas de 6mm para tornillos M3 que irán incrustadas en los orificios. No es necesario usar pegamento aunque hay que presionar un poco como se muestra en la imagen.

El proyecto medirá el peso en la Tierra y en los distintos planetas escalando las fuerzas G de cada mundo.

Conseguidas de wikipedia, usaremos sólo los de los planetas. El cálculo será tan fácil como multiplicar el peso obtenido en la Tierra, por el factor gravitacional de cada planeta y dividirlo por 9’8.

Astro g m/s2
Sol 27,90 273,70
Mercurio 0,37 3,70
Venus 0,88 8,85
Tierra 1,00 9,81
Luna 0,16 1,62
Marte 0,38 3,72
Júpiter 2,64 26,39
Saturno 1,15 11,67
Urano 1,05 11,43
Neptuno 1,22 11,07


Luminosos de selección de planetas

Serán los indicadores del planeta seleccionado para mostrar tu peso en el display de planeta. Van a ser 8, pero tranquilo, no necesitamos 8 salidas de arduino. Usaremos un chip de registro de desplazamiento. Podemos usar el 74hc595n de fácil implementación pero limitada potencia o el TPIC6B595 de similar funcionamiento y conexiones, pero que maneja mayor corriente. 

En mi caso usaré 4 leds por módulo selector en paralelo y con resistencias de 100 o 120 ohms, por lo que me decantaré por el TPIC6B595 que al igual que el hermano pequeño usa sólo 3 pines digitales para controlarlo.

Los pines digitales de conexión que se muestran en la imagen pueden no coincidir con los del proyecto, ten cuidado.

En este proyecto usaremos dataPin al D7;  latchPin al D8;  y clockPin al D9. Los terminales negativos de los módulos se conectan a los drains y el positivo es común y conectado a VCC. Se puede usar un pequeño condensador. 

A tener en cuenta que podríamos modificar la intensidad de los módulos jugando con el pin G conectado a una salida PWM, siendo 0 el valor más brillante y 254 el menos brillante. Pero no lo emplearemos en este proyecto y conectaremos ese pin a masa.


Leds WS2812b

Usaremos dos tiras de unos 15 leds cada una que irán en la base del peso bajo una pieza impresa en PetG traslúcido para crear un bonito efecto luminoso cada vez que se use el artefacto.

Tener en cuenta que estos leds consumen bastante a la hora de elegir la fuente de alimentación (60mA por led). Yo usaré una muy básica pero tendré la precaución en la programación de no encender todos a la vez ni en su mayor intensidad.

La alimentación debe ser directa de la fuente de 5V y añadiremos un condensador para garantizar fallos y una resistencia en el pin que va al microcontrolador para evitar dañar los leds.

Conectaremos la tira led en el pin D6, es recomendable usar una resistencia.

Para la programación usaremos la librería <Adafruit_NeoPixel.h>, incluida en el IDE de arduino.


Pulsadores

Seleccionarán el planeta de referencia para mostrar el peso en dicho lugar. Al presionarlos activaremos el siguiente de los 8 leds del panel frontal. Servirán para subir o bajar y esto afectará al display2 que mostrará una cifra distinta dependiendo del planeta seleccionado. 

Pulsadores con led

Para ahorrar material usaremos las resistencias pull-up del controlador. Usaremos pulsadores con leds para dar un aspecto más interactivo.


Soporte para fuente de alimentación y microcontrolador

Esta caja que contendrá la fuente y el microcontrolador irá sujeto en la parte trasera del marco superior, oculto tras el panel expositivo.

Debe atornillarse al listón inferior.


Esquema electrónico

Esquema electrónico

Estructura de madera.

Como es lógico, es tan solo una propuesta y permite colgar el artefacto y doblarlo para trasportarlo. Un gran inconveniente y que será punto de revisión es el uso de solo dos celtas de carga junto a las bisagras. Esto será cambiado en un futuro pues muestra grandes errores en la expresión del peso dependiendo de la localización.  Así que en un futuro añadiré las dos celdas para tener cuatro y aislar un poco la plataforma del efecto de las bisagras.

Plano y medida de la estructura de madera.

Decoración

No hay que olvidar que se trata de un proyecto para alumnos de primaria e infantil, por ello adornaremos el panel frontal con motivos adecuados.


Programación

/************************************************
   Nombre del proyecto: Peso escolar con medida en otros planetas

   Programado por Juan Carlos Pedrajas del Molino

   Https:\\www.geniero.es
   pedrajas@geniero.es
   afelio11@gmail.com

   Fecha de inicio: 28/11/21

   Fecha de finalización: 23/01/22

   ESQUEMA DE CONEXION

                                      +-----+
         +----[PWR]-------------------| USB |--+
         |                            +-----+  |
         |         GND/RST2  [ ][ ]            |
         |       MOSI2/SCK2  [ ][ ]  A5/SCL[ ] |
         |          5V/MISO2 [ ][ ]  A4/SDA[ ] |
         |                             AREF[ ] |
         |                              GND[ ] |
         | [ ]N/C                    SCK/13[ ] |  Led Botón2
         | [ ]IOREF                 MISO/12[ ] |  Botón2
         | [ ]RST                   MOSI/11[ ]~|  Botón1
         | [ ]3V3    +---+               10[ ]~|  Led boton1
         | [ ]5v    -| A |-               9[ ]~|  74HC595n clockPin
         | [ ]GND   -| R |-               8[ ] |  74HC595n latchPin
         | [ ]GND   -| D |-                    |
         | [ ]Vin   -| U |-               7[ ] |  74HC595n dataPin
         |          -| I |-               6[ ]~|  Data WS2812b
  DataHX711| [ ]A0    -| N |-               5[ ]~|  DIO Display2
  SLKHX711 | [ ]A1    -| O |-               4[ ] |  CLK Display2
         | [ ]A2     +---+           INT1/3[ ]~|  DIO Display1
         | [ ]A3                     INT0/2[ ] |  CLK Display1
         | [ ]A4/SDA  RST SCK MISO     TX>1[ ] |
         | [ ]A5/SCL  [ ] [ ] [ ]      RX<0[ ] |
         |            [ ] [ ] [ ]              |
         |  UNO_R3    GND MOSI 5V  ____________/
          \_______________________/

********************************************************************
*/

#include <Adafruit_NeoPixel.h>
#define PIN       9
#define NUMPIXELS 30
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);



#include <TM1637.h>
TM1637 pantalla1(2, 3);
TM1637 pantalla2(4, 5);
#include "HX711.h"

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = A0;
const int LOADCELL_SCK_PIN = A1;
float planeta[8] = { 3.7, 8.87, 9.8, 3.71, 24.79, 10.44, 8.87, 11.15}; //fuerza G de los planetas.
HX711 scale;

// Circuito TPIC6B595
const int dataPin  = 8;  // Pin conectado al Pin 3 del TPIC6B595 (Data)
const int latchPin = 6;  // Pin conectado al Pin 12 del TPIC6B595 (Latch)
const int clockPin = 7; // Pin conectado al Pin 13 del TPIC6B595 (Clock)
// Al drain* se conecta el negativo y a vcc se conecta el positivo de los leds.
const byte luz[8] = {   //Depende las soldaduras de los leds a los drains de salida del TPIC6B595n o 74HC595n.
  0b10000000,
  0b01000000,
  0b00100000,
  0b00010000,
  0b00001000,
  0b00000100,
  0b00000010,
  0b00000001,
};

// variables de la programación
int posicion = 3;
const int sube = 12;
const int baja = 11;
const int luzsube = 10;
const int luzbaja = 13;
boolean pulsado1 = 0;
boolean pulsado2 = 0;
boolean encendido = 1;
float peso;
float valor;
int optenido = 0;

void setup() {
  pinMode (sube, INPUT_PULLUP);
  pinMode (baja, INPUT_PULLUP);
  pinMode (luzsube, OUTPUT);
  pinMode (luzbaja, OUTPUT);
  pinMode (dataPin, OUTPUT);
  pinMode (latchPin, OUTPUT);
  pinMode (clockPin, OUTPUT);
  Serial.begin(57600);
  Serial.println ("Saludos");
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  scale.set_scale(19908); // Escala obtenida con pesos conocidos y otro programa.
  scale.tare(20);   // Desprecia la Tara en este momento (peso de la tabla).
  pantalla1.init();
  pantalla1.begin();                       //Pantalla 7 segmentos
  pantalla1.setBrightness(5);
  pantalla1.display("terra");
  pantalla2.init();
  pantalla2.begin();                       //Pantalla 7 segmentos
  pantalla2.setBrightness(15);
  pantalla2.display("plan");
  pixels.begin();
  pixels.clear();
  luces(255, 255, 255);
  inicioleds();
  inicioboton();
  pantalla2.clearScreen();
  pantalla1.clearScreen();
}

void loop() {
  pesa(1);

  while (peso <= 2 && optenido == 0) {
    pesa (1);
    pantalla2.clearScreen();
    pantalla1.clearScreen();
    luces (0, 0, 255);
    optenido = 0;
  }

  if (peso >= 3) {
    while (optenido < 5) {
      luces (255, 255, 0);
      optenido++;
      muestra();
      pesa(5);
      Serial.print ("peso:");
      Serial.println (peso);
      valor = peso; //podríamos hacer una media aquí   >> valor=valor+peso/5 __________________________
    }
    botones();
    pantalla1.display(valor);
    pantalla2.display((valor * planeta[posicion - 1]) / 9.8);
    for (int i = 0; i <= 30; i++) {
      pixels.setPixelColor(i, pixels.Color(0, 255, 0));
    }
    pixels.show();
  }

  if (peso <= 2) {
    optenido = 0;
    digitalWrite (luzsube, LOW);
    digitalWrite (luzbaja, LOW);
    posicion = 3;
    leds(posicion);
  }
}

void muestra () {
  pantalla1.display(peso);
  pantalla2.display((peso * planeta[posicion - 1]) / 9.8);
}

void botones() {
  int boton1 = digitalRead (sube);
  int boton2 = digitalRead (baja);
  if (boton1 == LOW && pulsado1 == 0) {
    posicion++;
    pulsado1 = 1;
    if (posicion > 8) {
      posicion = 8;
    }
    leds(posicion);
    delay (100);
    while (boton1 == LOW) {
      boton1 = digitalRead (sube);
      encendido = 0;
      digitalWrite (luzsube, encendido);
      digitalWrite (luzbaja, encendido);
    }
  }
  if (boton1 == HIGH) {
    pulsado1 = 0;
    encendido = 1;
    digitalWrite (luzsube, encendido);
    digitalWrite (luzbaja, encendido);
  }
  if (boton2 == LOW && pulsado2 == 0) {
    posicion--;
    pulsado2 = 1;
    if (posicion < 1) {
      posicion = 1;
    }
    leds(posicion);
    delay (100);
    while (boton2 == LOW) {
      boton2 = digitalRead (baja);
      encendido = 0;
      digitalWrite (luzsube, encendido);
      digitalWrite (luzbaja, encendido);
    }
  }
  if (boton2 == HIGH) {
    pulsado2 = 0;
    encendido = 1;
    digitalWrite (luzsube, encendido);
    digitalWrite (luzbaja, encendido);
  }
}

void pesa(int x) {
  if (scale.is_ready()) {
    // peso = scale.get_value(3)/ 19908;
    peso = scale.get_units(x);

  } else {
    Serial.println("HX711 not found.");
  }
  delay(100);
}

void luces(int r, int g, int b) {
  for (int i = 0; i <= 14; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
    pixels.setPixelColor(29 - i, pixels.Color(r, g, b));
    pixels.setPixelColor(i + 1, pixels.Color(r, g, b));
    pixels.setPixelColor(28 - i, pixels.Color(r, g, b));
    delay (15);
    pixels.show();
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
    pixels.setPixelColor(29 - i, pixels.Color(0, 0, 0));
  }

  for (int i = 14; i >= 0; i--) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
    pixels.setPixelColor(29 - i, pixels.Color(r, g, b));
    pixels.setPixelColor(i - 1, pixels.Color(r, g, b));
    pixels.setPixelColor(30 - i, pixels.Color(r, g, b));
    delay (15);
    pixels.show();
    pixels.setPixelColor(i + 1, pixels.Color(0, 0, 0));
    pixels.setPixelColor(28 - i, pixels.Color(0, 0, 0));
  }
  // pixels.setPixelColor(0, pixels.Color(0, 0, 0));
  // pixels.setPixelColor(14, pixels.Color(0, 0, 0));
  pixels.show();
}

void leds (int i) {
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST , luz[i - 1]);
  digitalWrite(latchPin, HIGH);
}

void inicioleds() {
  for (int i = 1; i < 8; i++) {
    leds(i);
    delay (50);
  }
  for (int i = 8; i > 0; i--) {
    leds(i);
    delay (50);
  }
  leds(posicion);
}

void inicioboton() {
  for (int i = 0; i < 3; i++) {
    digitalWrite (luzsube, HIGH);
    digitalWrite (luzbaja, HIGH);
    delay (50);
    digitalWrite (luzsube, LOW);
    digitalWrite (luzbaja, LOW);
    delay (50);
  }
}

https://open.spotify.com/playlist/3Gg2ThZmJgocUQrJi8wqnM?si=9c02370e68994c5c
Canciones que te ayudarán mientras trabajas