Como fazer uma balança com ESP32

Vou começar com uma dica. Se você ler um artigo em que eu tenha escrito “no próximo artigo relacionado…” e achar que está faltando algo, parabéns, você acertou. Por isso tem próximo artigo relacionado. E nessa continuação, veremos como fazer a balança com ESP32.

Esse é o artigo onde estou entregando o produto completo e funcional de uma balança com 4 células de carga, em continuidade ao artigo anterior com Arduino.

A diferença é mínima, uma vez que muda apenas o pinout com a MCU e o código é o mesmo. Mas dessa vez estou fazendo a balança com ESP32 para mostrar o programa que fiz (e estou disponibilizando) para fazer a interface com a balança. Vamos aos princípios.

Wiring e pinout das células de carga

Essa balança está bastante feia, foi feita no improviso, mas está incrivelmente boa. Tem um pequeno ruído, o que acaba variando uns dois ou três gramas, mas está excelente.

O primeiro passo é colocar as células de carga conectadas ao HX711. Para isso, siga esse outro tutorial.

Fez as conexões? Ok, sigamos.

Como usar MQTT no ESP32

A comunicação se dará por MQTT. Logo, será necessário adicionar ao programa em ESP32 a biblioteca PubSubClient. Basta instalar e usar o código disposto neste artigo. Se quiser um “overview”, dê uma olhada nesse artigo.

Como usar MQTT no Qt

O programa em Qt roda tanto no desktop (em Windows, Linux e Mac) como no Raspberry. Para dar suporte ao MQTT, siga esse tutorial. Pode ler apenas o tópico Como instalar o QT MQTT.

Como configurar um broker MQTT

Podemos utilizar um broker público, como o Mosquitto. Particularmente, gosto de configurar meu próprio broker, não leva mais do que 5 minutos. Talvez 3.

Se desejar configurar seu próprio broker, siga esse outro tutorial.

Wiring do ESP32 com o HX711

Precisamos simplesmente definir os pinos DT e o SCK. O HX711 trabalha de (salvo erro) 2.7 à 5.5V, de modo que não haverá problema em colocá-lo para funcionar à 3v3. Desse modo, defini a seguinte configuração:

HX711ESP32
VCC3v3
GNDGND
DTIO18
SCKIO17

Código da balança com ESP32

O código a seguir está aferido para mim, veja se precisa de algum ajuste.

Basicamente, temos 4 células de carga de 50kg. Pensando de forma empírica, se quisermos pesar 25kg em uma balança igual a balança símbolo da justiça, o que precisamos fazer? A resposta é:

“Colocar 25kg de cada lado”.

Isso significa que para ter equilíbrio na balança, devemos colocar 25kg de cada lado para aferir 25kg, tendo um total absoluto de 50kg. Com as células de carga acontece o mesmo; tendo 4 células de 50kg para pesar 1kg, deveremos multiplicar o resultado da leitura por 4, pois cada célula terá uma massa distribuída de 250g.

Código para debug da balança com ESP32

Há um pouco de ruído na leitura, talvez gerado pela placa ou pela alimentação da célula de carga. Indiferentemente, o valor é algo em torno de 4 gramas absoluto; isto é, não tem curva de variação. Desse modo, basta subtrair o ruído, caso desejado. Foi o que fiz.

#include <Arduino.h>
#include "HX711.h"
#define DT_PIN 18
#define SCK_PIN 17

float offset = 0; //variável para guardar o valor bruto de offset

HX711 scale;
 
void setup() {
  scale.begin(DT_PIN,SCK_PIN);
  Serial.begin(9600);
  offset = scale.read_average(3); //tira uma média de 3 amostras para o offset
}
 
void loop() {
  float kg = 0;
  //subtrai o offset
  kg       = scale.read_average(1) - offset; 

  // se conectar ao contrário, o valor será negativo. Pode ser invertido por software, desse modo.
  kg      /= 100 * -1; 

  //o peso está divido por 4 células, significando que podemos pesar até 200kg com 4 células de 50kg.
  kg      *= 4; 
  //está dando uma diferença pequena, mas uma função de tara resolve.
  kg       = kg-16; //16 = 4*4

  Serial.print(kg);
  Serial.println("gr");
  delay(1000);
}

Esse é o código básico para a balança, caso não queira usar MQTT, Raspberry, Qt etc. A partir disso, você pode dispor a informação em um display qualquer ou simplesmente exibir na serial. Esse código também é um ótimo princípio para debug.

Código da balança com ESP32 e MQTT

Tendo garantido o funcionamento e aferido sua balança, agora é hora de implementar um código completo. Todas as credenciais dispostas no código são do meu ambiente de laboratório, se quiser seguir à risca, sinta-se livre.

As bibliotecas HX711PubSubClient devem ser instaladas pelo repositório do Arduino. O código disposto abaixo foi feito no Visual Studio Code usando PlatformIO.

O tópico criado para utilizar no broker é o scale.

#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include "HX711.h"

#define DT_PIN 18
#define SCK_PIN 17

#define ESP32_MODE_AP   1
#define ESP32_MODE_STA  2

#define ESP32_STATE_OFF 0
#define ESP32_STATE_STA 1
#define ESP32_STATE_AP  2

#define MAX_LEN         50

TaskHandle_t mqttConn; 
TaskHandle_t handleStartMQTT; 

byte esp32_wifi_mode      = ESP32_STATE_STA;
const char* ssid          = "SuhankoFamily";
const char* password      = "fsjmr112";
long lastReconnectAttempt = 0;
bool mqttAlreadyRunning   = false;
float offset              = 0; //variável para guardar o valor bruto de offset
char buf[7]               = {0};
bool sendMsg              = false;

HX711 scale;

struct configStruct{
  char ssid[MAX_LEN]         = {0};
  char senha[MAX_LEN]        = {0};
  char senha1[MAX_LEN]       = {0};
  char mqtt_host[MAX_LEN]    = {0};
  char mqtt_port[MAX_LEN]    = {0};
  char clientId[MAX_LEN]     = {0};
  char mqtt_pass[MAX_LEN]    = {0};
  char publish_to[MAX_LEN]   = {0};
  char subscribe_to[MAX_LEN] = {0};

  IPAddress ip;
  IPAddress gateway;
} wifiConfig;

WiFiClient wifiClient;
PubSubClient client(wifiClient);

void preLoad();
void enableInterrupt();
void IRAM_ATTR my_isr_handler(void* arg);
void startWifiMode(byte choice);
void vMQTT(void *pvParameters);
bool reconnect();
void callback(char* topic, byte* payload, unsigned int length);

void startWifiMode(byte choice){
  Serial.println(":: WiFi configuration ::");
  Serial.println("Stopping, if any...");

  if (choice == ESP32_MODE_STA){
      Serial.println("Starting station mode...");
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      esp32_wifi_mode = ESP32_STATE_STA;
      Serial.println(WiFi.localIP());
      Serial.println(":: WiFi Configuration - done ::\n\n");
      return;
  }
}

bool reconnect() {
  if (client.connect(wifiConfig.clientId,wifiConfig.clientId,wifiConfig.mqtt_pass)) {
    client.subscribe("/scale/#");
  }
  return client.connected();
}

//TODO: tratar o payload?
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.println( (char *) payload);
}

void vMQTT(void *pvParameters){
  vTaskDelay(pdMS_TO_TICKS(3000));
  if (WiFi.status() != WL_CONNECTED){
    Serial.print("WiFi not connected. Waiting for...");
    while(WiFi.status() != WL_CONNECTED){
      Serial.print(".");
      vTaskDelay(pdMS_TO_TICKS(500));
    }
  }
 
  Serial.println("fazendo a conexao com o broker...");
  IPAddress srv(192,168,1,200);
  client.setServer("192.168.1.200", 1883);
  client.subscribe("/scale/#");
  client.setCallback(callback);
  client.connect("balanca","dobitaobyte","fsjmr112");
 
  mqttAlreadyRunning = true;
 
  while (true){
    client.loop();
    vTaskDelay(pdMS_TO_TICKS(10));
    if (sendMsg){
      Serial.println("mandou enviar");
      client.publish("/scale",buf);
      sendMsg = false;
    }
    
  }
}

void preLoad(){
  strcpy(wifiConfig.ssid,"SuhankoFamily");
  strcpy(wifiConfig.senha,"fsjmr112");
  strcpy(wifiConfig.senha1,"fsjmr112");
  strcpy(wifiConfig.mqtt_host,"192.168.1.200");
  strcpy(wifiConfig.mqtt_port,"1883");
  strcpy(wifiConfig.clientId,"dobitaobyte");
  strcpy(wifiConfig.mqtt_pass,"fsjmr112");
  strcpy(wifiConfig.subscribe_to,"/scale/#");
  strcpy(wifiConfig.publish_to,"/scale/");
 
  wifiConfig.ip      = IPAddress(192,168,1,123);
  wifiConfig.gateway = IPAddress(192,168,1,1);
}

void setup() {
  scale.begin(DT_PIN,SCK_PIN);
  Serial.begin(9600);
  offset = scale.read_average(10); //tira uma média de 3 amostras para o offset

  preLoad();
  startWifiMode(ESP32_MODE_STA);
  
    
  xTaskCreatePinnedToCore(vMQTT,"vMQTT", 10000, NULL, 0, &handleStartMQTT,0);

}
 
void loop() {
  float kg = 0;
  //subtrai o offset
  kg       = scale.read_average(1) - offset; 

  // se conectar ao contrário, o valor será negativo. Pode ser invertido por software, desse modo.
  kg      /= 100 * -1; 

  //o peso está divido por 4 células, significando que podemos pesar até 200kg com 4 células de 50kg.
  kg      *= 4; 
  //está dando uma diferença pequena, mas uma função de tara resolve.
  kg       += 10; //16 = 4*4

  Serial.print(kg);
  Serial.println("gr");

  
  memset(buf,0,7);
  dtostrf(kg,sizeof(kg),2,buf);
  if (sendMsg == false){
    sendMsg = true;
  }
   
  vTaskDelay(pdMS_TO_TICKS(1000));
}

Agora vamos ver a montagem da balança.

Montagem das células de carga

O “caroço” das células de carga devem ficando para baixo geram flexão negativa, com o wiring descrito no início do artigo. Por essa razão, inverti o sinal da leitura multiplicando por -1.

Peguei um pedaço de madeira que eu tinha sobrando, então fiz quatro furos com a serra copo, deixando as células na borda da madeira. Um dos cantos rompeu, mas não faz a menor diferença, já que o esforço se concentrará no meio da célula. Outra coisa é que eu não tinha madeira de apoio, coisa que é fundamental para não danificar a madeira na saída da serra copo ou mesmo de uma broca, mas não deixei de fazer o projeto por esse detalhe. O importante é funcionar, a princípio.

balança com ESP32

Programa em QT, QML e Quick para a balança

Usei como base o mesmo programa do comparativo de temperatura entre os Raspberry, desse outro artigo. Tive que mudar pouca coisa no código, mais precisamente o grau de movimentação de cada ponto e a resolução da medição. Apesar de ir até 200kg, um dos problemas é conseguir exibir isso no desenho. Para definir o número de pontos, escolhi dessa vez 300 graus distribuídos no perímetro, divididos a cada 3 graus, com cada intervalo equivalente à 20g. Isso significa que o ponteiro só mudará de posição a cada 20g, mas o mostrador analógico mostrará todos os valores. Com isso, o peso máximo medido na balança analógica será de 2kg.

Invés de citar todos os conceitos novamente, vou deixar apenas o link do programa para download (você deverá compilá-lo no QtCreator).

Onde comprar as células de carga 50kg?

A Curto Circuito está com um preço verdadeiramente especial, como citei no artigo anterior. Realmente especial, dê uma conferida.

Onde comprar o HX711?

Para o amplificador de sinal, a mesma coisa.

Onde comprar o Raspberry Pi?

Aqui temos diversas opções. A Raspberry Pi 3B na Curto Circuito, a Raspberry Pi 3B+ na Saravati e a Raspberry Pi 4 na MASUGUX.

Onde comprar ESP32?

A placa de desenvolvimento (que poderá ser vista no vídeo) é da Curto Circuito também, gosto demais de usar ela porque só troco o processador conforme o projeto. Dê uma olhada nessa belezinha.

Vídeo

O vídeo estará disponível em nosso canal DobitaobyteBrasil no Youtube tão logo seja editado. Se não é inscrito ainda, inscreva-se e clique no sininho para receber notificações.

Até a próxima!

Djames Suhanko

Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.