0

I'm pretty new to coding and stuff. I'm working on a digital weighing scale with a HX711 breakout board and outputting the values through a 4 digit 7 segment display.

The weighing() loop read values at a slower rate than my display multiplexing time so the code wouldn't continue until a value has been read resulting in the display flashing like hell. So i tried running the weighing() loop and the displaying() loop simultaneously via concurrent.futures. But the code would execute weighing() only once and then get stuck in the display() loop, so they are not running concurrently?

There must be something wrong with my code, please help me clarify and leave any suggestions for other methods.

import time
import RPi.GPIO as GPIO
import concurrent.futures


GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

segments = [2, 3, 4, 5, 6, 7, 8, 9]
digits = [12, 13, 18, 19]


GPIO.setup(segments, GPIO.OUT)
GPIO.output(segments, GPIO.HIGH)
GPIO.setup(digits, GPIO.OUT)
GPIO.output(digits, GPIO.LOW)

nums ={
    0:(1,1,1,1,1,1,0),
    1:(0,1,1,0,0,0,0),
    2:(1,1,0,1,1,0,1),
    3:(1,1,1,1,0,0,1),
    4:(0,1,1,0,0,1,1),
    5:(1,0,1,1,0,1,1),
    6:(1,0,1,1,1,1,1),
    7:(1,1,1,0,0,0,0),
    8:(1,1,1,1,1,1,1),
    9:(1,1,1,1,0,1,1)}
switchpolarity = {1: 0,
                  0:1}

def display(value):
    while 1:
        s = [int(d) for d in str(value)]        
        for digit in range(0,len(s)):
            for segment in range(0,7):
                GPIO.output(segments[segment], switchpolarity[nums[s[digit]][segment]])
            GPIO.output(digits[digit], 1)
            time.sleep(0.01)
            GPIO.output(digits[digit], 0)


EMULATE_HX711=False

if not EMULATE_HX711:
    from hx711 import HX711
else:
    from emulated_hx711 import HX711

def weighing():
    while 1:
        val = round(abs(hx.get_weight(1)))
        print(val)
        hx.power_down()
        hx.power_up()
        return(val)

hx = HX711(9, 10)
hx.set_reading_format("MSB", "MSB")
hx.set_reference_unit(754)
hx.reset()
hx.tare()

print("Tare done! Add weight now...")


try:

        with concurrent.futures.ProcessPoolExecutor() as executor:
            weighing = executor.submit(weighing)
            displaying = executor.submit(display, (t1.result()))


except(KeyboardInterrupt):
    GPIO.cleanup()

I am very sorry for the typo in the code as I was posting i changed the processes names without testing. This is my new code which i can say is without stupid mistakes:

import time
import RPi.GPIO as GPIO
import concurrent.futures


GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

segments = [2, 3, 4, 5, 6, 7, 8, 9]
digits = [12, 13, 18, 19]


GPIO.setup(segments, GPIO.OUT)
GPIO.output(segments, GPIO.HIGH)
GPIO.setup(digits, GPIO.OUT)
GPIO.output(digits, GPIO.LOW)

nums ={
    0:(1,1,1,1,1,1,0),
    1:(0,1,1,0,0,0,0),
    2:(1,1,0,1,1,0,1),
    3:(1,1,1,1,0,0,1),
    4:(0,1,1,0,0,1,1),
    5:(1,0,1,1,0,1,1),
    6:(1,0,1,1,1,1,1),
    7:(1,1,1,0,0,0,0),
    8:(1,1,1,1,1,1,1),
    9:(1,1,1,1,0,1,1)}
switchpolarity = {1: 0,
                  0:1}

def display(value):
    while 1:
        s = [int(d) for d in str(value)]        
        for digit in range(0,len(s)):
            for segment in range(0,7):
                GPIO.output(segments[segment], switchpolarity[nums[s[digit]][segment]])
            GPIO.output(digits[digit], 1)
            time.sleep(0.01)
            GPIO.output(digits[digit], 0)


EMULATE_HX711=False

if not EMULATE_HX711:
    from hx711 import HX711
else:
    from emulated_hx711 import HX711

def weighing():
    while 1:
        val = round(abs(hx.get_weight(1)))
        print(val)
        hx.power_down()
        hx.power_up()
        return(val)

hx = HX711(9, 10)
hx.set_reading_format("MSB", "MSB")
hx.set_reference_unit(754)
hx.reset()
hx.tare()

print("Tare done! Add weight now...")


try:

        with concurrent.futures.ProcessPoolExecutor() as executor:
            weighing1 = executor.submit(weighing)

            displaying1 = executor.submit(display, (weighing1.result()))


except(KeyboardInterrupt):
    GPIO.cleanup()
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • What is the purpose of the `return val` statement in your `weighing()` function? – Solomon Slow Mar 25 '20 at 10:52
  • The return val in my weighing() function returns the value read from the load cell, so i can display that value with display() function – Phuckhang Nguyen Mar 25 '20 at 10:56
  • `t1.result` isn't set anywhere. I think you need to put `val`, (i.e. the weight) in a global variable so that the display function can see it. – Mark Setchell Mar 25 '20 at 11:05
  • Oh, I am very sorry as before i named the processes "t1" and "t2" which did not make any sense so upon posting, i changed the processes name and forgot about the t1.result. – Phuckhang Nguyen Mar 25 '20 at 11:11
  • I also notice that i renamed the processes same as the functions without testing the code out after renaming. This proves to not work i will now update my new codes – Phuckhang Nguyen Mar 25 '20 at 11:14

1 Answers1

0

This is the main function for your "weighing" thread:

def weighing():
    while 1:
        val = round(abs(hx.get_weight(1)))
        ...
        return(val)

The return(val) statement will cause the function to return at the end of the first iteration of the loop. Once the function returns, the thread is finished. It won't ever run again.

This is how you start your threads:

weighing = executor.submit(weighing)
displaying = executor.submit(display, (t1.result()))

If I understand correctly,* The executor.submit(weighing) call returns a future, and the t1.result()** awaits the completion of the future, and then returns whatever value was returned by the weighing function.

That means, that the executor.submit(display, ...) will not happen until t1.result() returns a value, which means that the second thread can not even start until the first thread is finished.


IMO;

  • Your weighing() function should update a global variable and continue looping forever instead of returning a value, and

  • Your display() function should get the value that it displays by copying from the global variable, and

  • You can just ignore the futures that are returned by the ProcessPoolExecutor. You aren't really using it as an executor service: You're just using it as a way to create two threads.


* I'm not actually a Python guru.

** I'm assuming that t1.result() is a copy/paste error, and that you meant to say weighing.result().

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57
  • It looks like my global variable isn't working as expected, i believe it isn't shared between my processes, how do i solve this? – Phuckhang Nguyen Mar 25 '20 at 14:23
  • Did you _declare_ it to be `global`? Each function that wants to access a global variable must contain a `global` declaration of that variable (e.g., `global value`). If you forget that, then the function will access a local variable with a name that shadows the global, and Python won't warn you about the problem. – Solomon Slow Mar 25 '20 at 14:49
  • Im declaring it outside the functions as `gv = 1234`, inside the `weighing( )` function i do `global gv` and inside the while loop i have a statement `gv = val`. It's not working, did i miss something? – Phuckhang Nguyen Mar 26 '20 at 02:44
  • What about inside the `display()` function? – Solomon Slow Mar 26 '20 at 11:59