Hi guys, for this blog I managed to connect the whole project to the real world a bit. I added LED indicators, a buzzer, connected the program to work with files which will store all of the data and more excitingly I finally got the load cell up and running First off lets start with the LED-s and the buzzer. They are a necessity to the project, there is no other way for the user to know if the device recognized and logged everything correctly without giving him some sort of a signal. I went with both sound and visual signals. As mentioned before for the light signal i went with LED-s more specifically a red and green LED, where red LED of course signalizes that the either label read or something other was not done successfully, while the green one flashes when everything goes as it should. Similarly i programmed two different sounds for the buzzer depending on the success of the program. All of this means that I had to control the GPIO pins, so here is the start of all of that. First we have to initialize the RPi.GPIO library and set the pinmode.(Also one thing worth mentioning is that I am using the time library for all of the sequences)
import RPi.GPIO as GPIO GPIO.setmode(BCM)
The setmode function sets the numbering scheme for the Raspberry. There are two possibilities, BOARD and BCM (just want to note that in the final code there isn't setmode because of the hx711 library in which the mode is already set to BCM). The next thing is setting up the pins themselves. This means telling Raspberry whether the pins are supposed to be output, input and we can also set the initial state of a pin, this next part of code sets the pins up.
buzzerPin = 21 redledPin = 26 greenledPin = 20 GPIO.setup(buzzerPin, GPIO.OUT, initial = GPIO.LOW) GPIO.setup(redledPin, GPIO.OUT, initial = GPIO.LOW) GPIO.setup(greenledPin, GPIO.OUT, initial = GPIO.LOW)
That would be that for the setup of the pins, pretty plain and simple. The next thing of course is programming the sequences at which these go. For the "error" part I went with a long beep and long red light, while for the "everything went well" I went with a fast green flash as well as a fast double beep on the buzzer. In the next part of the code I will show the sequences I used, just want to point out first that i placed the sequences at places like, for example everything went well the label and mass were correctly detected so it goes green. This first sequence is the everything went smoothly sequence:
GPIO.output(buzzerPin, GPIO.HIGH) GPIO.output(greenledPin, GPIO.HIGH) time.sleep(0.2) GPIO.output(buzzerPin, GPIO.LOW) GPIO.output(greenledPin, GPIO.LOW) time.sleep(0.1) GPIO.output(buzzerPin, GPIO.HIGH) GPIO.output(greenledPin, GPIO.HIGH) time.sleep(0.2) GPIO.output(buzzerPin, GPIO.LOW) GPIO.output(greenledPin, GPIO.LOW)
That would be it for that sequence, now this next code will show the sequence when something goes wrong:
GPIO.output(buzzerPin, GPIO.HIGH) GPIO.output(redledPin, GPIO.HIGH) time.sleep(0.5) GPIO.output(buzzerPin, GPIO.LOW) GPIO.output(redledPin, GPIO.LOW)
And there is one more thing to this story and that is that at the end of the program it is good practice to always have this line of code:
GPIO.cleanup()
This command clears out all of the pins that were used during the program. I will post the audio tracks as attachments to this blog. To edit any of the sequences the easiest thing to do is of course just edit the time.sleep to the desired values. For the next part I will show my solution to storing data on the Raspberry, it is not the prettiest nor the best one, but it is pretty simple and does the job just fine. For now there are two files that store data on the Raspberry, I use them to store data on the labels which I talked about in the last blog (S.H.E.L.F. - Labels - Pi Chef Design Challenge - Blog post #6 ). I need to store the label codes as well as the names of the labels. Later on I will have to also store mass and other information on items but for now these two are the ones I am using. The method works by keeping the two files "synced". Each of the files contain one piece of data per line so it's easier to read. By synced data I mean to say that the for example on the third line of the code value file these is some value xx that corresponds to Item-78, in the other file the name of the Item-78 must be on the third line as well. This next piece of code will show the loading of the files into two separate arrays:
v = open('stickervalues.txt', 'r') n = open('stickernames.txt', 'r') i = 0 j = 0 a = [] b = [] while True: c = v.readline() if not c: break a.insert(i,c) i=i+1 while True: c=n.readline() if not c: break b.insert(j,c) j=j+1 i=i-1 j=j-1
First with the open function we open the files that we want to read from and set them to read with 'r', and then in the while loop we save line by line into a variable c and then into the array until readline reaches the end, when break kicks in and we go out of the loop. Now the next part will show what happens when we read the label. When trying to read the label we get a value based on the number of small circles, now to find the name of that item we have to go and search the array with values, until we find the value that matches the one we got from reading the label, or report and error, that either the label was read badly, or that it is maybe a new label that is not in the files yet. Either way this is the code i use to extract that information:
m = 101 q = 0 while True: if q<=i if int(a[q]) == d m = q break else: q = q + 1 else: break if m!=101: print(b[m]) #this is the place for the everything went good sequence else: print('Either error or new sticker') #this is the place where the error sequence goes
The odd value of 101 for the variable m is just a marker, it can be any value that isn't in the labels pretty much, it just shows me if the value of m has changed in other words, it shows me if a match was found in the files. We just go one through one in the while loop until we find the match, The variable d is the value we got from the reading the label. That would be it for that part, tried keeping it as simple as possible, will I stick with this method or change it up to a single file system I will see further down the line, but will keep it like this for now. The next and the most exciting part for me is the load cell sensor. I've gotten this sensor a long time ago when the design challenge started but didn't get the amplifier at the time. This week I finally got to ordering and getting the amplifier so here is what I did. For the amplifier i went with a dual channel hx711. I got one channel going and working great for now, didn't try getting the other one up and running yet which will pretty much be a necessity for the future of the project. The load cell work by measuring strain, which produces minuscule changes for which an amplifier is needed. This is how the load cell, hx711 and Raspberry are connected.
Firs the wire from the sensors to the hx711:
- The red wire goes to E+
- The black wire goes to E-
- The white wire goes to A+
- The green wire goes to A-
Now for the wires from hx711 to the Raspberry:
- VCC goes to the 5V pin on the Raspberry - pin number 2 for example
- GND goes to the ground pin on the Raspberry - pin number 6 for example
- SCK pin goes to the pin number 31 on the Raspberry (GPIO pin 6)
- DT pin goes to the pin number 29 on the Raspberry (GPIO pin 5)
The pins for the SCK and DT have to be GPIO pins and they can of course be changed which will of course need the change in the software as well. Here is a picture of the setup I am currently using to test out the load cell with Raspberry:
The load cell I am using currently is rated for max weight of 10kg. I went with tatobari's hx711 library which can be found here (https://github.com/tatobari/hx711py). It's a great and simple library which can easily be modified with an example (first try) program which shows you how to calibrate the load cell itself. In this part I will show the implementation of the hx711 library. First of all i copied his library code and saved it with my program as hx711.py. This step is important because we have to import it into out program, and an errors pops up if they are not in the same directory. After that was sorted out I continued on with reading the values, which I will show in this part of the code:
from hx711 import HX711 def cleanAndExit(): print "Cleaning..." GPIO.cleanup() print "Program is finished" v.close() n.close() quit() hx = HX711(5, 6) #these are the pins being used for the hx711 in BCM mode hx.set_reading_format("LSB", "MSB") hx.set_reference_unit(-204) hx.reset() hx.tare() val = 0 val1 = 0 while True: try: val1 = val val = max(0, int(hx.get_weight(5)) hx.power_down() hx.power_up() time.sleep(0.5) if val - val1 > 5: time.sleep(1) val = hx.get_weight(5) #this is the place where the label detection goes from the last blog except(KeyboardInterupt, SystemExit): cleanAndExit()
For the preceding code first we import the library, then we set up the pins for the hx711 with hx = HX711(5, 6), these are the number 5 and 6 GPIO pins, the next important thing is the reference unit, on the link of the library in the example.py code there is a great explanation on how to do this, I will just go through some quick lines real fast. The point is to put something of a known mass on to the load cell and then diving the raw data got with the mass of the thing, and that is how we get the reference unit. Next I setup variables val and val1 where val is the current mass while the val1 is the sensor reading from last time, then I check with an if if the mass has changed by 5 grams in my case (I will probably go lower, when I test the load cell a bit more). If the difference in values is greater then we turn on the camera and try reading the label. Just want to point out this is nowhere close to the final algorithm for reading, this is just here to show that everything works together, the final program will also activate the label detection when the load cell readings change, but with a lot of tweaks. With the tests I have done for now I've found that the accuracy of the load cell is within 2 grams of an ordinary kitchen scale, which is great, here is the result I get when I try to read the mass of my phone with a picture of the label on it.
The result is in the 2 gram distance of the kitchen scale value (though I don't know how accurate the kitchen scale is honestly), also on the second picture the problem I stated in the last blog can be seen when the label is on a phone, where the backlight makes the colors too white and harder to read which should be resolved with the use of intended paper labels. I am also planning on adding a feature for easy tweaking when it comes to color detection. The next phases for this project will be uploading the data online, reading it with a phone, getting the last parts for the build of the first full prototype which are more load cells, and making all of that work together. Thanks for reading the whole blog, hope you liked it!
Milos
Top Comments