Archivi tag: Arduino

SmartCityZen Recycle con HX-711

SCZ Recycle è un sistema per tenere sotto controllo la propria produzione di rifiuti. Lo scopo del sistema è di aumentare la consapevolezza di quanto il nostro comportamento quotidiano abbia impatto sul pianeta e sull’ambiente.

L’ho installato in casa ed in appena 2 giorni ci siamo resi conto che abbiamo prodotto oltre 7,46 Kg di rifiuti indifferenziati!

Convidendo in famiglia questo dato abbiamo rapidamente calcolato che il nostro impatto sulla città in 1 anno è di quasi 1 tonnellata di rifiuti che qualcuno dovrà gestire e smaltire!!!

Questo ci consente forse di vedere la famigerata TASSA SUI RIFIUTI come un corretto contributo che la mia famiglia deve concedere al territorio che ci ospita.

Cosa serve?

PER IL TRASMETTITORE (Arduino)


n.1 HX711
è una breakout board che si interfaccia con le celle di carico di una bilancia, legge il dato e lo trasmette ad Arduino.

HX711
E’ un componente molto economico (da 0,5€ a 2,5 €) eccovi alcuni links:
Ebay 1
Ebay2 dalla Cina
Aliexpress

n.1 Ricevitore RF e n.1 Trasmettitore RF a 433 Mhz
Costo pochi Euro
TX_RX_RF_arduino
Aliexpress

n.1 Arduino o compatibili (io ho usato un Luigino1000Pads che vedete nell’immagine)
luigino
Aliexpress Arduino UNO

n.1 Bilancia da cucina di quelle con un peso Max. di 5/7 Kg.
(Normalmente in un cestino dei rifiuti da “sotto il lavello” ci stanno da 1,5 a 3 Kg di rifiuti)
scale_hacking
Aliexpress

Un po’ di cavi ed eventualmente una breadboard o una basetta millefori.

PER IL RICEVITORE

n.1 Arduino o compatibili (io ho usato un Luigino1000Pads che vedete nell’immagine)
luigino
Aliexpress Arduino UNO
Aliexpress Arduino Pro Micro

n.1 LCD Display 1602
character_2x16_modules_lcd_display_hd44780_controller_black_on_yg
Aliexpress

STEP 1 – Sistema Trasmettitore

Occorre smontare la bilancia (è tenuta insieme da qualche vite), all’interno troverete una cosa simile a questa:
celladicarico
è la cella di carico.
Funziona così: ad essa sono collegati 4 fili che sono i 4 punti di un ponte di Wheatstone non sto ad approfondire tecnicamente (se vi interessa seguite il link) in pratica applicando una tensione a 2 di questi fili si può leggere un cambio di tensione sugli altri 2 in funzione della pressione a cui è sottoposta la cella di carico.
in pratica maggiore è il peso maggiore è la variazione di tensione.

Questi 4 fili  sono collegati ad una basetta elettronica all’interno della bilancia e si collegano a 4 punti denominati come segue:

E+: Tensione di eccitazione +
E-:  Tensione di eccitazione –
S+: Segnale +
S-: Segnale –

E’ sufficiente collegare questi quattro fili al nostro HX711 in corrispondenza dei rispettivi pin

e cioè: E+ con E+, E- con E-, S+ con A+, S- con A-.

A questo punto dobbiamo collegare l’HX711 e il Trasmettitore RF da 433Mhz con Arduino, questo lo schema dei collegamenti:

Per prima cosa occorre installare in Arduino una libreria e precisamente questa:

HX711 Library

STEP 2 – Calibrazione Bilancia

e calibrare la bilancia,

ci viene aiuto un piccolo codice che ho modificato dagli esempi della libreria, esiste uno sketch per la calibrazione  ma a me è risultato più semplice procedere a tentativi con questo sketch, quindi installate la libreria e caricate lo sketch:

/*
 Questo sketch consente la calibrazione di una bilancia con HX711
 
 This example code uses bogde's excellent library: https://github.com/bogde/HX711
 bogde's library is released under a GNU GENERAL PUBLIC LICENSE
 
 The HX711 does one thing well: read load cells. The breakout board is compatible with any wheat-stone bridge
 based load cell which should allow a user to measure everything from a few grams to tens of tons.

 Arduino pin A0 -> HX711 SCLK
 Arduino pin A1 -> HX711 DAT o DOUT
 Arduino 5V -> HX711 VCC
 Arduino GND -> HX711 GND
 
 la scheda può essere alimentata da 2.7V a 5.0V
 
*/

#include "HX711.h"

#define valoredicalibrazione -7050.0 //Questo è il valore da modificare fino a raggiungere la corretta misura può essere negativo o positivo


HX711 scale(A1, A0); //il parametro "gain" HX711(Dout,Sck,gain) se omesso assume il valore di default di 128

void setup() {
  Serial.begin(9600);
  Serial.println("HX711 scale demo");

  scale.set_scale(valoredicalibrazione); //Seleziona il parametro di calibrazione
  scale.tare();    //Azzera la tara 

  Serial.println("Letture:");
}

void loop() {
  Serial.print("Lettura: ");
  Serial.print(scale.get_units(), 2); //scale.get_units() returns a float
  Serial.print(" Kg"); //You can change this to kg but you'll need to refactor the calibration_factor
  Serial.println();
}

Aprendo il Serial Monitor vedrete che Arduino comincerà a leggere in sequenza il valore della bilancia, senza nessun oggetto segnerà il peso di 0,0 Kg.

A questo punto prendete un oggetto (un bicchiere, una mela quello che vi pare) pesatelo con una bilancia da cucina e poi ponetelo sulla bilancia collegata ad Arduino.

Modificando la costante: valoredicalibrazione alla riga 22 vedrete che il peso visualizzato nel Serial Monitor cambierà, fate diversi tentativi fino a trovare il valore che riporta il corretto peso dell’oggetto (potrebbe essere espresso in grammi e non Kg).

Quando il valore è uguale alla lettura sulla bilancia da cucina fatta in precedenza il sistema è calibrato!!!

Adesso potete provare qualsiasi altro oggetto a conferma della corretta lettura.

STEP 3 – Carichiamo SCZRE TX (trasmettitore)

Ed ecco lo sketch SCZRE TX da caricare su arduino…

#include "HX711.h"
#include <JeeLib.h>
#include <Manchester.h>
ISR(WDT_vect) {Sleepy::watchdogEvent();}

// HX711.DOUT    - pin #A1
// HX711.PD_SCK	- pin #A0
/*
 * How to Calibrate Your Scale

1. Call set_scale() with no parameter.
2. Call tare() with no parameter.
3. Place a known weight on the scale and call get_units(10).
4. Divide the result in step 3 to your known weight. You should get about the parameter you need to pass to set_scale.
5. Adjust the parameter in step 4 until you get an accurate reading.
 */
// HX711 (Dout,Sck)
HX711 scale(A1, A0);		// parameter "gain" is ommited; the default value 128 is used by the library

#define TX_PIN 6  //pin where your transmitter is connected
#define BUFFER_SIZE 50
#define LED_PIN 13
#define CELL_PIN A0


//*********** SERIAL NUMBER ***********
char SerialSens[ ]="SCZRE0364";
//*************************************

int volt=0;
char messaggio[32];
unsigned char data[BUFFER_SIZE]="";
char msg[BUFFER_SIZE];
char msg2[10];
char msg3[10];
char msg4[10];
float carica=0;
char vuota[32]="";
int offset_scale=53;

// How often do we do readings?
long time = 0; //
int timeBetweenReadings = 500; // We want a reading every 200 ms;


void setup() {
  Serial.begin(9600);
  man.workAround1MhzTinyCore(); //add this in order for transmitter to work with 1Mhz Attiny85/84
  man.setupTransmit(TX_PIN, MAN_600);
  
  pinMode ( LED_PIN, OUTPUT);
  pinMode ( TX_PIN, OUTPUT);

  
  Serial.println("HX711 Demo");

  Serial.println("Before setting up the scale:");
  Serial.print("read: \t\t");
  Serial.println(scale.read());			// print a raw reading from the ADC

  Serial.print("read average: \t\t");
  Serial.println(scale.read_average(20));  	// print the average of 20 readings from the ADC

  Serial.print("get value: \t\t");
  Serial.println(scale.get_value(5));		// print the average of 5 readings from the ADC minus the tare weight (not set yet)

  Serial.print("get units: \t\t");
  Serial.println(scale.get_units(5), 1);	// print the average of 5 readings from the ADC minus tare weight (not set) divided 
						// by the SCALE parameter (not set yet)  

  scale.set_scale(291.00);                      // this value is obtained by calibrating the scale with known weights; see the README for details
  scale.tare();				        // reset the scale to 0

  Serial.println("After setting up the scale:");

  Serial.print("read: \t\t");
  Serial.println(scale.read());                 // print a raw reading from the ADC

  Serial.print("read average: \t\t");
  Serial.println(scale.read_average(20));       // print the average of 20 readings from the ADC

  Serial.print("get value: \t\t");
  Serial.println(scale.get_value(5));		// print the average of 5 readings from the ADC minus the tare weight, set with tare()

  Serial.print("get units: \t\t");
  Serial.println(scale.get_units(5), 1);        // print the average of 5 readings from the ADC minus tare weight, divided 
						// by the SCALE parameter set with set_scale

  Serial.println("Readings:");
}

void loop() {
  
  Serial.print("\t| PESO:\t");
  float peso=-scale.get_units(10);
  if (peso>-3 && peso<3) peso=0;
  Serial.print(peso, 0);Serial.println(" gr.");
  delay(50);
  
 
  
  dtostrf(peso, 4, 1,msg2);
  
   
   float risultato=readVcc();
    
    dtostrf(risultato, 4, 0,msg4);
    carica=risultato/1000;
    dtostrf(carica, 1, 3,msg4);

    strcpy(msg,"");    
    strcat(msg, "SN:");
    strcat(msg, SerialSens);
    strcat(msg, "PE:");
    strcat(msg, msg2); 
    strcat(msg, "BT:");
    strcat(msg, msg4);   
    
    
    
    
      for (int i=0;i<=BUFFER_SIZE;i++)
    {
      data[i]=msg[i];    
    }
    digitalWrite(LED_PIN, true); //Lampeggia il led al ricevimento del messaggio
    delay(10);
    digitalWrite(LED_PIN, false);
    man.transmitArray(BUFFER_SIZE,data);
    
    
    
     scale.power_down();              // put the ADC in sleep mode
  Sleepy::loseSomeTime(30000);
  scale.power_up();
}

float readVcc() {
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    ADMUX = _BV(MUX3) | _BV(MUX2);
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif  
 
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring
 
  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
  uint8_t high = ADCH; // unlocks both
 
  long result = (high<<8) | low;
 
  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return result; // Vcc in millivolts
}

Ovviamente alla riga 71 modificate il valore con quello che avete ottenuto durante la calibrazione.

Lo sketch si basa sul protocollo di trasmissione utilizzato dal progetto SmartCityZen, quindi rispetto alla singola funzionalità di controllo rifiuti ci sono alcune informazioni inviate ridondanti ( per esempio il codice del sensore o i volt della batteria).
In questo modo però i dati trasmessi posso essere letti anche dalle SCZ Station e trasferiti via Internet sul server Web SmartCityZen Web e condivisi attraverso il portale.

Lo sketch invia al ricevitore ogni 30 secondi il peso dei rifiuti, questo valore può essere modificato sempolicemente cambiando il valore di questo comando

Sleepy::loseSomeTime(30000);

Modificando i 30000 mS fino ad un valore Max di 60000 mS,
che prevede una pausa di 1 minuto, per aumentarla e fare per esempio un’invio ogni 3 minuti usare la seguente sintassi:

Sleepy::loseSomeTime(60000);
Sleepy::loseSomeTime(60000);
Sleepy::loseSomeTime(60000);

Richiamando 3 volte il comando.

STEP 4 – Sistema Ricevitore

Il sistema ricevitore necessita il collegamento di Arduino con il display 1602 e con il Ricevitore RF a 433 Mhz.

Secondo questo schema di collegamento:

Fritzing Scheme SCZRE RX_bb

E questo è lo sketch da caricare:

/* -------------------------------------------------------------------------------

// Monitoraggio produzione rifiuti casalinghi con SCZRE
con display LCD 16x2 1602
con registrazione in EPROM del totrifiuti
e dell'ulima pesata

// www.smartcityzen.it
 */
#include <LiquidCrystal.h>
#include <SPI.h>
#include <SD.h>
#include <Manchester.h>
#include <string.h>
#include <EEPROMex.h>


// Connections:
// rs (LCD pin 4) to Arduino pin 12
// rw (LCD pin 5) to Arduino pin 11
// enable (LCD pin 6) to Arduino pin 10
// LCD pin 15 to Arduino pin 13
// LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2

// Ricevitore RF connesso a pin 7 arduino

LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

int backLight = 13;    // pin 13 will control the backlight

//Configurazione Libreria Manchester per trasmissione
#define RX_PIN 7
#define BUFFER_SIZE 50
uint8_t buffer[BUFFER_SIZE];
unsigned char message[BUFFER_SIZE];

#define LED_PIN 13
char SensMessage[] = "SCZXX";

// Memorizzazione totale rifiuti
String dataInizio = "02/01/2016";
int addressFloat = 0;
int addressFloatPeso=5;
boolean scarico=HIGH;
float totRifiuti = 0.0;


float precPeso = 0;
float nowPeso = 0;


void setup()
{
  Serial.begin(9600);
  //EEPROM.writeFloat(addressFloat,totRifiuti);
  //EEPROM.writeFloat(addressFloatPeso,precPeso);
  pinMode(backLight, OUTPUT);
  digitalWrite(backLight, LOW); // turn backlight on. Replace 'HIGH' with 'LOW' to turn it off.
  lcd.begin(16, 2);             // columns, rows.  use 16,2 for a 16x2 LCD, etc.
  lcd.clear();                  // start with a blank screen
  lcd.setCursor(0, 0);          // set cursor to column 0, row 0 (the first row)
  lcd.print("SCZ Recycle");    // change this text to whatever you like. keep it clean.
  lcd.setCursor(0, 1);          // set cursor to column 0, row 1
  lcd.print("smartcityzen.it");
  totRifiuti = EEPROM.readFloat(0);
  precPeso=EEPROM.readFloat(5);


  //Configurazione Manchester
  man.setupReceive(RX_PIN, MAN_600);
  man.beginReceiveArray(BUFFER_SIZE, buffer);

  delay(500);
  lcd.clear();                  // start with a blank screen
  lcd.setCursor(0, 0);          // set cursor to column 0, row 0 (the first row)
  lcd.print("Attendi");
}

void loop()
{

  if (man.receiveComplete())
  {
    uint8_t receivedSize = 0;
    Serial.println("Ricevuto: ");
    digitalWrite(LED_PIN, HIGH);
    delay(100);
    digitalWrite(LED_PIN, LOW);
    for (int i = 0; i < BUFFER_SIZE; i++)
    {

      message[i] = char(buffer[i]);
      Serial.print(char(message[i]));
    }
    Serial.println();
    Serial.print("SENSORE: ");
    for (int t = 0; t < 5; t++)
    {
      SensMessage[t] = message[t + 3];
    }
    String messstr = String(SensMessage);
    Serial.println(messstr);




    if (messstr == "SCZRE")
    {
      Serial.println("Ricevuto un SCZ RECYCLING");
      gestioneSCZRE();
    }
    man.beginReceiveArray(BUFFER_SIZE, buffer);

  }
  else
  {
    
    lcd.setCursor(0, 0);
    lcd.print("TOT: ");
    lcd.print(totRifiuti+nowPeso);
    lcd.print(" KG");
    Serial.print("totRifiuti:");Serial.println(totRifiuti);
    lcd.setCursor(0, 1);
    lcd.print("NOW: ");
    lcd.print(nowPeso);
    lcd.print(" KG");
    Serial.print("nowPeso:");Serial.println(nowPeso);
  }
}

//---------------------------------SCZRE--------------------------
void gestioneSCZRE()
{







  Serial.print("IN FUNZIONE: ");
  for (int i = 0; i < BUFFER_SIZE; i++)
  {


    Serial.print(char(message[i]));
  }

  String nowRifiuti = "";
  Serial.print("nowRifiuti:");Serial.println(nowRifiuti);
  for (int i = 0; i < 5; i++)
  {
  nowRifiuti = nowRifiuti + char(message[i + 15]);
  Serial.print(char(message[i + 15]));
  }
  Serial.print("nowRifiuti:");Serial.println(nowRifiuti);
  nowPeso = nowRifiuti.toFloat();
  if (precPeso==0)
  {
    precPeso=nowPeso;
  }
  if (nowPeso<0.1 && scarico==LOW)
  {
    totRifiuti=totRifiuti+precPeso;
    EEPROM.writeFloat(addressFloat,totRifiuti);
    EEPROM.writeFloat(addressFloatPeso,precPeso);
    scarico=HIGH;
  }
  if (nowPeso>1)
  {
    scarico=LOW;
  }
  Serial.print("nowPeso:");Serial.println(nowPeso);






}

 

CONCLUSIONE

Ed ecco le immagini del progetto finale.

In realtà siccome volevo poter utilizzare il sistema TX con una batteria ho sostituito l’Arduino con un ATMEGA328 su breadboard, riducendo dimensioni e consumo.