This post is to demonstate how to bring a py file into a script.sh file (as a python script library) in order to use the one library command (
dsp8_STD(value) ) to create various display patterns (in this case) or for any other output that might be desired from an 8bit digital LED panel; from art to a temperature readout, to boot-up codes, to robotics status registers, &c.
The codes listed below are based on the codes posted previously in this thread; however, they have been modified and generalized to be useful in a variety of situations, as examples for coding and as boiler-plates for modified projects that you might imagine. They are designed to be studied and played around with, as well to have some fun.
display8bit.py
This is the library file imported by the dsp_patterns.sh driver code. It contains the headers, imports, function definitions, and most importantly our interface function
dsp8_STD(value). This code should be in your PYTHONPATH, or in your working directory.
dsp_patterns.sh
This code is the driver code that displays several interesting 8bit patterns which imply motion. They are selectable via interrupt signals and run at various speeds selectable via SIGHUP. Whether you use my board or not, all that is required is that you have 8 LEDs hanging off of 8 GPIO lines (I'm using GPIO 20-27 high-order to low-order) and that whatever lines you choose -- they must be defined in display8bit.py. These codes run fine with the Gertboard, for instance (and you have lots of LEDs to choose from there!) although the patterns are designed to run on two parallel rows of four LEDs each for affect.
Adding patterns to this code is easy; the code is readable and the boiler plate ideology is easily expanded. The same techniques could be used to control multiple relays, motors, art-boards, &c; its an imagination thing. To run:
Code: Select all
sudo /home/pi/bin/dsp_patterns.sh &
ssendsig.sh
This script is a universal signal sender... it can send a signal to any process by name; you don't need to know the process number, it figures that out. The signals which may be sent are SIGINT, SIGHUP, SIGUSR1, and SIGUSR2. To run:
Code: Select all
sudo /home/pi/bin/ssendsig.sh dsp_pattern SIGHUP
Signals:
SIGINT Terminates the process, which is running in the background
SIGHUP Displays process status, and toggles frequency t_delay values
SIGUSR1 Selects the next indexed display pattern (forward)
SIGUSR2 Selects the previous indexed display pattern (reverse)

- ... this pattern #2 was running with 23ms between frames and the g6 stopped the motion ...
- pattern_two.jpg (54.04 KiB) Viewed 2553 times
While the display process is running the speed of any of the displays and the display itself are selectable via signal handler. The order of the displays is determined by an indexed array (python list) so that rearranging the pattern number in led_pattern_index[] will change the order selectable via SIGUSRx. The displays run at five different speeds, which are toggled forward by SIGHUP. The HUP signal also causes the process to send its cycle number, current t_delay, and present running display.
The pic above shows pattern #2 (the four LEDs 'move' as a unit left and right at whatever speed you choose). I included the pic because I was surprised by the stop motion of my Samsung g6; I had the pattern oscillating with only 23ms between sleep frames (looked like pwm running, a slight flicker) and the camera stopped the motion completely. I guess I expected a blur, or to catch some of the LEDs lit partially.
Should you decide to play with these codes, I will answer questions. Just post here, or PM me... no problema. But, while I trust that someone will find them useful, no promise is made for fitness of purpose or warranty of any kind.
display8bit.py
Code: Select all
## display8bit.py
#
# Mark H. Harris
# v.01h
# 06-10-2016
# Rochester, MN
#
#
## IMPORTS
from time import sleep
from sys import argv
import RPi.GPIO as GPIO
## ALL GPIO use Broadcom Numbering
GPIO.setmode(GPIO.BCM)
## PUSH BUTTON SWITCH DEFINED HERE, BUT NOT ALWAYS USED
p_switch = 19
GPIO.setup(p_switch, GPIO.IN, pull_up_down=GPIO.PUD_UP)
## BINARY ROMS
red_pins=[23, 22, 21, 20]
for pin in red_pins:
GPIO.setup(pin, GPIO.OUT)
green_pins=[27, 26, 25, 24]
for pin in green_pins:
GPIO.setup(pin, GPIO.OUT)
## FUNCTION DEFINITIONS
def push_button():
if GPIO.input(p_switch):
return False
else:
return True
def led_on(pin):
GPIO.output(pin, True)
def led_off(pin):
GPIO.output(pin, False)
def bin_display(val, led_rom, nibble, std_inv):
bin_digit = nibble
if (std_inv=="STD"):
start=0; finish=4; incrmt=1
else:
start=3; finish=-1; incrmt=-1
for n in range(start, finish, incrmt):
if (val & bin_digit):
led_on(led_rom[n])
else:
led_off(led_rom[n])
bin_digit = bin_digit<<(1)
def dsp8_STD(val):
bin_display(val, red_pins, 0x10, "STD")
bin_display(val, green_pins, 0x1, "STD")
def dsp8_INV(val):
bin_display(val, green_pins, 0x10, "INV")
bin_display(val, red_pins, 0x1, "INV")
def counter_8bit(max, t_delay, std_inv):
for n in range(max):
if (std_inv=="STD"):
dsp8_STD(n)
else:
dsp8_INV(n)
sleep(t_delay)
def counter_4bit(max, led_rom, t_delay, std_inv):
for n in range(max):
bin_display(n, led_rom, 0x1, std_inv)
sleep(t_delay)
def walking(cycles, t_delay, std_inv):
for m in range(cycles):
digit=0x1
for n in range(9):
if (std_inv=="STD"):
dsp8_STD(digit)
else:
dsp8_INV(digit)
sleep(t_delay)
digit = digit << (1)
def all_off():
dsp8_INV(0x0)
def all_on():
dsp8_INV(0xff)
def end():
GPIO.cleanup()
quit()
dsp_patterns.sh
Code: Select all
#!/usr/bin/python
# dsp_patterns.sh
#
# Mark H. Harris
# v.01h
# 06-10-2016
# Rochester, MN
#
## REQUIRES v.10h display8bit.py
import display8bit as DSP
import signal as SIG
## RUN CYCLE COUNTER DISPLAYED WITH HUP SIGNAL
cycle = 0
## EXIT FLAG FROM SIGINT INTERRUPT HANDLER
interrupt_flag = False
## DISPLAY ORDER OF PATTERNS USED BY SIGUSR1 AND SIGUSR2
led_pattern_index=[2, 12, 1, 4, 3, 9, 11, 5, 7, 6, 8, 0, 10]
## BEGINNING DISPLAY PATTERN (IN THIS EXAMPLE 1)
# led_pattern_index numbered from 0
# pattern_index = 2
# led_pattern_index[2] = 1 (see index above)
pattern_index=2
pattern_num = led_pattern_index[pattern_index]
## FREQUENCY SETTINGS (DELAYS) SET BY HUP
tt_delay_val=[0.023, 0.077, 0.140, 0.258, 0.70]
tt_delay_index=2
tt_delay=tt_delay_val[tt_delay_index]
## DISPLAY LED PATTERN ROMS
circular2R = [0x88, 0xc0, 0x60, 0x30, 0x11, 0x03, 0x06, 0x0c]
dual_walker= [0x81, 0x42, 0x24, 0x18, 0x24, 0x42]
side_side_steps = [0x08, 0x40, 0x02, 0x10, 0x01, 0x20, 0x04, 0x80]
figure_eight = [0x80, 0x40, 0x02, 0x01, 0x10, 0x20, 0x04, 0x08]
two_led_wave = [0x88, 0x44, 0x22, 0x11, 0x22, 0x44]
all_leds_on_flasher = [0xff, 0x00]
green_red_bars_flasher = [0xf0, 0x0f]
alternating_flasher = [0x69, 0x96]
curtain_scanner = [0xf, 0x8f, 0xc7, 0xe3, 0xf1, 0xf0, 0xf1, 0xe3, 0xc7, 0x8f]
## SIGUSR2 HANDLER FOR SELECTING PREVIOUS DISPLAY INDEX
def ssigusr2(signum, frame):
global pattern_num
global pattern_index
if (pattern_index>0):
pattern_index-=1
else:
pattern_index=len(led_pattern_index)-1
pattern_num=led_pattern_index[pattern_index]
print("\n USR1: swapping backward to previous pattern: "+str(pattern_num)+"\n")
## SIGUSR1 HANDLER FOR SELECTING NEXT DISPLAY INDEX
def ssigusr1(signum, frame):
global pattern_num
global pattern_index
if (pattern_index<len(led_pattern_index)-1):
pattern_index+=1
else:
pattern_index=0
pattern_num=led_pattern_index[pattern_index]
print("\n USR1: swapping forward to next pattern: "+str(pattern_num)+"\n")
## SIGHUP HANDLER FOR DISPLAYING INFORMATION AND ROTATING DELAY INDEX
def ssighup(signum, frame):
global tt_delay
global tt_delay_index
tt_delay_top = len(tt_delay_val)-1
if (tt_delay_index<tt_delay_top):
tt_delay_index+=1
else:
tt_delay_index=0
tt_delay=tt_delay_val[tt_delay_index]
print("\n cycle: "+str(cycle))
print("\n delay: "+str(tt_delay))
print("\n HUP: presently displaying pattern: "+str(pattern_num)+"\n")
## SIGINT HANDLER FOR EXITING THE DISPLAY PROCESS
def ssigint(signum, frame):
global interrupt_flag
print("\n keyboard interrupt"+"\n")
interrupt_flag = True
## SIGNAL TRAPS
SIG.signal(SIG.SIGINT, ssigint)
SIG.signal(SIG.SIGHUP, ssighup)
SIG.signal(SIG.SIGUSR1, ssigusr1)
SIG.signal(SIG.SIGUSR2, ssigusr2)
## DISPLAY FUNCTION FOR READING AND RESOLVING DISPLAY ROMS INFORMATION
def displayf(pattern, fwd_rvs):
p_pattern=[]
if (fwd_rvs=="RVS"):
for n in range(len(pattern)-1, -1, -1):
p_pattern.append(pattern[n])
else:
p_pattern=pattern
for p_code in p_pattern:
DSP.dsp8_STD(p_code)
DSP.sleep(tt_delay)
## MAIN TRY BLOCK FOR THE DISPLAY PROCESS
while (not interrupt_flag):
try:
if (pattern_num==0):
## 0 FLASHING BARS OF GREEN AND RED
displayf(green_red_bars_flasher, "FWD")
if (pattern_num==1):
## 1 DUAL WALKING PATTERN SIMPLE
displayf(dual_walker, "FWD")
if (pattern_num==2):
## 2x2 ALTERNATE FLASHING PATTERN SIMPLE
DSP.dsp8_STD(0xcc)
DSP.sleep(tt_delay)
DSP.dsp8_STD(0x33)
DSP.sleep(tt_delay)
if (pattern_num==3):
## 3 SINGLE RAPID WALKER FROM DSP
DSP.walking(1, tt_delay, "STD")
DSP.sleep(tt_delay)
DSP.walking(1, tt_delay, "INV")
DSP.sleep(tt_delay)
if (pattern_num==4):
## 4 STEPS BACK-AND-FORTH LEFT-AND-RIGHT
displayf(side_side_steps, "FWD")
DSP.dsp8_STD(0x0)
DSP.sleep(tt_delay)
displayf(side_side_steps, "RVS")
DSP.dsp8_STD(0x0)
DSP.sleep(tt_delay)
if (pattern_num==5):
## 5 CLOCK-WISE 2-LED CIRCULAR WALKING D-RIGHT
displayf(circular2R, "FWD")
if (pattern_num==6):
## 6 COUNTER CLOCK-WISE 2-LED CIRCULAR WALKING D-LEFT
displayf(circular2R, "RVS")
if (pattern_num==7):
## 7 FIGURE EIGHT X1 WALKING
displayf(figure_eight, "FWD")
if (pattern_num==8):
## 8 FIGURE EIGHT X1 WALKING
displayf(figure_eight, "RVS")
if (pattern_num==9):
## 9 TWO LED WAVE DISPLAY
displayf(two_led_wave, "FWD")
if (pattern_num==10):
## 10 ALL LEDS ON FLASHER !
displayf(all_leds_on_flasher, "FWD")
if (pattern_num==11):
## 11 ALTERNATING PATTERN INTERESTING
displayf(alternating_flasher, "FWD")
if (pattern_num==12):
## 12 ALTERNATING PATTERN INTERESTING
displayf(curtain_scanner, "FWD")
finally:
if interrupt_flag:
break
cycle+=1
# print("cycle: "+str(cycle)+"\n") DSP.all_off()
DSP.GPIO.cleanup()
ssendsig.sh
Code: Select all
#!/bin/bash
echo
PWMPID=$(ps ax |grep -i $1 |grep -v grep |grep -v sudo |grep -v ssendsig |awk '{print $1}' )
echo "PID: $PWMPID"
if [ "$PWMPID" != "" ]
then
if [[ "$2" != "HUP" && "$2" != "INT" && "$2" != "USR1" && "$2" != "USR2" ]]
then
echo "Error: valid signals are HUP INT USR1 USR2"
else
exec kill -SIG$2 $PWMPID
fi
else
echo "PWM_counter.sh does not appear to be running"
fi
marcus