fliff
Posts: 4
Joined: Wed Feb 26, 2014 12:39 pm

Threading, LEDs

Wed Feb 26, 2014 12:58 pm

Hello everyone!

I've built a LED Matrix (14x9) out of LPD8806 LED Stripes and i want it to display an animation and simultanously i want one "LEDpixel" which i can move by Keyboard Inputs. By now it's kinda working.
Both threads are running and doing what i expect them to do, except: the LEDpixel i want to move by Keyboard only lights up at the moment of Input then goes off again until the next input.
The getInput function actually does work like that, when run on its own. I can't see why it doesn't in this case.
Also: How can i end both threads while the program is running? So far it only ends the getInput function by pressing "q". The ledAction function keeps on spinning and Ctrl-C isnt quitting it.

I'm quite new to Python (and to programming anyway), so any help would be very appreciated.
Let me know if there's something unclear.
Thanks, f.


Here's the Code:

Code: Select all

from raspledstrip.ledstrip import *
import time
import threading
from threading import Thread

led = LEDStrip(126)

class _Getch:
    """Gets a single character from standard input.  Does not echo to the screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            try:
                self.impl = _GetchUnix()
            except ImportError:
                self.impl = _GetchMacCarbon()

    def __call__(self): return self.impl()


class _GetchUnix:
    def __init__(self):
        import tty, sys, termios # import termios now or else you'll get the Unix version on the Mac

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()


class _GetchMacCarbon:
    """
    A function which returns the current ASCII key that is down;
    if no ASCII key is down, the null string is returned.  The
    page http://www.mactech.com/macintosh-c/chap02-1.html was
    very helpful in figuring out how to do this.
    """
    def __init__(self):
        import Carbon
        Carbon.Evt #see if it has this (in Unix, it doesn't)

    def __call__(self):
        import Carbon
        if Carbon.Evt.EventAvail(0x0008)[0]==0: # 0x0008 is the keyDownMask
            return ''
        else:
            #
            # The event contains the following info:
            # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
            #
            # The message (msg) contains the ASCII char which is
            # extracted with the 0x000000FF charCodeMask; this
            # number is converted to an ASCII character with chr() and
            # returned
            #
            (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
            return chr(msg & 0x000000FF)

def getInput():	
	
	pixel0 = 120
	direction = 0;
	
	while True:
		
	   led.fillRGB(0,0,0)  
	   led.setRGB(pixel0, 255,248,17)
	   pixel0 = pixel0 + direction
	   led.update()
	   #time.sleep(0.01)
	   
           
           
	   print 'Press a key'
	   inkey = _Getch()
	   import sys
	   for i in xrange(sys.maxint):
		  k=inkey()
		  if k<>'':break
	   print 'you pressed ',k
	   if k == 'w':
	      direction = -14
	   if k == 's':
	      direction = 14
	   if k == 'a':
	      direction = -1
	   if k == 'd':
	      direction = 1
	   print direction
	   if k == 'q':
	      break

	   pixel0 = pixel0 + direction
	   print pixel0
	   led.update()

def ledAction():
	pixel0 = 120
	pixel1 = 1
	counter1 = 1
	while True:
	   led.fillRGB(0,0,0)   
	  

 #stripe 1
	
	   if pixel1 < 1 or pixel1 > 12:
		counter1 = counter1 * -1
		
	   led.setRGB(pixel1, 55,48,117)
	   #led.update()
	   #time.sleep(0.01)
	   pixel1 = pixel1 + counter1

           led.update()
           time.sleep(0.02)
           
if __name__== '__main__':
	Thread(target = getInput).start()
	Thread(target = ledAction).start()	
	  
###

User avatar
paddyg
Posts: 2555
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Threading, LEDs

Wed Feb 26, 2014 2:46 pm

@fliff, I've not tried too hard to figure out exactly what you're trying to do but these comments might be helpful:
all that stuff at the beginning looks awfully complicated to just get a character! Unless you really need to run on all the different operating systems you could just use curses getch()
both threads are calling led function but you don't know the timings of them.
you can set threads that are killable by setting thread.daemon = True (or some version of that syntax)
I wouldn't use threads here at all but put it in one loop so I could see what was happing. Something like this

Code: Select all

from raspledstrip.ledstrip import *
import time
import curses

led = LEDStrip(126)

damn = curses.initscr()
damn.nodelay(1) # doesn't keep waiting for a key press

pixel0 = 120
pixel1 = 1
direction = 0
counter1 = 1

while True:
  k = damn.getkey()
  if k == 'w':
    direction = -14
  elif k == 's':
    direction = 14
  elif k == 'a':
    direction = -1
  elif k == 'd':
    direction = 1
  elif k == 'q':
    break

  pixel0 = pixel0 + direction
  led.fillRGB(0, 0, 0) 
  led.setRGB(pixel0, 255, 248, 17)

  if pixel1 < 1 or pixel1 > 12:
    counter1 = counter1 * -1
  pixel1 = pixel1 + counter1
    
  led.setRGB(pixel1, 55, 48, 117)

  led.update()
  time.sleep(0.02)
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

fliff
Posts: 4
Joined: Wed Feb 26, 2014 12:39 pm

Re: Threading, LEDs

Wed Feb 26, 2014 5:46 pm

hey paddy
thanks for your answer. i probably have to read deeper into curses, as the code still isn't doing what i expect it to do.
but i think i might have found a solution to my original problem. i'll sure give it a try.

what do you mean by "both threads are calling led function but you don't know the timings of them." Aren't they both running simultanously? What's the timing of the threads and how is this important?
an answer on that would be very appreciated.

thanks, f.

User avatar
paddyg
Posts: 2555
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Threading, LEDs

Wed Feb 26, 2014 5:58 pm

Well you have led.fillRGB(0,0,0) being called in both thread loops so whichever thread sends its instructions first will be switched off by the other thread setting everything back to 0,0,0

Threads are sometimes essential but generally you can do what you want in a while loop. The RPi only has one processor so all the multitasking is really being done in series anyway! i.e. so No they are not actually running simultaneously they are swapping in and out of action behind the scenes.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

Return to “Python”