mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

RC Flying POV LED Strip

Tue Dec 22, 2015 5:09 am

I am building a project that will be mounted on an RC airplane.

Controlled with a Raspberry Pi Zero running Jessie Lite 4.1
Powered by a 2200mAh 11.1v Lipo stepped down to 5v 3a with a BEC

119 - APA102 5v Addressable RGB LEDs
360 - 3528 12v Single Color LEDs
UBLOX Neo-6M GPS
OrangeRX R615X
NTE2831 MOSFET
74AHCT125 Quad Level Shifter (3v to 5v)
2 - UBEC 5v 3a DC to DC stepdown

The objective here is to create a Persistence of Vision display with the APA102 LEDs. With the ability to control basic on/off state of the display loop by reading the PWM from the OrangeRX R615X AUX1 data pin and the on/off state of the 12v LEDS using the MOSFET and reading PWM from the OrangeRX R615X GEAR data pin.

Here is the first wiring diagram I made
Image

note that
GPS TX and RX will be changed to GPIO14 and GPI15
R615X changed to GPIO23 and GPIO24

Here is the airframe that I am putting it on.
Image
Image


The main loop for the APA102 led POV without any modification from github

Code: Select all

#!/usr/bin/python

# Persistence-of-vision (POV) example for Adafruit Dot Star RGB LED strip.
# Loads image, displays column-at-a-time on LEDs at very high speed,
# suitable for naked-eye illusions.
# See strandtest.py for a much simpler example script.
# See image-paint.py for a slightly simpler light painting example.

import Image
from dotstar import Adafruit_DotStar

filename  = "hello.png" # Image file to load

# Here's how to control the strip from any two GPIO pins:
datapin   = 23
clockpin  = 24
strip     = Adafruit_DotStar(0, datapin, clockpin)
# Notice the number of LEDs is set to 0.  This is on purpose...we're asking
# the DotStar module to NOT allocate any memory for this strip...we'll handle
# our own allocation and conversion and will feed it 'raw' data.

# So we'll write directly to the pixel data buffer.  Data is not necessarily
# in RGB order -- current DotStars use BRG order, and older ones are GBR.
# Additionally, byte 0 of each 4-byte pixel is always 0xFF, so the RGB
# offsets are always in range 1-3.
# Here's the offsets for current (2015+) strips:
rOffset = 2
gOffset = 3
bOffset = 1
# For older strips, change values to 3, 1, 2
# This is ONLY necessary because we're raw-writing; for normal setPixelColor
# use, offsets can be changed with the 'order' keyword (see strandtest.py).

strip.begin()           # Initialize pins for output

# Load image in RGB format and get dimensions:
print "Loading..."
img       = Image.open(filename).convert("RGB")
pixels    = img.load()
width     = img.size[0]
height    = img.size[1]
print "%dx%d pixels" % img.size

# Calculate gamma correction table, makes mid-range colors look 'right':
gamma = bytearray(256)
for i in range(256):
	gamma[i] = int(pow(float(i) / 255.0, 2.7) * 255.0 + 0.5)

# Allocate list of bytearrays, one for each column of image.
# Each pixel REQUIRES 4 bytes (0xFF, B, G, R).
print "Allocating..."
column = [0 for x in range(width)]
for x in range(width):
	column[x] = bytearray(height * 4)

# Convert entire RGB image into column-wise BGR bytearray list.
# The image-paint.py example proceeds in R/G/B order because it's counting
# on the library to do any necessary conversion.  Because we're preparing
# data directly for the strip, it's necessary to work in its native order.
print "Converting..."
for x in range(width):          # For each column of image...
	for y in range(height): # For each pixel in column...
		value             = pixels[x, y]    # Read pixel in image
		y4                = y * 4           # Position in raw buffer
		column[x][y4]     = 0xFF            # Pixel start marker
		column[x][y4 + rOffset] = gamma[value[0]] # Gamma-corrected R
		column[x][y4 + gOffset] = gamma[value[1]] # Gamma-corrected G
		column[x][y4 + bOffset] = gamma[value[2]] # Gamma-corrected B

print "Displaying..."
while True:                            # Loop forever

	for x in range(width):         # For each column of image...
		strip.show(column[x])  # Write raw data to strip
I plan on adding delay to the loop after strip.show that is mapped to the GPS velocity.
This will change the display speed to maintain a 1:1 image aspect ratio at any speed. (up to about 70mph)

here are some examples of what the final product might look like
Image
Image

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Tue Dec 22, 2015 8:55 am

A few questions
Does the mosfet need a resistor to prevent back feeding the rpi?

Using gpsd to read the GPIO is proving to be very difficult.
Should I just give in and connect the gps to a micro usb?

Does anyone know a good method for reading PWM? Accuracy is not extremely important as I will only be reading a two position switch and a three position switch.

User avatar
karrika
Posts: 1070
Joined: Mon Oct 19, 2015 6:21 am
Location: Finland

Re: RC Flying POV LED Strip

Tue Dec 22, 2015 9:04 am

Thumbs up. This project is so cool. :D

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Thu Dec 24, 2015 8:33 am

I have successfully hooked up the GPS to the GPIO UART pins and used gpsd to print gps data.
This was not simple and I made a separate post to troubleshoot some issues
Thread with details here
GPSD

I have successfully hooked up the OrangeRX R615X Receiver and used pigpio to print PWM data.
This was straightforward and I used the example PWM monitor with success.
pigpio
R615X AUX1 Data Pin -> rpi0 GPIO18
R615X AUX1 GND Pin -> rpi0 GND

Next I will be wiring up the quad level shifter and the mosfet to a breadboard and getting the LEDs working.

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Sat Dec 26, 2015 8:03 am

I got the MOSFET working.
It defaults to OPEN when the GATE is under 2volts.
So when nothing is connected to the gate the leds get power.
If I send a HIGH signal(5v) to a GPIO pin connected to the GATE of the MOSFET then the leds will turn off.

PWM_dutycycle.py

Code: Select all

import pigpio
pi = pigpio.pi()
pi.set_PWM_dutycycle(23, 255)
print(pi.get_PWM_dutycycle(23))

Still waiting on the 3v to 5v level shifter to come in the mail...

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Sun Dec 27, 2015 3:20 am

I have the level shifter all set up and I've run into a small issue.

broke some strips so I could fit the level shifter on the board.
Image

Top view
Image

Bottom view
Image

Running a test using a single APA102 led. (It shows green at low brightness and was removed from a larger strip of working leds. It works fine otherwise.)
Image

here is the code. Just a simple blink.

Code: Select all

import time
from dotstar import Adafruit_DotStar

numpixels = 1
strip    = Adafruit_DotStar(numpixels)
strip.begin()
strip.setBrightness(64)

while True:
    strip.setPixelColor(0, 0x00FF00)
    strip.show()
    time.sleep(1.0 / 2)

    strip.setPixelColor(0, 0x000000)
    strip.show()
    time.sleep(1.0 / 2)

Now when I try to use a battery as the power source I get very random colors.

Wiring setup
Image

same code as above. with these results.
Image


My best guess is this is a grounding issue.
Does the level shifter need to go back to the Raspberry Pi ground?

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Sun Dec 27, 2015 5:31 am

I figured it out.

I power and ground the Level shifter with the Raspberry pi 5v/GND.
The LEDS are powered by the UBEC directly.

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Sun Dec 27, 2015 7:50 am

ITS ALIVE!!!

That little red led near the start is caused by less than perfect wiring(jumpers everywhere)
and will disappear once everything is soldered in place.
https://www.youtube.com/watch?v=daHlu0P8-tQ

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Mon Dec 28, 2015 7:25 am

I laminated the wing, attached the elevons and motor.

Image

Next will be cutting out an area to put all of the electronics into.

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Tue Dec 29, 2015 7:04 am

Some sample code I made for APA102 LEDs using Adafruit Dotstar Pi and some strings from the examples in fastled3.1 library for C++ that I converted to python

First here is the most important one.
Turn everything off
off.py

Code: Select all

from dotstar import Adafruit_DotStar
numpixels = 119     #number of pixels in your strip
strip = Adafruit_DotStar(numpixels)
strip.begin()
strip.setPixelColor(numpixels, 0x000000)
strip.show()
next make pixel 0 1 and 2 blink red green and blue to check the color order is correct.
blinktest.py

Code: Select all

import time
from dotstar import Adafruit_DotStar

numpixels = 119
strip = Adafruit_DotStar(numpixels, 16000000,  order='bgr')
strip.begin()
strip.setBrightness(64)

while True:
    strip.setPixelColor(0, 0xFF0000)
    strip.setPixelColor(1, 0x00FF00)
    strip.setPixelColor(2, 0x0000FF)
    strip.show()
    time.sleep(0.1)

    strip.setPixelColor(0, 0x000000)
    strip.setPixelColor(1, 0x000000)
    strip.setPixelColor(2, 0x000000)
    strip.show()
    time.sleep(0.1)
A pulse that starts in the center of the strip and goes to each end.
Cycles through red, green, blue. Or if you uncomment a few lines cycle through random colors, or just a single color.
pulse.py

Code: Select all

import time
import random
from dotstar import Adafruit_DotStar

numpixels = 119
strip = Adafruit_DotStar(numpixels, 16000000, order='bgr')      # Use SPI (pins 10=MOSI, 11=SCLK), fix color order

strip.begin()            # Initialize pins for output
strip.setBrightness(128) # Limit brightness to

center = 59             # center of strip
step = -1               # don't change
maxsteps = 61           # center + 2
#color_r = 0             # red. for random colors
#color_g = 0             # green. for random colors
#color_b = 0             # blue. for random colors
color = 0xFF0000        # start red for red->green->blue->black cycle

while True:
    if step == -1:
#        color_r = random.randint(0,255)        #
#        color_g = random.randint(0,255)        # pick a random color
#        color_b = random.randint(0,255)        #
        step = 0
    if step == 0:
#        strip.setPixelColor(center, color_r, color_g, color_b)     #set starting pixel to the random color
#        strip.setPixelColor(center, 0, 0, 255)      #set starting pixel to blue
        strip.setPixelColor(center, color)      #set starting pixel to blue
        strip.show()
        step += 1
    if step == maxsteps:
        color >>= 8     # red->green->blue->black
        if(color == 0): color = 0xFF0000        # If black, reset to red
#        strip.setPixelColor(numpixels, 0, 0, 0)     #set all pixels to off
        strip.show()
        step = -1
    else:
#        strip.setPixelColor(((center + step + numpixels) % numpixels), color_r, color_g, color_b)      #set the next pixel to random color in the positive direction
#        strip.setPixelColor(((center - step + numpixels) % numpixels), color_r, color_g, color_b)      #set the next pixel to random color in the negative direction
#        strip.setPixelColor(((center + step + numpixels) % numpixels), 0, 0, 255)       #set the next pixel to blue in the positive direction
#        strip.setPixelColor(((center - step + numpixels) % numpixels), 0, 0, 255)       #set the next pixel to blue in the negative direction
        strip.setPixelColor(((center + step + numpixels) % numpixels), color)       #set the next pixel color in the positive direction
        strip.setPixelColor(((center - step + numpixels) % numpixels), color)       #set the next pixel to blue in the negative direction
        strip.setPixelColor((center + step - 1), 0, 0, 0)       #turn off the pixel behind the on pixel
        strip.setPixelColor((center - step + 1), 0, 0, 0)       #turn off the pixel behind the on pixel
        strip.show()
        time.sleep(0.001)
        step += 1

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Thu Jan 07, 2016 7:59 am

I finalized most of the wiring of the LEDs

I mounted the level shifter and mosfet on top of the raspberry pi zero.
Image

I tested the mosfet controlled 12v LEDS and the APA102 leds at the same time with success.
Image


Image


Image

User avatar
karrika
Posts: 1070
Joined: Mon Oct 19, 2015 6:21 am
Location: Finland

Re: RC Flying POV LED Strip

Thu Jan 07, 2016 8:32 am

Have you thought of SPI controlled LED's? Or is the Dotstar stuff the same thing?

In QLC+ (http://www.qlcplus.org) you can control LED snakes and RGB panels over SPI. LED's like ws2801.

It also has built in control of fonts and image displays.

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Thu Jan 07, 2016 8:48 am

karrika wrote:Have you thought of SPI controlled LED's? Or is the Dotstar stuff the same thing?

In QLC+ (http://www.qlcplus.org) you can control LED snakes and RGB panels over SPI. LED's like ws2801.

It also has built in control of fonts and image displays.
Yes! I am using SPI to control these LEDs.
These "APA102" LEDs don't require special timing like the ws28 series LEDs. They can be run at incredibly high speed.
I have successfully run them at 2,400 updates per second.
The pi will let me go up to 3,200 but I start getting artifacts/glitches above 2,400 on my led strip of 119 lights.

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Wed Jan 13, 2016 6:23 am

I have now installed all of the hardware into the wing.

Just a few minor adjustments before I can say it is ready for a test flight!

As far as coding goes, I have everything working the way I want.
I will have 6 different defined functions.
3 will have only the APA102 on and running some display of an image.
the other 3 will have both the 12v LEDs and the APA102 running a more simple coded pattern.

Image

Image

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Sun Jan 17, 2016 9:21 pm

I am now working on the final draft of some code that controls addressable RGB LEDs in a strip and I could use a bit of help.
I want to break out of a for loop as soon as possible "if pw1 != x or pw2 != y"
located in def toggle12() line 228
I can't get it to work. it will loop through the entire image { strip.show(pov.column[x]) } even if pw1 or pw2 changes.

If you see anything else that can be improved I would appreciate the feedback!

Here is the code. With many thanks to Phillip Burgess of Adafruit, and Joan of pigpio

Code: Select all

import time
import pigpio
from dotstar import Adafruit_DotStar
import Image
import random


PWM_GPIO_1 = 12 #PWM input gpio pins
PWM_GPIO_2 = 16
numpixels = 119 #number of pixels in the strip
strip = Adafruit_DotStar(numpixels, 24000000, order='bgr')

filename  = "test1.jpg" #file name of image to be converted

rOffset = 3	#fix RGB color order
gOffset = 2
bOffset = 1

strip.begin()
strip.setBrightness(127)

class pov:# converting an image to a byte array for sending to led strip
	print "Loading {}...".format(filename)
	img       = Image.open(filename).convert("RGB")
	pixels    = img.load()
	width     = img.size[0]
	height    = img.size[1]
	print "%dx%d pixels" % img.size
	gamma = bytearray(256)
	for i in range(256):
		gamma[i] = int(pow(float(i) / 255.0, 2.7) * 255.0 + 0.5)
	print "Allocating..."
	column = [0 for x in range(width)]
	for x in range(width):
		column[x] = bytearray(height * 4)
	print "Converting..."
	for x in range(width):          # For each column of image...
		for y in range(height): # For each pixel in column...
			value             = pixels[x, y]    # Read pixel in image
			y4                = y * 4           # Position in raw buffer
			column[x][y4]     = 0xFF            # Pixel start marker
			column[x][y4 + rOffset] = gamma[value[0]] # Gamma-corrected R
			column[x][y4 + gOffset] = gamma[value[1]] # Gamma-corrected G
			column[x][y4 + bOffset] = gamma[value[2]] # Gamma-corrected B
	print "Displaying..."


class reader:# Reads the Pulse Width signal of a gpio input and returns it's value

   def __init__(self, pi, gpio, weighting=0.0):
      self.pi = pi
      self.gpio = gpio

      if weighting < 0.0:
         weighting = 0.0
      elif weighting > 0.99:
         weighting = 0.99

      self._new = 1.0 - weighting # Weighting for new reading.
      self._old = weighting       # Weighting for old reading.

      self._high_tick = None
      self._period = None
      self._high = None

      pi.set_mode(gpio, pigpio.INPUT)

      self._cb = pi.callback(gpio, pigpio.EITHER_EDGE, self._cbf)

   def _cbf(self, gpio, level, tick):

      if level == 1:

         if self._high_tick is not None:
            t = pigpio.tickDiff(self._high_tick, tick)

            if self._period is not None:
               self._period = (self._old * self._period) + (self._new * t)
            else:
               self._period = t

         self._high_tick = tick

      elif level == 0:

         if self._high_tick is not None:
            t = pigpio.tickDiff(self._high_tick, tick)

            if self._high is not None:
               self._high = (self._old * self._high) + (self._new * t)
            else:
               self._high = t

   def pulse_width(self):       #Returns the PWM pulse width in microseconds.
      if self._high is not None:
         return ((round(self._high/100))*100) #round pwm to nerest hundred
      else:
         return 0.0

   def cancel(self):#      Cancels the reader and releases resources.
      self._cb.cancel()


def hsv2rgb(HSV):#convert HSV 255 values to RGB 255
    H, S, V = HSV
    if S == 0:
        R = V
        G = V
        B = V
        return (R, G, B)
    region = H // 43;
    remainder = (H - (region * 43)) * 6;
    P = (V * (255 - S)) >> 8;
    Q = (V * (255 - ((S * remainder) >> 8))) >> 8;
    T = (V * (255 - ((S * (255 - remainder)) >> 8))) >> 8;
    if region == 0:
        R = V
        G = T
        B = P
    elif region == 1:
        R = Q;
        G = V;
        B = P;
    elif region == 2:
        R = P;
        G = V;
        B = T;
    elif region == 3:
        R = P;
        G = Q;
        B = V;
    elif region == 4:
        R = T;
        G = P;
        B = V;
    else:
        R = V;
        G = P;
        B = Q;
    return R, G, B

"""
six toggle states.
toggle pw1(aux1) has three positions
toggle pw2(gear) has two positions
"""

def toggle31():
	if pw1 == 1900 and pw2 == 1100:
		print("toggle aux 3 pw ={}, toggle gear 1 = {}".format(int(pw1), int(pw2)))
		pi.set_PWM_dutycycle(23, 0) #set MOSFET to low -> 12v LEDs ON
		"""
		cylon,
		"""
		while True:
			i = 0
			while (i < numpixels):
				strip.setPixelColor(i, 0x0000FF)
				strip.show()
				strip.setPixelColor(i, 0x000000)
				time.sleep(0.001)
				i += 1
			i = numpixels - 1
			while (i < numpixels):
				strip.setPixelColor(i, 0xFF0000)
				strip.show()
				strip.setPixelColor(i, 0x000000)
				time.sleep(0.001)
				i -= 1
				if i <= 0:
					break
			break


def toggle21():
	if pw1 == 1500 and pw2 == 1100:
		print("toggle aux 2 pw ={}, toggle gear 1 = {}".format(int(pw1), int(pw2)))
		pi.set_PWM_dutycycle(23, 0)#set MOSFET to low -> 12v LEDs ON
		"""
		confetti
		"""
		while True:
			randompixel = random.randint(0, 119)
			randomcolor = random.randint(0, 255), 255, 255
			randomhsv = hsv2rgb(randomcolor)
			strip.setPixelColor((randompixel), randomhsv[0], randomhsv[1], randomhsv[2])
			strip.show()
			strip.setPixelColor((randompixel), 0, 0, 0)
			break


def toggle11():
	if pw1 == 1100 and pw2 == 1100:
		print("toggle aux 1 pw ={}, toggle gear 1 pw ={}".format(int(pw1), int(pw2)))
		pi.set_PWM_dutycycle(23, 0)#set MOSFET to low -> 12v LEDs ON
		strip.setPixelColor(0, 0x000000)
		strip.show()
		time.sleep(.2)
		strip.setPixelColor(0, 0xFF0000)
		strip.show()
		time.sleep(.2)


def toggle32():
	if pw1 == 1900 and pw2 == 1900:
		print("toggle aux 3 pw ={}, toggle gear 2 pw ={}".format(int(pw1), int(pw2)))
		pi.set_PWM_dutycycle(23, 255)#set MOSFET to high -> 12v LEDs OFF
		strip.setPixelColor(10, 0x000000)
		strip.show()
		time.sleep(.2)
		strip.setPixelColor(10, 0x0000FF)
		strip.show()
		time.sleep(.2)


def toggle22():
	if pw1 == 1500 and pw2 == 1900:
		print("toggle aux 2 pw ={}, toggle gear 2 pw ={}".format(int(pw1), int(pw2)))
		pi.set_PWM_dutycycle(23, 255)#set MOSFET to high -> 12v LEDs OFF
		strip.setPixelColor(10, 0x000000)
		strip.show()
		time.sleep(.2)
		strip.setPixelColor(10, 0x00FF00)
		strip.show()
		time.sleep(.2)


def toggle12():
	if pw1 == 1100 and pw2 == 1900:
		print("toggle aux 1 pw ={}, toggle gear 2 pw ={}".format(int(pw1), int(pw2)))
		pi.set_PWM_dutycycle(23, 255)#set MOSFET to high -> 12v LEDs OFF
		"""
		image-pov; shows an image line-by-line on the led strip
		"""
		while True:
			for x in range(pov.width):
				strip.show(pov.column[x])
				time.sleep(.01)
				print "showing"
				if pw1 != 1100:
					print "breaking pw1"
					break
				if pw2 != 1900:
					print "breaking pw2"
					break


if __name__ == "__main__":

	SAMPLE_TIME = 0.001

	pi = pigpio.pi()
	p1 = reader(pi, PWM_GPIO_1)
	p2 = reader(pi, PWM_GPIO_2)
	start = time.time()

	pov()#convert the image file

	while True:
#		time.sleep(SAMPLE_TIME)
#		pw1 = p1.pulse_width()
#		pw2 = p2.pulse_width()
		pw1 = 1100 #these are set temporaily to test each
		pw2 = 1900 #toggle without the need for pwm input signal.

		toggle31()
		toggle21()
		toggle11()
		toggle32()
		toggle22()
		toggle12()

And here is a video of it
https://www.youtube.com/watch?v=Fy78VOpgBDI
Last edited by mtgtopdeck on Mon Jan 18, 2016 6:51 am, edited 2 times in total.

User avatar
karrika
Posts: 1070
Joined: Mon Oct 19, 2015 6:21 am
Location: Finland

Re: RC Flying POV LED Strip

Mon Jan 18, 2016 4:44 am

Looks like an UFO. Nice.

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Thu Jan 21, 2016 11:13 pm

karrika wrote:Looks like an UFO. Nice.
I have a close encounters setup working now ;D


https://www.youtube.com/watch?v=2JNOUuct06w

Here is the working Beta Code for this project.

It's not optimized. It's not written by a professional programmer.
It works and that is all that I need.

6 different defined functions.
instant switching between each.
constant data rate set at 1,700fps for best viewing at ~60mph.


grxxl.py

Code: Select all

import time
import pigpio
from dotstar import Adafruit_DotStar
import Image
import random
import readrx


numpixels = 119 #number of pixels in the strip
strip = Adafruit_DotStar(numpixels, 24000000, order='bgr')

filename1 = "pattern03.jpg" #file name of image to be converted
filename2 = "triangles.jpg"
filename3 = "pattern04.jpg"
filename4 = "closeencounters.jpg"

rOffset = 3     #fix RGB color order
gOffset = 2
bOffset = 1

strip.begin()
strip.setBrightness(127)

class pov1:# converting an image to a byte array for sending to led strip
        print "Loading {}...".format(filename1)
        img       = Image.open(filename1).convert("RGB")
        pixels    = img.load()
        width     = img.size[0]
        height    = img.size[1]
#       print "%dx%d pixels" % img.size
        gamma = bytearray(256)
        for i in range(256):
                gamma[i] = int(pow(float(i) / 255.0, 2.7) * 255.0 + 0.5)
#       print "Allocating..."
        column = [0 for x in range(width)]
        for x in range(width):
                column[x] = bytearray(height * 4)
#       print "Converting..."
        for x in range(width):          # For each column of image...
                for y in range(height): # For each pixel in column...
                        value             = pixels[x, y]    # Read pixel in image
                        y4                = y * 4           # Position in raw buffer
                        column[x][y4]     = 0xFF            # Pixel start marker
                        column[x][y4 + rOffset] = gamma[value[0]] # Gamma-corrected R
                        column[x][y4 + gOffset] = gamma[value[1]] # Gamma-corrected G
                        column[x][y4 + bOffset] = gamma[value[2]] # Gamma-corrected B
        print "Done Loading {}...".format(filename1)

class pov2:# converting an image to a byte array for sending to led strip
        print "Loading {}...".format(filename2)
        img       = Image.open(filename2).convert("RGB")
        pixels    = img.load()
        width     = img.size[0]
        height    = img.size[1]
#       print "%dx%d pixels" % img.size
        gamma = bytearray(256)
        for i in range(256):
                gamma[i] = int(pow(float(i) / 255.0, 2.7) * 255.0 + 0.5)
#       print "Allocating..."
        column = [0 for x in range(width)]
        for x in range(width):
                column[x] = bytearray(height * 4)
#       print "Converting..."
        for x in range(width):          # For each column of image...
                for y in range(height): # For each pixel in column...
                        value             = pixels[x, y]    # Read pixel in image
                        y4                = y * 4           # Position in raw buffer
                        column[x][y4]     = 0xFF            # Pixel start marker
                        column[x][y4 + rOffset] = gamma[value[0]] # Gamma-corrected R
                        column[x][y4 + gOffset] = gamma[value[1]] # Gamma-corrected G
                        column[x][y4 + bOffset] = gamma[value[2]] # Gamma-corrected B
        print "Done Loading {}...".format(filename2)

class pov3:# converting an image to a byte array for sending to led strip
        print "Loading {}...".format(filename3)
        img       = Image.open(filename3).convert("RGB")
        pixels    = img.load()
        width     = img.size[0]
        height    = img.size[1]
#       print "%dx%d pixels" % img.size
        gamma = bytearray(256)
        for i in range(256):
                gamma[i] = int(pow(float(i) / 255.0, 2.7) * 255.0 + 0.5)
#       print "Allocating..."
        column = [0 for x in range(width)]
        for x in range(width):
                column[x] = bytearray(height * 4)
#       print "Converting..."
        for x in range(width):          # For each column of image...
                for y in range(height): # For each pixel in column...
                        value             = pixels[x, y]    # Read pixel in image
                        y4                = y * 4           # Position in raw buffer
                        column[x][y4]     = 0xFF            # Pixel start marker
                        column[x][y4 + rOffset] = gamma[value[0]] # Gamma-corrected R
                        column[x][y4 + gOffset] = gamma[value[1]] # Gamma-corrected G
                        column[x][y4 + bOffset] = gamma[value[2]] # Gamma-corrected B
        print "Done Loading {}...".format(filename3)

class pov4:# converting an image to a byte array for sending to led strip
        print "Loading {}...".format(filename4)
        img       = Image.open(filename4).convert("RGB")
        pixels    = img.load()
        width     = img.size[0]
        height    = img.size[1]
#       print "%dx%d pixels" % img.size
        gamma = bytearray(256)
        for i in range(256):
                gamma[i] = int(pow(float(i) / 255.0, 2.7) * 255.0 + 0.5)
#       print "Allocating..."
        column = [0 for x in range(width)]
        for x in range(width):
                column[x] = bytearray(height * 4)
#       print "Converting..."
        for x in range(width):          # For each column of image...
                for y in range(height): # For each pixel in column...
                        value             = pixels[x, y]    # Read pixel in image
                        y4                = y * 4           # Position in raw buffer
                        column[x][y4]     = 0xFF            # Pixel start marker
                        column[x][y4 + rOffset] = gamma[value[0]] # Gamma-corrected R
                        column[x][y4 + gOffset] = gamma[value[1]] # Gamma-corrected G
                        column[x][y4 + bOffset] = gamma[value[2]] # Gamma-corrected B
        print "Done Loading {}...".format(filename4)


def hsv2rgb(HSV):#convert HSV 255 values to RGB 255
    H, S, V = HSV
    if S == 0:
        R = V
        G = V
        B = V
        return (R, G, B)
    region = H // 43;
    remainder = (H - (region * 43)) * 6;
    P = (V * (255 - S)) >> 8;
    Q = (V * (255 - ((S * remainder) >> 8))) >> 8;
    T = (V * (255 - ((S * (255 - remainder)) >> 8))) >> 8;
    if region == 0:
        R = V
        G = T
        B = P
    elif region == 1:
        R = Q;
        G = V;
        B = P;
    elif region == 2:
        R = P;
        G = V;
        B = T;
    elif region == 3:
        R = P;
        G = Q;
        B = V;
    elif region == 4:
        R = T;
        G = P;
        B = V;
    else:
        R = V;
        G = P;
        B = Q;
    return R, G, B

"""
six toggle states.
toggle readrx.pw1()(aux1) has three positions
toggle readrx.pw2()(gear) has two positions
"""

def toggle31():
        if readrx.pw1() == 1900 and readrx.pw2() == 1100:
                print("aux 3 pw ={}, gear 1 pw ={}".format(int(readrx.pw1()), int(readrx.pw2())))
                pi.set_PWM_dutycycle(23, 0)
                running = True
                while running:
                        for x in range(pov4.width):
                                strip.show(pov4.column[x])
                                time.sleep(.02)
                                if readrx.pw1() != 1900:
                                        running = False
                                        break
                                if readrx.pw2() != 1100:
                                        running = False
                                        break
                        break
                """
                cylon
                """
                """
                running = True
                while running:
                        i = 0
                        while (i < numpixels):
                                if readrx.pw1() != 1900:
                                        running = False
                                        break
                                if readrx.pw2() != 1100:
                                        running = False
                                        break
                                strip.setPixelColor(i, 0x0000FF)
                                strip.show()
                                strip.setPixelColor(i, 0x000000)
                                time.sleep(0.001)
                                i += 1
                        i = numpixels - 1
                        while (i < numpixels):
                                if readrx.pw1() != 1900:
                                        running = False
                                        break
                                if readrx.pw2() != 1100:
                                        running = False
                                        break
                                strip.setPixelColor(i, 0xFF0000)
                                strip.show()
                                strip.setPixelColor(i, 0x000000)
                                time.sleep(0.001)
                                i -= 1
                                if i <= 0:
                                        break
                """

def toggle21():
        if readrx.pw1() == 1500 and readrx.pw2() == 1100:
                print("aux 2 pw ={}, gear 1 pw ={}".format(int(readrx.pw1()), int(readrx.pw2())))
                pi.set_PWM_dutycycle(23, 0)
                """
                confetti
                """
                running = True
                while running:
                        if readrx.pw1() != 1500:
                                running = False
                                break
                        if readrx.pw2() != 1100:
                                running = False
                                break
                        randompixel = random.randint(0, 119)
                        randomcolor = random.randint(0, 255), 255, 255
                        randomhsv = hsv2rgb(randomcolor)
                        strip.setPixelColor((randompixel), randomhsv[0], randomhsv[1], randomhsv[2])
                        strip.show()
                        time.sleep(.01)
                        strip.setPixelColor((randompixel), 0, 0, 0)
                        strip.show()

def toggle11():
        if readrx.pw1() == 1100 and readrx.pw2() == 1100:
                print("aux 1 pw ={}, gear 1 pw ={}".format(int(readrx.pw1()), int(readrx.pw2())))
                strip.show()
                running = True
                while running:
                        i = 0
                        while (i < 200):
                                if readrx.pw1() != 1100:
                                        running = False
                                        break
                                if readrx.pw2() != 1100:
                                        running = False
                                        break
                                pi.set_PWM_dutycycle(23, i)
                                time.sleep(0.001)
                                i += 1
                        while (i == 200):
                                if readrx.pw1() != 1100:
                                        running = False
                                        break
                                if readrx.pw2() != 1100:
                                        running = False
                                        break
                                time.sleep(.1)
                                i -= 1
                        while (i < 200):
                                if readrx.pw1() != 1100:
                                        running = False
                                        break
                                if readrx.pw2() != 1100:
                                        running = False
                                        break
                                pi.set_PWM_dutycycle(23, i)
                                time.sleep(0.001)
                                i -= 1
                                if i <= 0:
                                        break

def toggle32():
        if readrx.pw1() == 1900 and readrx.pw2() == 1900:
                print("aux 3 pw ={}, gear 2 pw ={}".format(int(readrx.pw1()), int(readrx.pw2())))
                pi.set_PWM_dutycycle(23, 255)
#               print "image-pov 3"
                while True:
                        for x in range(pov3.width):
                                strip.show(pov3.column[x])
                                time.sleep(.0005)
                                if readrx.pw1() != 1900:
                                        running = False
                                        break
                                if readrx.pw2() != 1900:
                                        running = False
                                        break
                        break


def toggle22():
        if readrx.pw1() == 1500 and readrx.pw2() == 1900:
                print("aux 2 pw ={}, gear 2 pw ={}".format(int(readrx.pw1()), int(readrx.pw2())))
                pi.set_PWM_dutycycle(23, 255)
#               print "image-pov 2"
                while True:
                        for x in range(pov2.width):
                                strip.show(pov2.column[x])
                                time.sleep(.0005)
                                if readrx.pw1() != 1500:
                                        running = False
                                        break
                                if readrx.pw2() != 1900:
                                        running = False
                                        break
                        break


def toggle12():
        running = True
        if readrx.pw1() == 1100 and readrx.pw2() == 1900:
                print("aux 1 pw ={}, gear 2 pw ={}".format(int(readrx.pw1()), int(readrx.pw2())))
                pi.set_PWM_dutycycle(23, 255)
#               print "image-pov 1"
                running = True
                while running:
                        for x in range(pov1.width):
                                strip.show(pov1.column[x])
                                time.sleep(.0005)
                                if readrx.pw1() != 1100:
                                        running = False
                                        break
                                if readrx.pw2() != 1900:
                                        running = False
                                        break
                        break


if __name__ == "__main__":
        SAMPLE_TIME = 0.01
        pi = pigpio.pi()
        pov1()#convert the image file
        pov2()
        pov3()

        print "Starting Main Loop"
        while True:
#               print dir(readrx)
#               print readrx.pw1()
                time.sleep(SAMPLE_TIME)
                toggle31()
                toggle21()
                toggle11()
                toggle32()
                toggle22()
                toggle12()



readrx.py

Code: Select all

import time
import pigpio

PWM_GPIO_1 = 12 #PWM input gpio pins
PWM_GPIO_2 = 16

class reader:# Reads the Pulse Width signal of a gpio input and returns it's value

    def __init__(self, pi, gpio, weighting=0.0):
        self.pi = pi
        self.gpio = gpio

        if weighting < 0.0:
            weighting = 0.0
        elif weighting > 0.99:
            weighting = 0.99

        self._new = 1.0 - weighting # Weighting for new reading.
        self._old = weighting       # Weighting for old reading.

        self._high_tick = None
        self._period = None
        self._high = None

        pi.set_mode(gpio, pigpio.INPUT)

        self._cb = pi.callback(gpio, pigpio.EITHER_EDGE, self._cbf)

    def _cbf(self, gpio, level, tick):

        if level == 1:

            if self._high_tick is not None:
                t = pigpio.tickDiff(self._high_tick, tick)

                if self._period is not None:
                    self._period = (self._old * self._period) + (self._new * t)
                else:
                    self._period = t

            self._high_tick = tick

        elif level == 0:

            if self._high_tick is not None:
                t = pigpio.tickDiff(self._high_tick, tick)

                if self._high is not None:
                    self._high = (self._old * self._high) + (self._new * t)
                else:
                    self._high = t

    def pulse_width(self):       #Returns the PWM pulse width in microseconds.
        if self._high is not None:
          return ((round(self._high/100))*100) #round pwm to nerest hundred
        else:
          return 2.0

    def cancel(self):#      Cancels the reader and releases resources.
        self._cb.cancel()

pi = pigpio.pi()
p1 = reader(pi, PWM_GPIO_1)
p2 = reader(pi, PWM_GPIO_2)

def pw1():
    pw1 = p1.pulse_width()
    return pw1

def pw2():
    pw2 = p2.pulse_width()
    return pw2

User avatar
karrika
Posts: 1070
Joined: Mon Oct 19, 2015 6:21 am
Location: Finland

Re: RC Flying POV LED Strip

Thu Jan 21, 2016 11:22 pm

Looks great. Your starboard/port color scheme gives it a nice touch. Using long shutter times on the camera at night could make great pictures. Could the plane be controlled to draw a Raspberry logo in the sky? Or perhaps it requires too exact control of the flight.

You could get some great photos by freezing the plane with a flash at the end of the exposure.

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Sat Jan 23, 2016 10:14 am

karrika wrote:Looks great. Your starboard/port color scheme gives it a nice touch. Using long shutter times on the camera at night could make great pictures. Could the plane be controlled to draw a Raspberry logo in the sky? Or perhaps it requires too exact control of the flight.

You could get some great photos by freezing the plane with a flash at the end of the exposure.
This plane will be controlled line-of-sight.
I have high hopes that persons will be able to see the images created with the LEDs with a naked eye.
I will be using my Canon EOS Rebel T3 to capture long exposure shots to get a more complete view of the images for publishing.

Here is the completed wing Ready To Fly!

Image

Image

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Tue Jan 26, 2016 3:33 am

Maiden flight was a success.

A few clicks down trim and a few left and it was perfect.

CG is great

http://youtu.be/dfCKps-BfHo


More to come next week when I can get my hands on a DSLR camera

User avatar
karrika
Posts: 1070
Joined: Mon Oct 19, 2015 6:21 am
Location: Finland

Re: RC Flying POV LED Strip

Tue Jan 26, 2016 4:22 am

At least the plane flies great.

mtgtopdeck
Posts: 22
Joined: Tue Dec 22, 2015 4:27 am

Re: RC Flying POV LED Strip

Mon Feb 22, 2016 8:53 pm

Here is a ground test image.
I held the wing and rode a bike at about 15mph.

Image

User avatar
karrika
Posts: 1070
Joined: Mon Oct 19, 2015 6:21 am
Location: Finland

Re: RC Flying POV LED Strip

Fri Feb 26, 2016 7:34 pm

Really outstanding image quality. Very good picture.

Return to “Graphics, sound and multimedia”