I have been looking at using a scale amplifier (similar to the HX-711) with an ESP32 & Teensy 3.2 (similar to most Arduinos) to weigh a food carrying dispenser before and after dispensing to find the weight dispensed by the container. I have connected a button to trigger the dispensing of the components where in essence it will turn a DC motor to turn an auger & dispense but that is not the main topic of this thread.
My issue is with the calculation of the weight before the button is pressed. I am using the ESP32 as the Master which is measuring the weight from the amplifier and sending it to the Teensy 3.2 slave in accordance to the I2C protocol as found here:
/**
A simple sketch to test and demo the dispenser's current features
*/
#include "DispenserData.h"
#include "DispenserUI.h"
#include "Dispenser.h"
#include <Wire.h>
// Const
const int dispensingTimout = 5000; //in milliseconds
float weight;
float prevWeight = 0;
Dispenser dp;
void setup()
{
dp.begin();
// Show product screen at startup
dp.clearScreen();
dp.showProductScreen();
Serial.begin(115200);
}
void loop()
{
// Continuosly check for rfid cards
if (dp.isCardPresent()) {
Serial.print("CardID: ");
Serial.println(dp.getCardID());
// If one is detected, toggle LED
// and display sale screen
dp.buzz();
dp.clearScreen();
dp.showSaleScreen(0);
dp.ledOn();
// Keep filling container until timout is reached
unsigned long startTime = millis();
while (millis() - startTime < dispensingTimout) {
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent);
// Toggle motor depending on whether
// button is pressed
if (dp.isButtonPressed()) {
startTime = millis();
Serial.println("Dispensing.");
dp.motorOn(255);
// Wire.onReceive(receiveEvent);
} else {
dp.motorOff();
}
delay(5000);
}
// After timout, "stop dispensing",
// and return to product screen
dp.motorOff();
dp.ledOff();
dp.clearScreen();
dp.showProductScreen();
}
delay(2500);
}
void receiveEvent(int howmany) {
String weightstring = "";
while(Wire.available()) // loop through all but the last
{
char w = Wire.read(); // receive byte as a character
weightstring = weightstring + w;
//Serial.print(weightstring); // print the character
}
weight = weightstring.toFloat(); // respond with message of 6 bytes // as expected by master
dp.showSaleScreen(weight);
prevWeight = weight;
}
The idea is to take the weight measured before the button is pressed and store it in a float type variable. Then after the button dispensing timeout is done, the weight is measured yet again and subtracted from the initial weight before the button is pressed to give the weight dispensed. The issue comes in retrieving the weight value on the Teensy 3.2 before the while loop. I am not sure how to initialize the Wire.begin( 8 ) / Wire.onReceive(receiveEvent) to execute the code appropriately and have it return to the beginning. Any insight on how to perform this would be very welcome. I have also attached my classes with the slave and master code below for reference. Thank you!
hammy:
If you are doing this for selling items , then the scale has to be approved by the relevant weights and measures organisation .
Yes, I am aware! This is just for a prototype which I plan to upgrade with a more industrialized approach down the line. I just require some guidance for the I2C protocol since I think the way I am currently calling it is probably not the proper way. As far as I know, the wire library should be initialized and run in the setup(), I just require that it continuously calls the Wire.onReceive() function multiple times without impeding the loop's ability to return to the beginning and be able to retrieve the computations discussed here:
iqasi096:
The idea is to take the weight measured before the button is pressed and store it in a float type variable. Then after the button dispensing timeout is done, the weight is measured yet again and subtracted from the initial weight before the button is pressed to give the weight dispensed.
Okey, I've got that.
We need to focus on the sending ESP32. You write that the predisposing calc goes wrong. What about the after disposal measurement? That ought to be bad too. Right?
Railroader:
Okey, I've got that.
We need to focus on the sending ESP32. You write that the predisposing calc goes wrong. What about the after disposal measurement? That ought to be bad too. Right?
Did You calibrate the weight system?
Yes I have accurately configured the weight system and I am able to read the weight on the ESP32 and write the weight into the float variable weight on my Teensy 3.2 here:
void receiveEvent(int howmany) {
String weightstring = "";
while(Wire.available()) // loop through all but the last
{
char w = Wire.read(); // receive byte as a character
weightstring = weightstring + w;
//Serial.print(weightstring); // print the character
}
weight = weightstring.toFloat(); // respond with message of 6 bytes // as expected by master
dp.showSaleScreen(weight);
prevWeight = weight;
}
How am I able to use that variable appropriately into the Teensy 3.2 slave loop??
Railroader:
You have the variable "weight" calculated. Why not use that?
I have used it and was able to display the values on my slave. The problem comes when I have to take the weight difference between the weight before the button is pressed and the weight after the button is pressed.
The component connections are as follows: ESP32 Master:
Load cell amplifier
Teensy 3.2 Slave:
-4.2 inch Waveshare e-paper display
-LED embedded antivandal push button
-MFRC522 RFID module
-Piezo buzzer
How would I be able to tell my ESP32 to store the weight calculated before the button is pressed and subtract the final weight (after the button is no longer pressed) from it when it is not connected to the pushbutton?? Should I be doing the storing of the weight values in the Teensy 3.2 slave instead?? What would be the most feasible approach??
Railroader:
Just before weight is calculated You add a line like this
oldWeight = weight;
Declare oldWeight the same way and in the same place as weight.
Are you saying I do this on the Slave or Master?? In the case you mentioned, the oldweight would only take the last calculated weight value which is calculated about every 5ms, which is good when constantly updating the screen. The way my device is calculating things though is by subtracting the final weight from the initial one.
Example:
I have an initial weight of 40g which is taken, stored and is constantly being updated as im dispensing[Just before button is pressed]:
40
39
38
37
.
.
.
32
I require 40 g to be indicated as my zero point and as i go down to 32 the decrease in weight is incremented my scale. So 39 is 1 g, 38 is 2g etc until it gets to 32 showing a final weight of 8g. After this the 32g would become the initial weight and becoming the new zero point
The way I have it now is that I'm getting a live value of the scale as show here :
40
39
38
37
.
.
.
32
What can I do to manipulate the weight variable I have now to achieve this with I2C??
I have implemented an initial and final weigh function here:
Teensy 3.2 code:
/**
A simple sketch to test and demo the dispenser's current features
*/
#include "DispenserData.h"
#include "DispenserUI.h"
#include "Dispenser.h"
#include <Wire.h>
// Const
const int dispensingTimout = 10000; //in milliseconds
float weight;
float in_weight;
float fin_weight;
float prevWeight = 0;
Dispenser dp;
void setup()
{
// Initialise dispenser
dp.begin();
// Show product screen at startup
dp.clearScreen();
dp.showProductScreen();
Serial.begin(115200);
}
void loop()
{
// Continuosly check for rfid cards
if (dp.isCardPresent()) {
Serial.print("CardID: ");
Serial.println(dp.getCardID());
// If one is detected, toggle LED, buzzer and display sale screen
dp.buzz();
dp.clearScreen();
dp.showSaleScreen(0);
dp.ledOn();
// Keep filling container until timout is reached
unsigned long startTime = millis();
while (millis() - startTime < dispensingTimout) {
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(initialweight);
// Toggle motor depending on whether
// button is pressed
if (dp.isButtonPressed()) {
startTime = millis();
Serial.println("Dispensing.");
dp.motorOn(255);
} else {
dp.motorOff();
}
delay(500);
Wire.onReceive(finalweight);
}
// Debug echo
// Serial.println("Exiting dispensing mode.");
// Serial.print("CardID: ");
// Serial.println(cardID);
// Serial.print("machineID: ");
// Serial.println(machineID);
// Serial.print("weightGrams: ");
// Serial.println(weightGrams);
// After timout, "stop dispensing",
// and return to product screen
dp.motorOff();
//dp.showSaleScreen(weight);
dp.ledOff();
// Wire.onReceive(receiveEvent);
//dp.resetWeight(); //reset
dp.clearScreen();
dp.showProductScreen();
}
delay(2500);
// weight = 0;
// prevWeight = 0;
}
void initialweight(int howmany) {
String weightstring = "";
while(Wire.available()) // loop through all but the last
{
char w = Wire.read(); // receive byte as a character
weightstring = weightstring + w;
//Serial.print(weightstring); // print the character
}
in_weight = weightstring.toFloat(); // respond with message of 6 bytes // as expected by master
//Serial.println(weight);
//if (weight < prevWeight) {
prevWeight = weight;
// }
// Serial.println(weight);
Serial.println("Initial weight is:");
Serial.println(in_weight);
}
void finalweight(int howmany) {
String weightstring = "";
while(Wire.available()) // loop through all but the last
{
char w = Wire.read(); // receive byte as a character
weightstring = weightstring + w;
//Serial.print(weightstring); // print the character
}
weight = weightstring.toFloat(); // respond with message of 6 bytes // as expected by master
fin_weight = in_weight - weight;
//Serial.println(weight);
if (fin_weight > prevWeight) {
dp.showSaleScreen(fin_weight);
prevWeight = fin_weight;
}
// Serial.println(weight);
else{
Serial.println("Final weight is:");
Serial.println(fin_weight);
}
}
My serial monitor as I am dispensing a 1.7 g dispenser looks like this:
Initial weight is:
1.67
Initial weight is:
1.66
Initial weight is:
1.69
Initial weight is:
1.63
Dispensing.
Initial weight is:
1.68
Dispensing.
Dispensing.
Initial weight is:
1.69
Dispensing.
Initial weight is:
1.73
Initial weight is:
1.67
Initial weight is:
1.66
Initial weight is:
1.73
Initial weight is:
1.50
Initial weight is:
1.46
Initial weight is:
1.39
Initial weight is:
1.43
Initial weight is:
1.51
Initial weight is:
1.52
As I dispense the ingredients and the weight decreases, my initial weight decreases with it which is not tolerable as it affects the final weight reading found here:
Final weight is:
Final weight is:
0.63
Final weight is:
0.54
Final weight is:
0.55
Final weight is:
0.64
Final weight is:
0.62
after removing 0.8 g worth of ingredients from the scale which is off by 0.2g. How do I prevent my initial weight value to stop updating once the button is pressed?
You have 2 controllers, the ESP and the Tensy. You just have to decide which controller is doing what.
I would like to se some kind of logical drawing, information flow chart, showing who is doing what. Buttons and while loops I leave to You for the time being.
I don't know the overall architexture of Your build.
Railroader:
You have 2 controllers, the ESP and the Tensy. You just have to decide which controller is doing what.
I would like to se some kind of logical drawing, information flow chart, showing who is doing what. Buttons and while loops I leave to You for the time being.
I don't know the overall architexture of Your build.
I have designed a flow chart shown in the bottom of the post. My complete source code can be found in the zip files that I have attached to the first post of this thread, I have however attached it to this post again for convenience.
Read the first topics telling "How to use forum" etc. and "How to attache code". Many helpers don't take on the job of downloading and filling their computers with members code several times per day. Some helpers using tablets or phones just can't read code this way. You cut of a good part the life line.
Thanks for the flow chart. The Tensy reads the triggering button and handles the motor.
I suggest a serie of events below.
Could the Tensy ask for weight when the button is pressed, receive "previousWeight, run the motor and stop it, and then ask for the weight again, calculate the difference and display it.
What do You think?
Railroader:
Read the first topics telling "How to use forum" etc. and "How to attache code". Many helpers don't take on the job of downloading and filling their computers with members code several times per day. Some helpers using tablets or phones just can't read code this way. You cut of a good part the life line.
Thanks for the flow chart. The Tensy reads the triggering button and handles the motor.
I suggest a serie of events below.
Could the Tensy ask for weight when the button is pressed, receive "previousWeight, run the motor and stop it, and then ask for the weight again, calculate the difference and display it.
What do You think?
Yes, I have tried to do that and it works well now. I just cant seem to stop the display from updating and returning to the showProductScreen() once I initialize the I2C communication as found here:
/**
A simple sketch to test and demo the dispenser's current features
*/
#include "DispenserData.h"
#include "DispenserUI.h"
#include "Dispenser.h"
#include <Wire.h>
// Const
const int dispensingTimout = 10000; //in milliseconds
float weight;
float in_weight;
float fin_weight;
float prevWeight = 0;
Dispenser dp;
void setup()
{
// Initialise dispenser
dp.begin();
// Show product screen at startup
dp.clearScreen();
dp.showProductScreen();
Serial.begin(115200);
}
void loop()
{
// Continuosly check for rfid cards
if (dp.isCardPresent()) {
Serial.print("CardID: ");
Serial.println(dp.getCardID());
// If one is detected, toggle LED, buzzer and display sale screen
dp.buzz();
dp.clearScreen();
dp.showSaleScreen(0);
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(initialweight);
delay(2000);
dp.ledOn();
// Keep filling container until timout is reached
unsigned long startTime = millis();
while (millis() - startTime < dispensingTimout) {
Wire.onReceive(finalweight);
// Toggle motor depending on whether
// button is pressed
if (dp.isButtonPressed()) {
startTime = millis();
Serial.println("Dispensing.");
dp.motorOn(255);
} else {
dp.motorOff();
}
delay(500);
}
// After timout, "stop dispensing",
// and return to product screen
dp.motorOff();
dp.ledOff();
Wire.onReceive(finalweight);
dp.clearScreen();
dp.showProductScreen();
}
delay(2500);
}
void initialweight(int howmany) {
String weightstring = "";
while(Wire.available()) // loop through all but the last
{
char w = Wire.read(); // receive byte as a character
weightstring = weightstring + w;
//Serial.print(weightstring); // print the character
}
in_weight = weightstring.toFloat(); // respond with message of 6 bytes // as expected by master
//Serial.println(weight);
//if (weight < prevWeight) {
prevWeight = weight;
// }
// Serial.println(weight);
Serial.println("Initial weight is:");
Serial.println(in_weight);
}
void finalweight(int howmany) {
String weightstring = "";
while(Wire.available()) // loop through all but the last
{
char w = Wire.read(); // receive byte as a character
weightstring = weightstring + w;
}
weight = weightstring.toFloat(); // respond with message of 6 bytes // as expected by master
fin_weight = in_weight - weight;
if (fin_weight > prevWeight) {
dp.showSaleScreen(fin_weight);
prevWeight = fin_weight;
}
else{
Serial.println("Final weight is:");
Serial.println(fin_weight);
}
}
My wire.onRecieve(finalweight) function keeps repeating even when the process is over and it goes back to the if statement in the beginning of void loop()
I'm not sure if I look at the right If-statement. Is it this one:
void loop()
{
// Continuosly check for rfid cards
if (dp.isCardPresent()) {
Serial.print("CardID: ");
I also don't know how You operate things. There is both a card and a button involved. If the card is present and the button is pressed for a time longer than 2000 + 500 milliseconds then the process repeats every 2.5 second.
Tell the way You operate Your stuff, card, button... The sequence, the timing. If I guess and suggest more logic changes it might not help.