Skip to content

Commit 75cf14a

Browse files
authored
Merge pull request #2213 from adafruit/food_scale
adding code for the food scale learn guide
2 parents 1420420 + 826ba02 commit 75cf14a

File tree

2 files changed

+321
-0
lines changed

2 files changed

+321
-0
lines changed

NAU7802_Food_Scale/callibration.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
callibration = {
5+
'offset_val' : 60.8006, # default offset for 6 lbs
6+
'weight' : 2721.55 # 6 lbs in grams
7+
}

NAU7802_Food_Scale/code.py

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
import time
5+
import board
6+
from digitalio import DigitalInOut, Direction, Pull
7+
from adafruit_ht16k33.segments import Seg14x4
8+
from cedargrove_nau7802 import NAU7802
9+
from callibration import callibration
10+
11+
# I2C setup with STEMMA port
12+
i2c = board.STEMMA_I2C()
13+
# alphanumeric segment displpay setup
14+
# using two displays together
15+
display = Seg14x4(i2c, address=(0x71, 0x70))
16+
# start-up text
17+
display.print("*HELLO* ")
18+
# button LEDs
19+
blue = DigitalInOut(board.A0)
20+
blue.direction = Direction.OUTPUT
21+
green = DigitalInOut(board.A2)
22+
green.direction = Direction.OUTPUT
23+
# buttons setup
24+
blue_btn = DigitalInOut(board.A1)
25+
blue_btn.direction = Direction.INPUT
26+
blue_btn.pull = Pull.UP
27+
green_btn = DigitalInOut(board.A3)
28+
green_btn.direction = Direction.INPUT
29+
green_btn.pull = Pull.UP
30+
# nau7802 setup
31+
nau7802 = NAU7802(board.STEMMA_I2C(), address=0x2A, active_channels=2)
32+
nau7802.gain = 128
33+
enabled = nau7802.enable(True)
34+
35+
# zeroing function
36+
def zero_channel():
37+
"""Initiate internal calibration for current channel; return raw zero
38+
offset value. Use when scale is started, a new channel is green_btned, or to
39+
adjust for measurement drift. Remove weight and tare from load cell before
40+
executing."""
41+
blue.value = True
42+
print(
43+
"channel %1d calibrate.INTERNAL: %5s"
44+
% (nau7802.channel, nau7802.calibrate("INTERNAL"))
45+
)
46+
blue.value = False
47+
print(
48+
"channel %1d calibrate.OFFSET: %5s"
49+
% (nau7802.channel, nau7802.calibrate("OFFSET"))
50+
)
51+
blue.value = True
52+
zero_offset = read_raw_value(100) # Read 100 samples to establish zero offset
53+
print("...channel %1d zeroed" % nau7802.channel)
54+
blue.value = False
55+
return zero_offset
56+
# read raw value function
57+
def read_raw_value(samples=100):
58+
"""Read and average consecutive raw sample values. Return average raw value."""
59+
sample_sum = 0
60+
sample_count = samples
61+
while sample_count > 0:
62+
if nau7802.available:
63+
sample_sum = sample_sum + nau7802.read()
64+
sample_count -= 1
65+
return int(sample_sum / samples)
66+
# function for finding the average of an array
67+
def find_average(num):
68+
count = 0
69+
for n in num:
70+
count = count + n
71+
average = count / len(num)
72+
return average
73+
# callibration function
74+
def calculateCallibration(array):
75+
for _ in range(10):
76+
blue.value = True
77+
green.value = False
78+
nau7802.channel = 1
79+
#value = read_raw_value()
80+
print("channel %1.0f raw value: %7.0f" % (nau7802.channel, read_raw_value()))
81+
array.append(read_raw_value())
82+
blue.value = False
83+
green.value = True
84+
time.sleep(1)
85+
green.value = False
86+
avg = find_average(array)
87+
return avg
88+
# blink LED function
89+
def blink(led, amount, count):
90+
for _ in range(count):
91+
led.value = True
92+
time.sleep(amount)
93+
led.value = False
94+
time.sleep(amount)
95+
96+
# zeroing on startup
97+
display.fill(0)
98+
display.marquee("CLEAR SCALE CLEAR", 0.3, False)
99+
time.sleep(2)
100+
display.fill(0)
101+
display.print("ZEROING")
102+
time.sleep(3)
103+
# zeroing each channel
104+
nau7802.channel = 1
105+
zero_channel() # Calibrate and zero channel
106+
nau7802.channel = 2
107+
zero_channel() # Calibrate and zero channel
108+
display.fill(0)
109+
display.print("STARTING")
110+
111+
# variables and states
112+
clock = time.monotonic() # time.monotonic() device
113+
mode = "run"
114+
mode_names = ["SHOW OZ?", " GRAMS?", " ZERO?", "CALIBRTE", " OFFSET?"]
115+
#offset_val = callibration['offset_val']
116+
stage = 0
117+
weight_avg = 0
118+
zero_avg = 0
119+
show_oz = True
120+
show_grams = False
121+
zero_out = False
122+
callibrate_mode = False
123+
blue_btn_pressed = False
124+
green_btn_pressed = False
125+
run_mode = True
126+
127+
while True:
128+
# button debouncing
129+
if blue_btn.value and blue_btn_pressed:
130+
blue_btn_pressed = False
131+
if green_btn.value and green_btn_pressed:
132+
green_btn_pressed = False
133+
green.value = False
134+
# default run mode
135+
# checks NAU7802 every 2 seconds
136+
if run_mode is True and (time.monotonic() - clock) > 2:
137+
nau7802.channel = 1
138+
value = read_raw_value()
139+
# takes value reading and divides with by the offset value
140+
# to get the weight in grams
141+
grams = value / callibration['offset_val']
142+
# convert grams to ounces
143+
oz = grams / 28.35
144+
# display in ounces (default)
145+
if show_oz is True:
146+
if oz < 0:
147+
oz = 0
148+
display.print(" %0.2f oz" % oz)
149+
# display in grams
150+
if show_grams is True:
151+
if grams < 0:
152+
grams = 0
153+
display.print(" %0.2f g" % grams)
154+
clock = time.monotonic()
155+
# if you press the change mode button
156+
if (not green_btn.value and not green_btn_pressed) and run_mode:
157+
green.value = True
158+
# disables run mode (stops weighing)
159+
run_mode = False
160+
show_oz = False
161+
show_grams = False
162+
# mode is set to 0
163+
mode = 0
164+
# display shows the mode option
165+
display.print(mode_names[mode])
166+
blue.value = True
167+
green_btn_pressed = True
168+
# advances through the modes menu
169+
if (not green_btn.value and not green_btn_pressed) and mode != "run":
170+
green.value = True
171+
# counts up to 4 and loops back to 0
172+
mode = (mode+1) % 5
173+
# updates display
174+
display.print(mode_names[mode])
175+
green_btn_pressed = True
176+
# if you select show_oz
177+
if (not blue_btn.value and not blue_btn_pressed) and mode == 0:
178+
# show_oz is set as the state
179+
show_oz = True
180+
blue.value = False
181+
# goes back to weighing mode
182+
run_mode = True
183+
mode = "run"
184+
blue_btn_pressed = True
185+
# if you select show_grams
186+
if (not blue_btn.value and not blue_btn_pressed) and mode == 1:
187+
# show_grams is set as the state
188+
show_grams = True
189+
blue.value = False
190+
# goes back to weighing mode
191+
run_mode = True
192+
mode = "run"
193+
blue_btn_pressed = True
194+
# if you select zero_out
195+
if (not blue_btn.value and not blue_btn_pressed) and mode == 2:
196+
# zero_out is set as the state
197+
# can zero out the scale without full recallibration
198+
zero_out = True
199+
blue.value = False
200+
mode = "run"
201+
blue_btn_pressed = True
202+
# if you select callibrate_mode
203+
if (not blue_btn.value and not blue_btn_pressed) and mode == 3:
204+
# callibrate_mode is set as the state
205+
# starts up the callibration process
206+
callibrate_mode = True
207+
blue.value = False
208+
mode = "run"
209+
blue_btn_pressed = True
210+
# if you select the offset
211+
if (not blue_btn.value and not blue_btn_pressed) and mode == 4:
212+
# displays the curren offset value stored in the code
213+
blue.value = False
214+
display.fill(0)
215+
display.print("%0.4f" % callibration['offset_val'])
216+
time.sleep(5)
217+
mode = "run"
218+
# goes back to weighing mode
219+
run_mode = True
220+
show_oz = True
221+
blue_btn_pressed = True
222+
# if the zero_out state is true
223+
if zero_out and mode == "run":
224+
# updates display
225+
display.fill(0)
226+
display.print("ZEROING")
227+
blue.value = False
228+
# runs zero_channel() function on both channels
229+
nau7802.channel = 1
230+
zero_channel()
231+
nau7802.channel = 2
232+
zero_channel()
233+
display.fill(0)
234+
display.print("ZEROED ")
235+
zero_out = False
236+
# goes into weighing mode
237+
run_mode = True
238+
show_oz = True
239+
# the callibration process
240+
# each step is counted in stage
241+
# blue button is pressed to advance to the next stage
242+
if callibrate_mode is True and stage == 0:
243+
blue_btn_pressed = True
244+
# clear the scale for zeroing
245+
display.fill(0)
246+
display.print("REMOVE ")
247+
stage = 1
248+
blue.value = True
249+
# stage 2
250+
if (not blue_btn.value and not blue_btn_pressed) and stage == 1:
251+
blue_btn_pressed = True
252+
# runs the zero out function
253+
display.fill(0)
254+
display.print("ZEROING")
255+
blue.value = False
256+
nau7802.channel = 1
257+
zero_channel()
258+
nau7802.channel = 2
259+
zero_channel()
260+
display.fill(0)
261+
display.print("ZEROED ")
262+
stage = 2
263+
blue.value = True
264+
# stage 3
265+
if (not blue_btn.value and not blue_btn_pressed) and stage == 2:
266+
blue_btn_pressed = True
267+
blue.value = False
268+
display.print("STARTING")
269+
blink(blue, 0.5, 3)
270+
zero_readings = []
271+
display.print("AVG ZERO")
272+
# runs the calculateCallibration function
273+
# takes 10 raw readings, stores them into an array and gets an average
274+
zero_avg = calculateCallibration(zero_readings)
275+
stage = 3
276+
display.fill(0)
277+
display.print("DONE")
278+
blue.value = True
279+
# stage 4
280+
if (not blue_btn.value and not blue_btn_pressed) and stage == 3:
281+
# place the known weight item
282+
# item's weight matches callibration['weight'] in grams
283+
blue_btn_pressed = True
284+
blue.value = False
285+
display.fill(0)
286+
display.print("PUT ITEM")
287+
stage = 4
288+
blue.value = True
289+
# stage 5
290+
if (not blue_btn.value and not blue_btn_pressed) and stage == 4:
291+
blue_btn_pressed = True
292+
blue.value = False
293+
display.fill(0)
294+
display.print("WEIGHING")
295+
weight_readings = []
296+
# weighs the item 10 times, stores the readings in an array & averages them
297+
weight_avg = calculateCallibration(weight_readings)
298+
# calculates the new offset value
299+
callibration['offset_val'] = (weight_avg-zero_avg) / callibration['weight']
300+
display.marquee("%0.2f - CALLIBRATED " % callibration['offset_val'], 0.5, False)
301+
stage = 5
302+
display.fill(0)
303+
display.print("DONE")
304+
blue.value = True
305+
# final stage
306+
if (not blue_btn.value and not blue_btn_pressed) and stage == 5:
307+
blue_btn_pressed = True
308+
callibrate_mode = False
309+
blue.value = False
310+
# goes back into weighing mode
311+
show_oz = True
312+
run_mode = True
313+
# resets stage
314+
stage = 0

0 commit comments

Comments
 (0)