Coming off break and getting back into the swing of things, this week offered an opportunity for us as a team and individually to reflect on our progress to meet our NutrientMatch MVP. Entering the project work period where we had an ambitious idea but were largely uninformed of implementation strategies, we are in a much better space now as we have taken a deep dive into building the stages of the design. For me, this was a week where my preconceived notions and ideas of integrating the scale into the project were challenged, and I considered alternative options in the form of risk mitigation and to complete our MVP. I’d like to dedicate this week’s blog posts to explaining what I learned and subsequent approaches.
Our first idea to integrate the scale with a remote database (and subsequent display to a custom website) involved a physical scale, signal amplifiers, microcontrollers and logic, and a WiFi chip which would make requests to a backend engine for website rendering. The first design consideration was whether to build a custom scale or hack into an existing one. We favored the latter, as scales built in the market today are more complex than one would think, and have several nuanced electronic components that ensure the measurements are accurate. The downside to this approach, however, is the lack of customizability given the scale is prebuilt, and the fact that we would need to exercise extreme caution so as to not cut the wrong wires or the solder components to the wrong sections of the scale.
The next step involved rewiring the load cells to run through an amplifier. A load cell is just a component that translates experienced mechanical force into a signal to be interpreted digitally. When running these signals to an Arduino for display, the signals themselves are typically low in amplitude compared to the sensitivity of the ADC input of the microcontroller; hence the need for a load cell amplifier.
For testing, a nice thing to do would be to wire the load cell amplifier outputs to a 7-segment display, just to get an idea of the numbers we are dealing with. In implementation, the next step would be to send these signals to the ESP32 chip. This is where we will develop a significant component of the logic to control when the load cells are sampled. Furthermore, the ESP32 script needs to generate an HTTP request wirelessly to our cloud-hosted web application so it can write in the measured weight when certain conditions are met. These include if the weight is stable, if the website hasn’t been updated yet, and so on. Find below some of the logic I wrote for the ESP implementing the above concepts in detail. Some of it is in pseudocode, for simplicity:
void loop() { static float history[4]; static float ave = 0; static bool stable = false; static bool webUpdated = false; static float weightData = 0.0; // When should we send a request to the server? this controls that if (stable && !webUpdated) { // Only try if the wireless network is connected // WL_CONNECTED is an imported state from the earlier logic in the ESP if((wifiMulti.run() == WL_CONNECTED)) { HTTPClient http; Serial.print("[HTTP] begin...\n"); Serial.println(weightData); // Write string address of where website is hosted here String weight = String(weightData, 1); String fullAddress = String(address + weight); http.begin(fullAddress); Serial.print("[HTTP] GET...\n"); // start connection and send HTTP header int httpCode = http.GET(); if(httpCode > 0) { // HTTP header has been send and Server response header has been handled Serial.printf("[HTTP] GET... code: %d\n", httpCode); // file found at server, response 200 if(httpCode == HTTP_CODE_OK) { // clear the stable flag as the data is no longer valid stable = false; webUpdated = true; Serial.println("Web updated"); } } else { // debugging case Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); } http.end(); } } // Check the weight measurement every 250ms (THIS IS ARBRITRARY) if (millis() - scaleTick > 250) { scaleTick = millis(); // Read from the HX711. have 2 do this before using data LoadCell.update(); weightData = abs(LoadCell.getData()); //running average history[3] = history[2]; history[2] = history[1]; history[1] = history[0]; history[0] = weightData; ave = (history[0] + history[1] + history[2] + history[3])/4; // Logic to control when to write in the weight measurement if ((abs(ave - weightData) < 0.1) && (ave > 30) && !webUpdated) { stable = true; } // IF we've updated the website AND // the average weight is close to zero, clear the website updated flag // so we are ready for the next weight reading if (webUpdated && ave < 1) { webUpdated = false; } Serial.print("Load_cell output val: "); Serial.println(weightData); // Write in the scale reading here! } }
The web application handles incoming HTTP requests from here on out, so there is no more to implement on the scale side of things.
Now, this plan that our team developed in theory works very well, but some of the things that concern us mainly have to do with uncertainties on the scale end. Hacking a scale requires a strong understanding of how the scale is built to begin with, so we can avoid damaging existing wiring and components. So I began to think about alternative options for scale integration that wouldn’t involve the internals of the scale electronics. A less risky, but equally stimulating implementation idea would be to hook up an RPI camera and physically read the digital scale reading; this would also require talking to an external sensor which would tell the camera to only “sample” and take pictures when the door of our apparatus is closed. The module would forward the image result to an ML algorithm which would detect the weight measured and write it to the database.
The drawbacks to this approach are the increased probability of measurement inaccuracy, as well as the fact that it would be harder to control the logic for when to capture the images. Also, images are more memory intensive than streams of data, so the RPI would need to have a decent amount of memory onboard to handle the image capturing. In either case, we have plenty of money under the budget to implement both (highly cost effective) ideas, so we will be trying both in parallel and seeing which approach makes more sense.
I envision the next 2 weeks in advance of our demo to be an important time for our project development; I’m excited to get to work on the scale once our parts come in!