Created
May 19, 2014 16:07
-
-
Save alexanderhiam/620f401fc06c605b0919 to your computer and use it in GitHub Desktop.
DMX512 demo for Logic Supply's CBB-Serial BeagleBone cape
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
dmx512.py | |
May, 2014 | |
Alexander Hiam <[email protected]> | |
A very basic DMX512 implementation made for the BeagleBone and | |
BeagleBone Black. | |
DMX512 class should be instantiated with a PyBBIO serial port object, | |
e.g.: | |
from bbio import * | |
dmx = DMX512(Serial4) | |
There are then three methods to generate and send DMX data: | |
# put value 128 in DMX channel 1: | |
dmx.addData(1, 128) | |
# Put values 10, 11, and 255 starting at DMX channel 4: | |
dmx.addData(4, 10, 11, 255) | |
# i.e. | |
# channel 4 = 10 | |
# channel 5 = 11 | |
# channel 6 = 255 | |
# Send out the current data packet: | |
dmx.send() | |
# Reset the working packet to all 0 values: | |
dmx.clearPacket() | |
.addData() can take an arbitrary number of values after the start | |
channel. | |
After .send() is called, the state of the working data packet will | |
remain the same as it was when sent. | |
The serial port used will require an external RS485 transceiver, such | |
as the MAX485. | |
Note: this is only an example, and is a fairly slow implementation. | |
The standard maximum data rate of DMX512 is 44 packets per second, | |
where as this object can only send out data at a maximum of ~13 | |
packets per second. | |
Written for Logic Supply's CBB-Serial DMX tutorial at: | |
http://inspire.logicsupply.com/2014/05/cbb-serial-dmx-lighting-control.html | |
""" | |
from bbio import delay | |
class DMX512(object): | |
def __init__(self, serial_port): | |
""" serial_port should be a PyBBIO serial port object. """ | |
self.port = serial_port | |
self.clearPacket() | |
def fade(self, ch, start, end, duration=0, increment=1): | |
""" Fade from 'start' to 'end' over approximitely 'duration' milliseconds. | |
If 'duration' is 0, runat the maximum update rate. The value will be | |
changed by 'increment' each update. """ | |
inc = abs(increment) | |
if start > end: inc = -inc | |
if duration > 0: | |
p = int(duration / abs(start-end) * increment) | |
else: p = 0 | |
if p >= 75: | |
# Takes about 75ms to send a packet, remove this offset: | |
p -= 75 | |
else: | |
# Below the maximum resolution, don't delay at all: | |
p = 0 | |
for val in range(start, end, inc): | |
self.addData(ch, val) | |
self.send() | |
if p: delay(p) | |
def addData(self, ch, *data): | |
""" Add one or more bytes to the current packet starting at given | |
channel. """ | |
assert ch > 0, "DMX channels start at 1" | |
ch -= 1 # DMX starts at 1, list index starts at 0 | |
for val in data: | |
assert ch < 512, "tried to set channel > 512" | |
# Ensure value is within allowed range: | |
if val < 0: val = 0 | |
if val > 255: val = 255 | |
self.packet[ch] = val | |
ch += 1 | |
def send(self, sc=0): | |
""" Send out the current packet. A custom start code may optionally be | |
given. """ | |
# Send a 0 byte at a lower baud to get a long enough BREAK signal: | |
self.port.begin(57600) | |
self.port.write(0) # BREAK | |
# Set to DMX baud rate: | |
self.port.begin(250000) | |
# Send start code: | |
self.port.write(sc) # Start code | |
# Finally send the packet: | |
for val in self.packet: | |
self.port.write(val) | |
def clearPacket(self): | |
""" Sets all channel values to 0. """ | |
self.packet = [0 for i in range(512)] | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
dmx_test.py | |
May, 2014 | |
Alexander Hiam <[email protected]> | |
This is an example program using PyBBIO the dmx512.py module. | |
Meant to be used with the Logic Supply CBB-Serial BeagleBone cape with | |
an RGB DMX512 light attached to the on-board RS485 transceiver. | |
Written for Logic Supply's CBB-Serial DMX tutorial at: | |
http://inspire.logicsupply.com/2014/05/cbb-serial-dmx-lighting-control.html | |
""" | |
import random, time, sys | |
from bbio import * | |
# dmx512.py must be in the same directory as this file or somewhere in the Python | |
# search path to import it: | |
from dmx512 import DMX512 | |
# RGB values will be sent to FIRST_CH, FIRST_CH+1 and FIRST_CH+2 respectively: | |
FIRST_CH = 1 | |
# The GPIO pin that enables the driver in the half duplex RS485 transceiver: | |
DE_PIN = GPIO1_16 | |
# The CBB-Serial cape uses GPIO1_16 by default. | |
# Create an instance of the DMX512 class, passing it PyBBIO's Serial4 object: | |
d = DMX512(Serial4) | |
# The RS485 transceiver is attached to UART4 on the CBB-Serial cape | |
def clear(): | |
""" Clears the working DMX packet to all 0 values and transmits it. """ | |
d.clearPacket() | |
d.send() | |
def testColors(): | |
""" Cycles through the different combinations of the RGB channels. """ | |
clear() | |
levels = [0, 255] | |
for r in levels: | |
for g in levels: | |
for b in levels: | |
d.addData(FIRST_CH, r, g, b) | |
d.send() | |
delay(500) | |
clear() | |
def testFade(): | |
""" Demonstrates the DMX512 object's fade() method. """ | |
clear() | |
# Fade channel 1 from 0 to 255 as quick as possible, incrementing | |
# the value by 10 each update | |
d.fade(1, 0, 255, 0, increment=10) | |
# And the other channels: | |
d.fade(2, 0, 255, 0, increment=10) | |
d.fade(3, 0, 255, 0, increment=10) | |
# Now fade the other direction back to 0: | |
d.fade(1, 255, 0, 0, increment=10) | |
d.fade(2, 255, 0, 0, increment=10) | |
d.fade(3, 255, 0, 0, increment=10) | |
def testRandom(): | |
""" Generates and transmits random values on the RGB channels. """ | |
for i in range(50): | |
d.addData(1, random.randint(0, 255), | |
random.randint(0, 255), | |
random.randint(0, 255)) | |
d.send() | |
delay(10) | |
def testSpeed(): | |
""" Measures and reports the average data rate in packets/sec. """ | |
start = millis() | |
for i in range(10): | |
d.addData(1, 255, 0, 0) | |
d.send() | |
d.addData(1, 0, 255, 0) | |
d.send() | |
d.addData(1, 0, 0, 255) | |
d.send() | |
dt = (millis() - start) / 1000.0 / 30.0 | |
print "%0.2f packets/sec" % (1.0/dt) | |
def setup(): | |
""" setup() routine for PyBBIO. """ | |
# Set the driver enable pin as an output and drive it high to put | |
# the RS485 transceiver into transmit mode: | |
pinMode(DE_PIN, OUTPUT) | |
digitalWrite(DE_PIN, HIGH) | |
# Seed the random number generation algorithm: | |
random.seed(time.time()) | |
print "\nDMX512 demo\n" | |
def loop(): | |
""" loop() routine for PyBBIO. """ | |
print "Measuring data rate...", | |
sys.stdout.flush() | |
testSpeed() | |
print "Testing colors...", | |
sys.stdout.flush() | |
testColors() | |
print "done" | |
print "Testing fade...", | |
sys.stdout.flush() | |
testFade() | |
print "done" | |
print "Generating random colors...", | |
sys.stdout.flush() | |
testRandom() | |
print "done" | |
# Tell PyBBIO to stop here instead of looping forever: | |
stop() | |
# Tell PyBBIO to run the program: | |
run(setup, loop) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment