Halloween candy vending machine
Software
The preconfigured Python image from the PiXtend website [6] lets you start programming as quickly as possible. Make sure the image matches the PiXtend model you use. To do so, search for the PiXtend Python Library heading on the page for the respective device.
Once you have downloaded the image and written it to an SD card, the PiXtend Python Library (PPL) is available directly. You only need to install the library to control the WS2812 LEDs. These steps are summarized in the first eight lines of Listing 1. To test whether the library installation was successful, run the strandtest.py
program (lines 9 and 10).
Listing 1
Installing PPL
01 $ cd ~ 02 $ sudo apt update 03 $ sudo apt upgrade 04 $ sudo apt install build-essential python-dev python-pip unzip wget scons swig 05 $ wget https://github.com/jgarff/rpi_ws281x/archive/master.zip unzip master.zip 06 $ cd rpi_ws281x-master 07 $ sudo scons 08 $ sudo pip install rpi_ws281x 09 $ cd ~/rpi_ws281x-master/python 10 $ sudo PYTHONPATH=".:build/lib.linux-armv7l-2.7" python examples/strandtest.py
In the source code, you can configure different settings for the LEDs, including the LED_BRIGHTNESS
parameter for the brightness of the diodes. You will want to choose a value that is as low as possible, because the LEDs consume a lot of current at full light intensity, and they also heat up.
Control
The ws.py
program (Listing 2) [7] controls the eyes and mouth. At the start of the program you will find the TRANSLATE
table that enables linear access to the individual LEDs. As mentioned earlier, the way the LEDs are installed on the panels is a little strange.
Listing 2
ws.py
01 import time 02 from neopixel import * 03 import argparse 04 05 LED_COUNT = 384 06 LED_PIN = 12 07 LED_FREQ_HZ = 800000 08 LED_DMA = 10 09 LED_BRIGHTNESS = 16 10 LED_INVERT = False 11 LED_CHANNEL = 0 12 13 TRANSLATE = [0, 15, 16, 31, 32, 47, 48, 63, 64, 79, 80, 95, 96, 111, 112, 127, 128, 143, 144, 159, 160, 175, 176, 191, 192, 207, 208, 223, 224, 239, 240, 255, 256, 271, 272, 287, 288, 303, 304, 319, 320, 335, 336, 351, 352, 367, 368, 383, 1, 14, 17, 30, 33, 46, 49, 62, 65, 78, 81, 94, 97, 110, 113, 126, 129, 142, 145, 158, 161, 174, 177, 190, 193, 206, 209, 222, 225, 238, 241, 254, 257, 270, 273, 286, 289, 302, 305, 318, 321, 334, 337, 350, 353, 366, 369, 382, 2, 13, 18, 29, 34, 45, 50, 61, 66, 77, 82, 93, 98, 109, 114, 125, 130, 141, 146, 157, 162, 173, 178, 189, 194, 205, 210, 221, 226, 237, 242, 253, 258, 269, 274, 285, 290, 301, 306, 317, 322, 333, 338, 349, 354, 365, 370, 381, 3, 12, 19, 28, 35, 44, 51, 60, 67, 76, 83, 92, 99, 108, 115, 124, 131, 140, 147, 156, 163, 172, 179, 188, 195, 204, 211, 220, 227, 236, 243, 252, 259, 268, 275, 284, 291, 300, 307, 316, 323, 332, 339, 348, 355, 364, 371, 380, 4, 11, 20, 27, 36, 43, 52, 59, 68, 75, 84, 91, 100, 107, 116, 123, 132, 139, 148, 155, 164, 171, 180, 187, 196, 203, 212, 219, 228, 235, 244, 251, 260, 267, 276, 283, 292, 299, 308, 315, 324, 331, 340, 347, 356, 363, 372, 379, 5, 10, 21, 26, 37, 42, 53, 58, 69, 74, 85, 90, 101, 106, 117, 122, 133, 138, 149, 154, 165, 170, 181, 186, 197, 202, 213, 218, 229, 234, 245, 250, 261, 266, 277, 282, 293, 298, 309, 314, 325, 330, 341, 346, 357, 362, 373, 378, 6, 9, 22, 25, 38, 41, 54, 57, 70, 73, 86, 89, 102, 105, 118, 121, 134, 137, 150, 153, 166, 169, 182, 185, 198, 201, 214, 217, 230, 233, 246, 249, 262, 265, 278, 281, 294, 297, 310, 313, 326, 329, 342, 345, 358, 361, 374, 377, 7, 8, 23, 24, 39, 40, 55, 56, 71, 72, 87, 88, 103, 104, 119, 120, 135, 136, 151, 152, 167, 168, 183, 184, 199, 200, 215, 216, 231, 232, 247, 248, 263, 264, 279, 280, 295, 296, 311, 312, 327, 328, 343, 344, 359, 360, 375, 376] 14 15 strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL) 16 strip.begin() 17 18 f = open("data.bin","rt") 19 data=f.readlines() 20 bitcounter=0 21 image=2 22 for line in data: 23 if len(line)<3: 24 bitcounter=0 25 image=image+1 26 strip.show() 27 time.sleep(0.1) 28 if not(line.find("#")): 29 continue 30 bits = line.split(" ") 31 for bit in bits: 32 bit=bit.strip() 33 if len(bit) > 0: 34 if bit=='1': 35 strip.setPixelColor(TRANSLATE[bitcounter], Color(0,255,0)) 36 else: 37 strip.setPixelColor(TRANSLATE[bitcounter], Color(0,0,0)) 38 bitcounter=bitcounter+1 39 f.close
The information as to which LED is switched is provided in the data.bin
file; Listing 3 shows an excerpt. Bit patterns control the LEDs. You can store any number of patterns for ws.py
to send to the LEDs in sequence. It parses the file line-by-line and converts the data to commands for the LEDs. An empty line initiates a new bit pattern; the program skips comment lines that start with a hash symbol (#).
Listing 3
data.bin (Excerpt)
# 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 # 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0
Program
The control program (Listing 4) continuously queries the PiXtend's inputs and starts the conveyor belts alternately when the light barrier is triggered. In parallel to starting the belts, it calls two additional programs: One controls the LEDs, and the other plays back the matching creepy sound. If the play
command doesn't work as intended, you can try connecting and configuring an external sound card to the Rasp Pi. Figure 4 shows the eyes and mouth. To see the whole setup working, check out my YouTube video [8].
Listing 4
halloween.py
01 #!/usr/bin/env python 02 # coding=utf-8 03 04 from __future__ import print_function 05 # Import Pixtend class 06 from pixtendlib import Pixtend 07 import time 08 import sys 09 import threading 10 import os, platform 11 12 p = Pixtend() 13 14 # Open SPI bus for communication 15 try: 16 p.open() 17 except IOError as io_err: 18 # Print error text and delete PiXtend instance 19 print("Error opening the SPI bus! Error is: ", io_err) 20 p.close() 21 p = None 22 23 def thread_sound(): 24 os.system("play gost.wav") 25 26 def thread_animation(): 27 os.system("sudo python ws.py") 28 29 # ----------------------------------------------------- 30 # Main Program 31 # ----------------------------------------------------- 32 if p is not None: 33 print("Running Main Program - Hit Ctrl + C to exit") 34 # Set some variables needed in the main loop 35 is_config = False 36 switch = True 37 pressed = False 38 while True: 39 try: 40 # Using Auto Mode for optimal SPI bus usage 41 if p.auto_mode() == 0: 42 if not is_config: 43 is_config = True 44 # Space for setup 45 print (p.digital_input0,":",p.digital_input1) 46 if p.digital_input2 == p.ON and pressed==False: 47 pressed=True; 48 x = threading.Thread(target=thread_sound) 49 x.start() 50 y = threading.Thread(target=thread_animation) 51 y.start() 52 if switch: p.digital_output0 = p.ON 53 else : p.digital_output1 = p.ON 54 switch=not(switch) 55 if p.digital_output0 == p.ON and di0_old == 0 and p.digital_input0 == p.ON: 56 p.digital_output0 = p.OFF 57 pressed=False 58 if p.digital_output1 == p.ON and di1_old == 0 and p.digital_input1 == p.ON: 59 p.digital_output1 = p.OFF 60 pressed=False 61 di0_old = p.digital_input0 62 di1_old = p.digital_input1 63 else: 64 print("Auto Mode - Communication is not yet up...Please wait...") 65 # Wait at minimum 0.1sec or 100ms before getting new values 66 time.sleep(0.1) 67 except KeyboardInterrupt: 68 # Keyboard interrupt caught, Ctrl + C, now clean up and leave program 69 p.close() 70 p = None 71 break 72 else: 73 # If there was an error when opening the SPI bus interface, leave the program. 74 print("") 75 print("There was a problem with the PiXtend communication. Quitting.") 76 print("")
« Previous 1 2 3 Next »
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Direct Download
Read full article as PDF:
Price $2.95
News
-
KaOS 2022.06 Now Available With KDE Plasma 5.25
The newest iteration of KaOS Linux not only adds the latest KDE Plasma desktop but sets LibreOffice as the default.
-
Manjaro 21.3.0 Is Now Available
Manjaro “Ruah” has been released and includes the latest Calamares installer, GNOME 42, and much more.
-
SpiralLinux is a New Linux Distribution Focused on Simplicity
A new Linux distribution, from the creator of GeckoLinux, is a Debian-based operating system with a focus on simplicity and ease of use.
-
HP Dev One Linux Laptop is Now Available for Pre-Order
The System76/HP collaboration Dev One laptop, geared toward developers, is now available for pre-order.
-
NixOS 22.5 Is Now Available
The latest release of NixOS with a much-improved package manager and a user-friendly graphical installer.
-
System76 Teams up with HP to Create the Dev One Laptop
HP and System76 have come together to develop a new laptop, powered by Pop!_OS and aimed toward developers.
-
Titan Linux is a New KDE Linux Based on Debian Stable
Titan Linux is a new Debian-based Linux distribution that features the KDE Plasma desktop with a focus on usability and performance.
-
Danielle Foré Has an Update for elementary OS 7
Now that Ubuntu 22.04 has been released, the team behind elementary OS is preparing for the upcoming 7.0 release.
-
Linux New Media Launches Open Source JobHub
New job website focuses on connecting technical and non-technical professionals with organizations in open source.
-
Ubuntu Cinnamon 22.04 Now Available
Ubuntu Cinnamon 22.04 has been released with all the additions from upstream as well as other features and improvements.