Python Forum
Normalizing a value from HX711 - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Normalizing a value from HX711 (/thread-29549.html)



Normalizing a value from HX711 - duckredbeard - Sep-09-2020

I have a scale project that is used to determine the quantity of beer in a keg. Since not all beers weigh the same, the full weight of the keg is inconsistent. I'd like to find a way to "normalize" the range of variables used for the varied weights. When I run the following code, it starts out with getting a "zero" reference then I place the full keg on. With a full keg, I get values between 500000 and 515000. How do I convert the larger number to a simple "100" so that I could use percentage of range (0-100) instead of 0-inconsistent number.

# Scale project that uses a scale to determine the volume of beer in the keg.
# A row of LEDs indicates the state of the program and the volume of the keg.
# A requests post initiates a push notification to my phone when the weight of the keg changes.

import time
import sys
import requests
from gpiozero import LED


#Define LED indicators - these are GPIO numbers
LED1 = LED(21) #Blue
LED2 = LED(26) #Red
LED3 = LED(20) #Amber
LED4 = LED(19) #Green
LED5 = LED(16) #Green
LED6 = LED(13) #Green
LED7 = LED(6) #Green
LED8 = LED(12) #Green
LED9 = LED(5) #Pink

EMULATE_HX711=False

referenceUnit = 1

if not EMULATE_HX711:
    import RPi.GPIO as GPIO
    from hx711 import HX711
else:
    from emulated_hx711 import HX711

def moving_average(prev_average, new_value, num_steps = 5.0):
   return (prev_average * (num_steps - 1) + new_value) / num_steps

average = weight = 400000  #just a value close to what a newly deployed keg would be
w_threshold = 2000  #approximate value of 3-4 fluid ounces of the beer 

def cleanandexit():
    print("Cleaning...")
    if not EMULATE_HX711:
        GPIO.cleanup()        
    print("Bye!")
    sys.exit()

hx = HX711(27, 22)
hx.set_reading_format("MSB", "MSB")
hx.set_reference_unit(1)
hx.reset()
hx.tare()

print("The scale is ready")  
print("put the keg on...")

LED9.blink(.2,3)  # indication that the scale is running - not blinking means program crash
start = time.time()

while True:
    try:        
        keg1 = hx.get_weight(5)
        weight = keg1
        keg1 = round(keg1,3)
        start_weight = keg1
        print(keg1, average)
        if time.time() - start > 5:
            weight = keg1
            lost_weight = average - keg1
            lost_weight = round(lost_weight,3)
            if lost_weight > w_threshold:
               #r = requests.post("https://bit.ly/editedforprivacy")  #Join URL that triggers push notification to my phone
               print("You got served")
               average = keg1  #resets average to new keg1 value for faster recovery
            print(lost_weight)  #visual indication of how much was poured - one pint is about 8400
            average = moving_average(average, weight)
            average = round(average,3)
            start = time.time()


        if 8000 >= keg1 <= 507001: #keg is outside of usable range - flashes when keg is missing (indicating tare is complete at startup)
            LED1.blink(.2,.2)
        else:
            LED1.off()

        if 109800 >= keg1 >= 80000: #Red less than 5% - DANGER
            LED2.blink(.5,.5)
        else:
            LED2.off()
            
        if 130600 >= keg1 >= 109799: #Amber less than 10% - Warning
            LED3.on()
        else:
            LED3.off()
            
        if 507000 >= keg1 >= 130599: #  Green 10-20% - Caution
            LED4.on()
        else:
            LED4.off()
            
        if 507000 >= keg1 >= 172199: #Green2 20-40%
            LED5.on()
        else:
            LED5.off()
            
        if 507000 >= keg1 >= 255400: #Green3 40-60%
            LED6.on()
        else:
            LED6.off()
            
        if 507000 >= keg1 >= 338600: #Green4 60-80%
            LED7.on()
        else:
            LED7.off()
            
        if 507000 >= keg1 >= 421800: #Green5 80-100%
            LED8.on()
        else:
            LED8.off()


        hx.power_down()
        hx.power_up()
        time.sleep(1)


    except (KeyboardInterrupt, SystemExit):

        cleanandexit()
Keep in mind that this code's values are based on a full keg being about 507000 and an empty keg being about 89000. This works out to a net weight of about 418000, which is the weight of the beer.

I have found that I can get inconsistent "full" values using the same keg. Running this 4 times this morning, I got the following values for full: 507000, 511000, 509000, and 516000.


RE: Normalizing a value from HX711 - deanhystad - Sep-09-2020

scale = 100 / (full - empty)
percent_full = (weight - empty) * scale

Empty is the weight of an empty keg. Hopefully this is consistent enough to be a constant. full is the weight of a full keg and would be taken just before entering the loop. It will be different for each keg.


RE: Normalizing a value from HX711 - duckredbeard - Sep-09-2020

That seems easy enough. So what I need to do now is to tell the program when to capture the "full" value. Plobby do that with a button push, kind of like a reset function. I will see what I can do with this. Thanks for the idea.


RE: Normalizing a value from HX711 - duckredbeard - Sep-09-2020

So I added a few things, haven't been able to test it yet. Let me know if this is what you were talking about. I only changed the part where these maths control the lights, not much else. I also added the reset button on GPIO4, expecting a push of that button will reset the "full" value to the currently observed "keg1" value that the HX711 is reporting. On paper, this looks like what I am after.

Behold the code:
# Scale project that uses a scale to determine the volume of beer in the keg.
# A row of LEDs indicates the state of the program and the volume of the keg.
# A requests post initiates a push notification to my phone when the weight of the keg changes.
 
import time
import sys
import requests
from gpiozero import LED
 
 
#Define LED indicators - these are GPIO numbers
LED1 = LED(21) #Blue
LED2 = LED(26) #Red
LED3 = LED(20) #Amber
LED4 = LED(19) #Green
LED5 = LED(16) #Green
LED6 = LED(13) #Green
LED7 = LED(6) #Green
LED8 = LED(12) #Green
LED9 = LED(5) #Pink
Reset = Button(4) #Button to reset the variable "full" to the current scale value


EMULATE_HX711=False
 
referenceUnit = 1
 
if not EMULATE_HX711:
    import RPi.GPIO as GPIO
    from hx711 import HX711
else:
    from emulated_hx711 import HX711
 
def moving_average(prev_average, new_value, num_steps = 5.0):
   return (prev_average * (num_steps - 1) + new_value) / num_steps

def reset_full():
    full = keg1
    
average = weight = 400000  #just a value close to what a newly deployed keg would be
w_threshold = 2000  #approximate value of 3-4 fluid ounces of the beer 
 
def cleanandexit():
    print("Cleaning...")
    if not EMULATE_HX711:
        GPIO.cleanup()        
    print("Bye!")
    sys.exit()
 
hx = HX711(27, 22)
hx.set_reading_format("MSB", "MSB")
hx.set_reference_unit(1)
hx.reset()
hx.tare()
 
print("The scale is ready")  
print("put the keg on...")
 
LED9.blink(.2,3)  # indication that the scale is running - not blinking means program crash
start = time.time()
 
while True:
    try:        
        keg1 = hx.get_weight(5)
        weight = keg1
        keg1 = round(keg1,3)
        start_weight = keg1
        
        print(keg1, average)
        if time.time() - start > 5:
            weight = keg1
            lost_weight = average - keg1
            lost_weight = round(lost_weight,3)
            if lost_weight > w_threshold:
               #r = requests.post("https://bit.ly/editedforprivacy")  #Join URL that triggers push notification to my phone
               print("You got served")
               average = keg1  #resets average to new keg1 value for faster recovery
            print(lost_weight)  #visual indication of how much was poured - one pint is about 8400
            average = moving_average(average, weight)
            average = round(average,3)
            start = time.time()
            Reset.when_pressed = reset_full

            full = keg1
            empty = 89000
            scale = 100 / (full - empty)
            percent_full = (weight - empty) * scale

 
        if 1 >= percent_full <= 102: #keg is outside of usable range - flashes when keg is missing (indicating tare is complete at startup)
            LED1.blink(.2,.2)
        else:
            LED1.off()
 
        if 1.1 >= percent_full >= 5: #Red less than 5% - DANGER
            LED2.blink(.5,.5)
        else:
            LED2.off()
             
        if 100 >= percent_full >= 10: #Amber less than 10% - Warning
            LED3.on()
        else:
            LED3.off()
             
        if 100 >= percent_full >= 20: #  Green 10-20% - Caution
            LED4.on()
        else:
            LED4.off()
             
        if 100 >= percent_full >= 40: #Green2 20-40%
            LED5.on()
        else:
            LED5.off()
             
        if 100 >= percent_full >= 60: #Green3 40-60%
            LED6.on()
        else:
            LED6.off()
             
        if 100 >= percent_full >= 80: #Green4 60-80%
            LED7.on()
        else:
            LED7.off()
             
        if 100 >= keg1 >= 80.1: #Green5 80-100%
            LED8.on()
        else:
            LED8.off()
 
 
        hx.power_down()
        hx.power_up()
        time.sleep(1)
 
 
    except (KeyboardInterrupt, SystemExit):
 
        cleanandexit()



RE: Normalizing a value from HX711 - deanhystad - Sep-10-2020

The percent_full equation converts the keg weight to a number in the range 0 to 100. This is the number you should use for calculating average and turning LED's on and off. It should be calculated each time you weigh the keg.