Skip to content

Instantly share code, notes, and snippets.

@alexanderhiam
Created May 19, 2014 16:07
Show Gist options
  • Save alexanderhiam/620f401fc06c605b0919 to your computer and use it in GitHub Desktop.
Save alexanderhiam/620f401fc06c605b0919 to your computer and use it in GitHub Desktop.
DMX512 demo for Logic Supply's CBB-Serial BeagleBone cape
"""
dmx512.py
May, 2014
Alexander Hiam <hiamalexander@gmail.com>
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)]
"""
dmx_test.py
May, 2014
Alexander Hiam <hiamalexander@gmail.com>
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