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
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
News
-
KDE Plasma 6 Looks to Bring Basic HDR Support
The KWin piece of KDE Plasma now has HDR support and color management geared for the 6.0 release.
-
Bodhi Linux 7.0 Beta Ready for Testing
The latest iteration of the Bohdi Linux distribution is now available for those who want to experience what's in store and for testing purposes.
-
Changes Coming to Ubuntu PPA Usage
The way you manage Personal Package Archives will be changing with the release of Ubuntu 23.10.
-
AlmaLinux 9.2 Now Available for Download
AlmaLinux has been released and provides a free alternative to upstream Red Hat Enterprise Linux.
-
An Immutable Version of Fedora Is Under Consideration
For anyone who's a fan of using immutable versions of Linux, the Fedora team is currently considering adding a new spin called Fedora Onyx.
-
New Release of Br OS Includes ChatGPT Integration
Br OS 23.04 is now available and is geared specifically toward web content creation.
-
Command-Line Only Peropesis 2.1 Available Now
The latest iteration of Peropesis has been released with plenty of updates and introduces new software development tools.
-
TUXEDO Computers Announces InfinityBook Pro 14
With the new generation of their popular InfinityBook Pro 14, TUXEDO upgrades its ultra-mobile, powerful business laptop with some impressive specs.
-
Linux Kernel 6.3 Release Includes Interesting Features
Although it's not a Long Term Release candidate, Linux 6.3 includes features that will benefit end users.
-
Arch-Based blendOS Features Cool Trick
If you're looking for a Linux distribution that blends Linux, Android, and web apps together, blendOS might be what you're looking for.