How to build a WebUSB DMX512 Controller by using an Arduino

Tim Pietrusky
14 min readApr 24, 2018

--

The final WebUSB DMX512 Controller

I love to control all the lights and I always try to find new ways of doing so. Currently I’m in love with DMX512 and WebUSB.

This article describes how you can build your own DMX512 controller by using an Arduino and how this controller can be used directly in the browser by leveraging WebUSB. It will answer the following questions:

DMX512

Wikipedia defines DMX512 like this:

DMX512 (Digital Multiplex) is a standard for digital communication networks that are commonly used to control stage lighting and effects. It was originally intended as a standardized method for controlling light dimmers, which, prior to DMX512, had employed various incompatible proprietary protocols.

DMX512 is used in many theaters, clubs and festivals to control all the lights and beyond: From static lights to moving heads and lasers to fog machines.

In my basement I have a collection of DMX512 lights:

DMX512 setup in my basement

How does it work?

DMX512 combines a set of lights (called fixtures) into a bus network of fixtures (called Universe). Each fixture has one or more functionalities, such as:

  • Color in RGB
  • Dimmer (= brightness)
  • UV
  • Movement (horizontally or vertically)
  • Strobe (= blinking effect)
  • Generate fog / smoke
  • Blow bubbles

Each functionality can be controlled by one or more channels. This means that each fixture has a different amount of channels, depending which functionality the fixture has. It also means that you can’t change the functionality of a fixture, you can only configure which of the predefined set of channels is used.

Each channel can be filled with a value between 0 and 255. In most situations it has the following meaning:

  • 0 = 0%: no intensity, zero speed, no blinking
  • 255 = 100%: full color, full speed, fast blinking

Every fixture comes with a manual that holds all the informations you need to use the it. It includes a list all predefined channel sets + the meaning of the channel values and general information about the fixture.

Basic fixtures

I will describe two of my favourite fixtures to get started with DMX512.

Fog Machine

“AF-150” by Stairville

The purpose of the fog machine is to produce smoke. The smoke itself helps to improve the visibility of the lights and the overall atmosphere.

  • 0 = fan is turned off
  • 255 = fan is at highest speed

Flat PAR RGBUV

“SePar Quad LED RGBUV IR” by Fun Generation

Let’s take a look at a very basic fixture: The “SePar Quad LED RGBUV IR” by Fun Generation. What does all of this mean?

  • SePar = This is a PAR light with 5 LEDs
  • Quad LED RGBUV = The LEDs can create any RGB color and UV light at the same time
  • IR = Fixture can be controlled via infrared

The Flat PAR’s manual is more exciting than to the one of the Fog Machine, because the PAR has 8 channels in 4 different sets (2, 4, 6 or 8):

2 Channels

4 Channels

6 Channels

8 Channels

Which set of channels should you use? That depends on what you actually want to do with the fixture. In this case I want to set the RGB color and use the dimmer, so I will use the 6 channels set.

But where can we set that? Every fixture has some kind of interface that can be used to configure it. In many cases you will find a display and some buttons at the back of the fixture:

Configure the set of channels, in this case it says “6-ch” = 6 Channels

This display let’s you change the configuration of the fixture, for example the set of channels that should be used.

It’s also possible to set the address.

Configure the address of the fixture, in this case it says “d001” = Address 1

Fixtures in a universe

The 512 in DMX512 stands for 512 channels. A combination of fixtures in a network is called a universe. Every fixture in the universe can have a specific address, so that it’s possible to set the channels of a specific device in the universe.

This means that the more fixtures we have in a universe, the more channels are blocked by a fixture. That means that we should always choose a set of channels based on what we want to achieve. If we don’t want to specific functionality, we choose the set that doesn’t contain it.

To calculate the next free address in a universe we can do it like this: address of fixture a + # channels of fixture a = address of fixture b

Attention: This is not required, but it’s always a good idea to give every fixture it’s own space. Only use the same address more than once if you want to have fixtures of the same type that are in sync with each other. Because in the end they all get the same channel values if they share the same address.

Example universe

Let’s say we have three fixtures:

  • 2 x Flat PAR with 6 channels
  • 1 x Fog machine with 1 channel

The first fixture is a Flat PAR with the address of 1. Using the formula 1 + 6, then the next fixture can start at 7. Then we add the second Flat PAR at address 7 and the Fog Machine at address 13.

The next thing we need is a WebUSB DMX512 controller to send the data (= an Array of 512 values) into the universe.

Arduino

Wikipedia defines Arduino like this:

Arduino is an open source computer hardware and software company, project, and user community that designs and manufactures single-board microcontrollers and microcontroller kits for building digital devices and interactive objects that can sense and control objects in the physical and digital world.

The project’s products are distributed as open-source hardware and software, which are licensed under the GNU Lesser General Public License (LGPL) or the GNU General Public License (GPL),[1] permitting the manufacture of Arduino boards and software distribution by anyone.

Arduino boards are available commercially in preassembled form, or as do-it-yourself (DIY) kits.

This is the perfect foundation to create our own WebUSB DMX512 Controller, because some Arduino (like the Arduino Leonardo with the ATmega32U4 chip) have the ability to be recognised by the computer as an external USB device. This makes it possible to use the Arduino over WebUSB.

Arduino Leonardo ETH with Headers

The Arduino has a set of female headers at the top with 18 connectors and the bottom with 14 connectors. They can be used to attach all kind of electronic devices or shields to the Arduino.

An Arduino shield can extend the functionality of the Arduino by adding it on top of the headers. This makes it possible for everyone to use all kind of devices without having to know anything about electrical engineering or soldering.

Arduino DMX512 Shield

In order to control a DMX512 universe with the Arduino we use the “2.5kV Isolated DMX512 Shield for Arduino — R2” on tindie. Let’s put it on top of the Arduino:

DMX512 shield on top of the Arduino
  1. The DMX512 shield, with two DMX connectors (I and II). I is the output to send data into the universe. II is empty.
  2. The Arduino Leonardo ETH, connected over MicroUSB to the computer.

Attention: As of writing this article there is no DMX512 shield for the small Arduino boards (like the Arduino Micro). This means that in order to use this shield you have to at least get an Arduino Leonardo or similar in terms of the size, because the position of the headers must be the same.

A list of boards that can be used in combination with the shield:

The hardware is ready, so let’s jump into the software.

Setup

In order to be able to upload the code to the Arduino you have to execute the following 12 steps:

  1. Checkout the NERDDISCO/webusb-dmx512-controller repository to your computer: git clone git@github.com/NERDDISCO/webusb-dmx512-controller.git
  2. Download & install the Arduino IDE >= 1.8.5 (so you are able to write & push code onto the Arduino)
  3. Open the Arduino IDE
  4. Open the preferences: Arduino > Preferences
  5. In the preferences dialog you have to change the Sketchbook location so that it points to the sketchbook folder that comes with the repository
  6. Close the Arduino IDE and then open it again (this is needed to load the new sketchbook that we selected in the step before)
  7. Now we need to configure the Arduino IDE so that it can recognise our Arduino:
  8. Select the model: Tools > Board > Arduino Leonardo (WebUSB) (or one of the other supported boards underneath the NERDDISCO: WebUSB DMX512 Controller headline in the menu)
  9. Select the USB port: Tools > Port > /dev/tty.usbmodem$ (The $ is a placeholder and will be different for every Arduino you are using)
    Attention: This can only be selected if your Arduino is actually attached to your computer!
  10. Open the sketch (if it’s not already open): File > Sketchbook > webusb_dmx512_controller
  11. Verify that the sketch is working: Sketch > Verify/Compile. This will produce an output like this when everything is ok:
    Sketch uses 8258 bytes (28%) of programm storage space. Maximum is 28672 bytes. Global variables use 888 bytes (34%) of dynamic memory, leaving 1672 bytes for local variables. Maximum is 2560 bytes.
  12. Upload the sketch to the Arduino: Sketch > Upload (This will produce a similar output as step 11)

Attention: If the steps 11 or 12 did not work as promised, please open an issue on GitHub in my repository

When you are done the Sketchbook location should look something like this:

Sketchbook location in the Arduino IDE preferences

And your Arduino IDE should look like this:

Arduino IDE with the loaded webusb-dmx512-controller sketch

Arduino Sketch

The applications that you upload on the Arduino are called sketch. They contain all the code and external libraries that are needed in order to control what the Arduino should do for you.

In order to better understand the webusb-dmx512-controller sketch that was just uploaded to the Arduino, we split it into three different parts.

1. Imports & definitions & global variables

( a ) Import the external libraries that are needed:

  • WebUSB to handle the WebUSB connection
  • Conceptinetics to handle the DMX512 shield (which is maintained by the same person that is selling the shield)

👉 Those two libraries are already part of the sketchbook that came with the repository.

( b ) For security reasons the WebUSB device has to whitelist the URLs that are allowed to use the device in the browser. In this case it points to my demo page. Please change this when you want to use the controller on your URL!

( c ) Use Serial instead of WebUSBSerial

( d ) Set the amount of channels in the universe to 512

( e ) Initialize the dmx_master which is used to send data to the DMX512 shield

( f ) Create an array of bytes that has the size of 512 to save the data that is coming over WebUSB to the Arduino

2. setup()

( a ) Every time the Arduino is started (for example when you connect it over USB to your computer), the setup() function is triggered once. It can be used to initialize everything.

( b ) Fill the incoming array of bytes with 0, so that every channel in the universe has a default value. This is needed to put the universe in a clean state.

( c ) Wait until the WebUSB connection in the browser was successfully established with the Arduino

( d ) When ( c ) is fulfilled, start the communication with the DMX512 shield

3. loop()

( a ) The main logic of the code is happening in loop(), because this function is called over and over again (and not only once as setup() does)

( b ) When the WebUSB connection in the browser was successfully established with the Arduino

( c ) Read 512 bytes that are send via WebUSB to the Arduino and save them into incoming

( d ) Iterate over all 512 values

( e ) Set the value of each channel of the universe according to the data that was received over WebUSB. First channel is 1.

WebUSB

Wikipedia defines USB like this:

USB, short for Universal Serial Bus, is an industry standard that was developed to define cables, connectors and protocols for connection, communication, and power supply between personal computers and their peripheral devices.

USB gives us the power to use devices regardless of the OS. Well, that is not entirely true, because only devices with standard functionality (= keyboard, mice, audio, video and storage devices) can be used everywhere. Non-standard devices always need some kind of OS-specific driver or SDK from the hardware manufacturer. This makes it super hard for developers to actually use these USB devices on the web.

WebUSB is here to overcome this problem, as it provides a safe way to expose non-standard USB devices in the browser. But what does safe even mean? The WebUSB standard defines different kind of protections:

  1. You can use it locally on localhost for testing
  2. You can use it online only secured via https
  3. You need a device that can handle URL whitelisting, meaning that the device has to allow on which URLs it can be used (which we already saw in the Arduino Sketch)
  4. The user has to allow using the USB device by triggering an explicit gesture (for example a click)

As of right now you can use WebUSB in Google Chrome 63 (native support) and as a port in Node.js. This might change in the future, so let’s keep track on the implementation status.

Using the DMX512 controller

At this point you already have the hardware ready, but to actually make use of it in the browser I created a module. It is part of the NERDDISCO/webusb-dmx512-controller repository and you can find it in controller.js. The module itself is also published on npm, so you can install it into your project: npm install webusb-dmx512-controller

Let’s see how the module can be used.

Create a connection to the Arduino

( a ) Import the ES6 module

( b ) Create an instance of the module

( c ) Get a reference to the button (or any other element the user can interact with to trigger the user gesture required by WebUSB protection mentioned earlier)

( d ) Listen for click events on the button (which have to be triggered by the user)

( e ) This will enable WebUSB and open a dialog for the user in which they can select the Arduino. The dialog looks like this (Chrome on macOS):

( f ) We can create a connection to the Arduino when (e) was successful

Update the DMX512 universe

Now that we have a connection to the Arduino from the browser, we can update the universe by using a single function:

  • The first parameter is the channel and expects a number
  • The second parameter is the value and expects either a number or an array of numbers

The function itself has two modes:

  1. Single = Update one channel. This happens when the value is a number
  2. Multiple = Update multiple channels starting at channel. This happens when value is an array

Before we start to use the function, let’s recapture what we have in our DMX512 universe:

( I ) Flat PAR with 6 channels at address 1

( II ) Flat PAR with 6 channels at address 7

( III ) Smoke machine with 1 channel at address 13

Let’s assume we want to set the Color (= channels 1, 2 & 3) to red for (I):

Yaaaay, our (I) is now in red. Or isn’t it? Well no, setting the Color alone is not enough. You also have to set the Dimmer on channel 5, because that controls how bright the LEDs are. Initially all channels are set to 0, which means that the brightness is “turned off”. So let’s set the Dimmer to 255:

Now the fixture (I) is shining in bright red.

Flat PAR with color red and dimmer at full brightness

Let’s also set the color of fixture (II) (address: 7) to yellow and use a slow strobe (= blinking at low frequency):

To improve the lighting effect of the two lights, we also activate the smoke of fixture (III) (address 13):

How does updateUniverse() work?

Every time you use the updateUniverse() function, the controller.universe array gets updated with the specified value(s), converted to an Uint8Array and finally send to the Arduino. The array itself looks like this (after we called it several times above):

API Documentation

You can find the full API documentation on GitHub.

Live Demo

In order to test the WebUSB DMX512 Controller directly in the browser, I have created a demo that is using the webusb-dmx512-controller module and wraps it in a basic UI: nerddisco.github.io/webusb-dmx512-controller

Browser demo for testing the WebUSB DMX512 Controller
  1. Activate WebUSB (& select the Arduino)
  2. Disconnect from the Arduino
  3. Set the value (0–255) of any channel (1–512) in the universe
  4. Use the example fixture (Flat PAR with 6 channels) from above and set the Color in RGB, UV, Dimmer and Strobe
  5. Console to show what is happening behind the scenes. It’s also possible to print out the content of the universe when using the “log universe” checkbox

What now?

This was just a very basic introduction in the world of visualizations with DMX512. You want to dive even deeper? GREAT.

fivetwelve

This project by Martin Schuhfuss provides a super nice abstraction to control DMX512 light-equipment. Everything I know and did with DMX512 is because of his library, so please go check it out: fivetwelve on GitHub

luminave

If you come that far, you should already know that I LOVE LIGHTS. And because I wanted to have a browser-based software to manage everything related to DMX512 and beyond, I created luminave. You can use luminave to create visual experiences, because it is providing different kind of integrations to other soft- and hardware:

So what can you do? Let’s watch this video of luminave in action:

Attention: The video contains flashing lights & music!

Originally published at notes.

--

--

Tim Pietrusky

Digital Artist @LiveJS_network and @NERDDISCO. Travels into other dimensions by leveraging the Web.