Raspberry Pi As a DMX Light Controller

203,525

284

52

Introduction: Raspberry Pi As a DMX Light Controller

About: I am a multidisciplinary engineer actively interested in new technology and how it can be used to further interest in science, technology, engineering, and mathematics.

Turn your Raspberry Pi into a DMX light controller


This instructable shows you how to display a color wheel editor window on the screen of a Raspberry Pi computer, which you can manipulate with your mouse. As you change the color on the screen, the color on the DMX light fixture changes in realtime to match. This can serve as a starting point for a variety of simple lighting projects using the Raspberry Pi ( i.e. haunted houses, onscreen light control panel, TV backlights, living room DJ setup, etc. ).

Step 1: Nuts and Bolts

A standard $35 Raspberry Pi computer runs a program that generates the onscreen interface, and sends commands via USB to a DMX controller continuously. The DMX controller then sends DMX commands to the light fixture to change the color. The hardware was chosen for cost and durability, and the software was developed on the platform and is available for free in source and binary format so you can begin hacking right away. Here is what you'll need ( as pictured ):



1. Raspberry Pi

The Raspberry Pi is an amazing $35 credit card sized computer that contains all the basic features of a "real" computer, including a free pre-built Linux operating system ( via SD card ), USB for keyboard and mouse, and most impressively a full HDMI video output. If you are new to the Raspberry Pi ( or raspi ) we strongly suggest you get your mitts on one as soon as possible - its a great platform for anyone interested in knowing more about how computers work, and you can actually write programs on it!


2. USB | DMX Controller

The raspi has a built-in I/O connector for doing all sorts of cool things, but for this project we chose to use one of the USB ports as our output interface because its simpler and more rugged than using breadboards and ribbon cables. To get things into DMX (digital light control) format, we will be using a Velleman USB to DMX interface. This can be bought in either kit or pre-built form, and is a really a great introduction to controlling DMX devices from a computer. Once you have this controller you'll find it a great tool for any lighting control project you may cook up in the future.


3. DMX light fixture

Pretty much any DMX controlled light fixture that has red, green, or blue channels will work, and in fact you can chain together several if you want t control a whole bank of lights from your raspi. In this example we are using a Chauvet LEDSplash 200B spotlight because we found one cheap online for about $60 and its very bright and runs cool. If you have a DMX dimmer and standard PAR cans that's fine too, its only important that you have a device that can receive red, green, and blue intensity channels.


4. HDMI ( or NTSC monitor )

Perhaps the best feature of the raspi is its HDM interface ( compare with Arduino video output ), which provides a full 1920x1080 graphics resolution to any TV screen that has an HDMI input. In this example we used a cheap Vizio monitor that we had in our kitchen, and functions nicely for a video monitor. It might be interesting to to use this kind of system as a starting point for a TV back light project or similar living room light effects when you move it into your living room since you have the video interface right there.

Step 2: The Raspi

1. raspi-tize yourself

The bulk of the work on this project is to get your raspi ready for business. You can purchase the raspi from several sources, but our preference is from the great folks at Adafruit industries - they have been and continue to be a strong supporter of makers everywhere. You can purchase a raspi from this link:

http://www.adafruit.com/products/998



2. get jacked

The raspi by itself is just a card, so to make it into a fully functioning computer you'll need a few components that you most likely already have lying around. It is well worth the effort to build your raspi into a fully functioning computer because it really is great machine for building any "smart" project you have in mind down the road. The Raspberri Pi foundation website is a great resource for getting or raspi up and running. Please read this page for information on what you need to get your raspi computing:

http://www.raspberrypi.org/quick-start-guide



3. get loaded

This project is using the stock Raspian "wheezy" operating system, which you can download for free from the Raspberry Pi Foundation website. This page has complete details on how to get the OS to your SD card - its very straightforward procedure, and in less than 20 minutes you should be able to plug the SD card into your raspi and have it booted and ready for business.

http://www.raspberrypi.org/downloads


4. hello raspi!

Once you've got the SD card prepared and cabling connected, simply insert it into the SD card slot, and hit the juice to the raspi. To your amazement a computer will appear on the screen. The stock wheezy distribution contains a window manager ( LXDE ) that you will use to log in ( Username: pi , Password: raspberry ) and begin your raspi adventure. As per the boot instructions, you can type "startx" to get the LXDE window manager running. Take a few minutes to explore the system. BTW, if you want to have your raspi boot into the windows environment every time you plug it in, you can follow these instructions:

http://www.raspberrypi-spy.co.uk/2012/06/auto-login-auto-load-lxde/



5. get wheelin'

The software that creates the color wheel interface and talks to the DMX converter can be downloaded for free in both binary and source format directly to your raspi. To get started, download the free DMXWheel application code from here:

dmxwheel source code (zip file)


Launch Midori ( from your desktop icon ), and enter this URL. Click on the paperclip, and save the file to your desktop when prompted; this will create an icon labeled DMXWheel.tar.gz" on your desktop. Next, open up a terminal window to get a command line interface by selecting the icon on the lower left of the tool bar -> Accessories -> LXTerminal. In the terminal window, type these two commands:

<strong>cd Desktop

tar xvzf DMXWheel.tar.gz</strong>


This will unpack the DMXWheel application code on your desktop to a folder named "DMXWheel". You can open this folder to find the code that is referred to in the rest of this instructable.



6. get the extra bits

Although not needed to run the programs, to make changes and build the source code two additional software packages should be installed. These two packages contain Linux-native code to communicate with USB (libusb-dev), and develop user interface windows (gtk+3.0) respectively. These packages are installed using the linux application management program called "apt-get". In the terminal, type these commands and follow the proceeding prompts:

<strong>sudo apt-get install libusb-dev

sudo apt-get install gtk+3.0
</strong>


7. raspi-ready

At this point you should have the raspi ready to go for the rest of the project. The software you will be using will be found in the DMXWheel folder on your desktop. Take a minute to look through this folder and read the README file - it provides valuable information on what the code is, what is does, and how to run it. We will go through some of the basics, but this README file can serve as your local reference documentation. There is a huge amount of coolness to explore on the raspi, so when you have some time explore the Raspberry Pi foundation forum to get some great ideas as well as support from the raspi community.

Step 3: The Dmx Controller

Now that your raspi is ready, the next step is to connect the lights to it. This is a simple procedure that basically involves connecting a USB cable from the raspi to the DMX interface, and a DMX cable from the interface to the light fixture you are using. First let's take a look at the DMX converter.


1. USB | DMX | FTW

To make things easier now (and down the road), we are using the VM116 USB Controlled DMX Interface by Velleman. This box performs the simple function of converting serial data send over USB to DMX signals sent to DMX units. This unit comes in two model numbers depending on whether you purchase it as a kit ( K8062 ) or assembled ( VM116 ). The kit is not particularly difficult to build, and the price difference is about $20:

http://www.amazon.com/Velleman-K8062-USB-Controlled-Interface/dp/B000TA79UK
http://www.amazon.com/Controlled-Interface-Factory-Assembled-Tested/dp/B001IRMFUW/ref=pd_cp_pc_0

As you can see from the picture, the unit requires a USB ( D ) input, which is the most common USB cable connection. Odds are that you already have one of the D to flat USB connectors lying around somewhere. The DMX out connector is a standard XLR connector commonly used for microphones and other balanced audio functions; these cables for fine so don't bother getting a DMX specific cable unless you feel the need to spend more money.



2. hub up? yeah, probably

One thing that you may have observed is that the raspi has two USB ports, both of which are currently in use by your keyboard and mouse. For this reason we recommend you look into a cheap powered USB hub; you may already have one sitting around somewhere, or might find a keyboard that has a mouse integrated into with (i.e. internal hub). We were able to get a powered hub for $10 at OfficeMax on clearance, so with a bit of shopping you'll find it will make life easier when working with the raspi. Another reason to get a powered hub is that it takes the power load off the USB connection on the raspi, thus reducing the power load on the supply on the raspi. You can, of course run this project without the hub ( by disconnecting the keyboard after launching the program ), but it can be cumbersome to develop the application in any significant way doing this.



3. puttin' it all together

To finish up with the raspi to light connection, connect the USB cable from the converter to the raspi, and from the convertor to your DMX light unit. At this point you should have cables that connect the mouse, keyboard, monitor, DMX converter, and light all together, and you're ready to fire up the program.

Step 4: The Software

The last thing to do in the project is to fire up the program and have some fun!

1. the secret sauce

The source code included in the DMXWheel distribution contains two programs that are needed to run the project. The way the code works is that there is one program that runs as a background process that reads a shared memory location that contains the states of the DMX channels. A second program runs directly in the foreground and brings up the color editor and changes the intensity values in the shared memory segment.
This division of labor allows the raspi to keep a constant line of communication open the the DMX controller and updates at a fixed interval, regardless of what application program manipulates the shared memory. The two programs communicate with each other using a C library that contains simple functions to set the DMX channel data so that the shared memory operation is transparent.

The programs are shipped in binary format and do not need to be recompiled, but you can do this if you want to make changes to the code or write your own program using the DMX controller. The software you downloaded has the following structure:

dmx/       DMX software library ( lib/ ) and the deamon program ( deamon/ )
DMXWheel/  contains the color wheel application ( src/, bin )
Makefie/   make file to build the source
README     detailed information about the software and its operation



2. daemonic intervention

The first step in getting things going is to launch the DMX controller interface program that runs in the background. In Linux parlance this is called a daemon. This program needs only be started once each time you boot the system. To start this program, type:

<strong>cd ~/Desktop/DMXWheel/dmx/deamon</strong>
<strong>sudo ./dmxd.bin &</strong>

When this program starts, it prints out some basic status information about the USB connection, and then goes quiet while it transmits the DMX channel data to the DMX interface. Note that this program must be run as an administrator ( sudo ), and runs in the background ( & ).


3. present the colors

The second step in getting things going is to launch the DMXWheel program. This program is the one that creates a window that contains the familiar color wheel that you can edit with the mouse. As you can see in this shot, there is an outer ring with a grab line that you can drag around to change the hue, and a circle inside the center triangle that lets you adjust saturation and brightness. As you move this control about, the color on the light will change accordingly. You can launch the program using the following command ( and quit the program by closing the window ):

<strong>cd ~/Desktop/DMXWheel/DMXWheel/bin</strong>
<strong>./DMXWheel.bin</strong>


Step 5: What's Next

Congratulations on a job well done. After experimenting a bit with the color wheel, a wide variety of outrageous ideas will most likely pop into your head. With the hardware you have in your possession you have all the resources you need to use DMX compatible devices in your raspi applications. Its time to start making!

In developing your own applications, some things you might find useful:


1. check out DMXWheel.c This program is very simple but shows you two important things. First, it shows you how to use the DMX library function calls to set DMX channels. You can easily change the code to support different channels, additional channels, and so on. Second, it shows you how to open up a GTK window on the screen. With a bit of googling on GTK you'll find a whole library of functions to create your own on-screen interfaces without having to start from scratch.


2. check out dmxd.c This program is the other side of the shared memory coin and does the serial command communication for the DMX controller. This code describes the packet format for sending data and gives you the nuts and bolts on how the DMX controller interprets the data.


3. check out other DMX units There are a lot of cool DMX controlled devices - this simple application just writes three channels of the available 512 that represent red, green, and blue for a light unit, but you can also support motors, lasers, strobes, and all kinds of smart units with just a bit of code tweaking.


4. check out the raspi We touched a bit on this amazing device, but if you poke around you'll find this board can go some impressive real-time 3D graphics, stereo audio, general I/O and more. Its just been released, so keep following its progress and more features and
applications become available to make your projects come to life.

Share

    Recommendations

    • Creative Misuse Contest

      Creative Misuse Contest
    • Water Contest

      Water Contest
    • Metalworking Contest

      Metalworking Contest

    52 Discussions

    Sorry to be the critic but.. you say DMX controller when in fact this is just the software to tell the controller ( The usb Device ) what to do. Whilst I can see it’s purpose I achieve the same with a ethernet to DMX encoder ( Controller ) and forget the rpi there are numerous apps I can then use

    Hi flashular, this is a great project, nice work! Just wondering how to access/download the dmxd.c program? thanks

    8 replies

    Hi omeguanut. The source can be downloaded here:

    http://www.engeldinger.com/services/latest-project/dmxwheel

    Let me know if you run into any problems getting it working.

    Hi flashular

    Are you still supporting this project? I'm trying to use it for a final project in a class I'm taking but I can't get it to work I keep getting an error when I launch the DMXWheel that states, :"** (DMXWheel.bin:1609): WARNING **: Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files"

    Any help is appreciated as I'm tying to complete the project and can't get past this.

    Thanks!

    I don't have a raspberry pi at the moment to test this out, but I would suspect there might be a binary incompatibility. Can you build the source, and if so do you get the same error?

    Thanks for getting back to me. As I'm kind of new to all this I'm not sure what build the source means. I dicussed my issues with my professor and she wants me to report on my experience so even though it didn't work for me the time pressure is off. But would love to get it working just the same.

    dmx.c:

    // ==========================================================================
    // Velleman K8062 DMX controller library for VM116/K8062
    // ==========================================================================

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <errno.h>

    #include "dmx.h"


    int   * maxChanAddr;        // control register for # of channels to update
    ubyte * exitAddr;           // control register to exit deamon
    ubyte * chanData;           // 512 byte array of channel data

    ubyte * shm;                // shared memory segment containing data & ctrl regs
    int     shmid = -1;         // handel to shared memory segment


    // ==========================================================================
    // open the DMX connection
    // ==========================================================================

    int dmxOpen()
    {

      // get the shared memory created by the deamon

        shmid = shmget ( 0x56444D58 , sizeof ( ubyte ) * 515 , 0666 );

        if ( shmid == -1 ) {
          printf ( "error[%d] - is dmxd running?\n" , errno );
          return ( errno );
        }

        // set up control and data registers

        shm = ( ubyte *) shmat ( shmid, NULL, 0 );

        maxChanAddr  = ( int * ) shm;
        exitAddr     = ( ubyte * ) maxChanAddr + 2;
        chanData     = ( ubyte * ) maxChanAddr + 3;
    }

    // ==========================================================================
    // close the DMX connection
    // ==========================================================================

    void dmxClose()
    {
      if ( shmid != -1 ) shmdt ( shm );
    }

    // ==========================================================================
    // dmxSetMaxChannels -- set the maximum # of channels to send
    // ==========================================================================

    void dmxSetMaxChannels ( int maxChannels )
    {
      *maxChanAddr = maxChannels;
    }

    // ==========================================================================
    // dmxSetValue -- set the value for a DMX channel
    // ==========================================================================

    void dmxSetValue ( ubyte channel , ubyte data )
    {
      chanData[channel] = data;
    }

    dmx.h:

    // ==========================================================================
    // Velleman K8062 DMX controller library for VM116/K8062
    // ==========================================================================

    typedef unsigned char ubyte;

    int  dmxOpen           ();
    void dmxClose          ();
    void dmxSetMaxChannels ( int maxChannels );
    void dmxSetValue       ( ubyte channel , ubyte value );

    dmxd.c:

    // ==========================================================================
    // Velleman K8062 DMX controller Deamon for VM116/K8062
    // ==========================================================================
    //
    // Modified from code from Denis Moreaux 2008 ( <vapula@endor.be> )
    //
    //
    // This program should be run as a background process and continously updates
    // a shared memory segment created by the application to control DMX channels
    // sent through the DMX controller. The DMX channels can be accessed through
    // a shared memory block that is allocated as:
    //
    // 0     = max # of channels to send  ( 0 - 512 )
    // 1     = exit deamon control flag   ( 0 = run, 1 = exit )
    // 2-514 = dmx channel data
    //
    // ==========================================================================
    //
    // Prerequisites ( USB lib ):
    //   sudo apt-get install libusb-dev
    //
    //
    // ==========================================================================
    //

    #include <usb.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <string.h>
    #include <errno.h>


    // dmx data and control registers

    typedef unsigned char ubyte;

    int   * maxChanAddr;      // control register for # of channels to update
    ubyte * exitAddr;         // control register to exit deamon
    ubyte * chanData;         // 512 byte array of channel data


    ubyte *shm;              // shared memory segment containing data & ctrl regs
    int shmid;               // handel to shared memory segment


    // constants and defs

    #define ProgName "dmxd"  // name of this program
    #define VendorID 0x10cf  // K8062 USB vendor ID
    #define ProdID   0x8062  // K8062 USB product ID

    #define UpdateInt 100000 // update interval ( microseconds )
    #define DefMaxChans   16 // default number of maximum channels

    // internal structures

    struct usb_bus *bus;    // pointer to the USB bus
    struct usb_device *dev; // pointer to the K8062 USB device
    usb_dev_handle *udev;   // access handle to the K8062 device


    // function delcarations

    int  main();

    int sendDMX();


    int  initUSB();
    int  writeUSB ( ubyte *data , int numBytes );
    void exitUSB();

    int  initSHM();
    void exitSHM();

    void timediff ( struct timeval *res, struct timeval *a, struct timeval *b );
    void timeadd  ( struct timeval *res, struct timeval *a, struct timeval *b );


    // ==========================================================================
    // main -- dmx deamon
    // ==========================================================================

    int main() {

        struct timeval now,next,diff,delay;
        int success;

        printf ( "%s: starting dmx deamon\n" , ProgName );


        // intialize USB device

        success = initUSB();

        if ( !success ) {
          printf ( "%s: error initializing USB interface\n" , ProgName );
          return ( -1 );
        }

        // initialize shared memory segment

        success = initSHM();

        if ( !success  ) {
          printf ( "%s: error initializing shared memory\n" , ProgName );
          return ( -2 );
        }


        // start timer

        delay.tv_sec = 0;
        delay.tv_usec= UpdateInt;

        gettimeofday ( &next , NULL );



        // loop until commanded to shutdown

        while( !*exitAddr ) {


          // send DMX data

          success = sendDMX();

          if ( !success ) {

    printf  ( "%s: DMX send error\n" , ProgName );
    *exitAddr++;
          }
         

          // wait for update interval

          timeadd ( &next , &next , &delay );
          gettimeofday ( &now , NULL );
          timediff ( &diff, &next , &now );

          while (diff.tv_sec || diff.tv_usec) {

    select ( 0, NULL, NULL, NULL, &diff );
    gettimeofday ( &now, NULL );
    timediff ( &diff, &next, &now );
          };     

        }

        printf ( "%s: dmx deamon is shutting down\n" , ProgName );


        // on shutdown reset all DMX channels

        memset ( chanData , 0, 512 * sizeof (ubyte) );

        sendDMX();


        // exit the system

        exitUSB();
        exitSHM();

        return ( 0 );
    }


    // ==========================================================================
    // sendDMX -- send current DMX data
    // ==========================================================================

    int sendDMX ()
    {
      ubyte data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
      int numChans = *maxChanAddr;
     

    #if 1

      // find out how many consecutive zeroes are in the data - the start
      // packet can indicate this to avoid sending a bunch of leading
      // zeroes

      int curChanIdx = 0;
     
      for ( curChanIdx = 0; curChanIdx < numChans; curChanIdx++ ) {
        if ( chanData[ curChanIdx ] != 0 ) break;
      }

      // build starting packet. this packet specifies how many channels have
      // zero data from the start and then contains the next 6 channels of
      // data

      data[0] = 4;                          // start packet header (4)
      data[1] = curChanIdx;                 // number of zeroes ( not sent )
     
      data[2] = chanData [ curChanIdx++ ];  // first ( non-zero ) chan data
      data[3] = chanData [ curChanIdx++ ];  // next chan data
      data[4] = chanData [ curChanIdx++ ];  // next chan data
      data[5] = chanData [ curChanIdx++ ];  // next chan data
      data[6] = chanData [ curChanIdx++ ];  // next chan data
      data[7] = chanData [ curChanIdx++ ];  // next chan data
     
      int success = writeUSB ( data , 8 );

      if ( !success ) {
        printf ( "%s: error sending DMX start packet\n" , ProgName );
        return ( 0 );
      }

      if ( curChanIdx >= numChans ) return ( 1 );

     

      // after the first packet additional packets are sent that contain seven
      // channels each up to 512.

      while ( curChanIdx < ( numChans - 7 ) ) {
         
        data[0] = 2;                          // start packet header (2)
        data[1] = chanData [ curChanIdx++ ];  // next chan data
        data[2] = chanData [ curChanIdx++ ];  // next chan data
        data[3] = chanData [ curChanIdx++ ];  // next chan data
        data[4] = chanData [ curChanIdx++ ];  // next chan data
        data[5] = chanData [ curChanIdx++ ];  // next chan data
        data[6] = chanData [ curChanIdx++ ];  // next chan data

      }

      success = writeUSB ( data , 8 );

      if ( !success ) {
        printf ( "%s: error sending DMX bulk packet\n" , ProgName );
        return ( 0 );
      }

      if ( curChanIdx >= numChans ) return ( 0 );

    #else

      data[0] = 5;   // packet header for single channeld data

      printf ( "sending %d channels\n" , numChans );
     

      for ( int chIdx = 0; chIdx < numChans; chIdx++ )
        {
          data[1] = chanData [ chIdx ];

          int success = writeUSB ( data , 8 );

          if ( !success ) {
    printf ( "%s: error sending DMX data packet\n" , ProgName );
    return ( 0 );
          }
        }

    #endif 

     
      return ( 1 );

    }

    // ==========================================================================
    // initUSB -- intialize the USB interface for the device
    // ==========================================================================

    int initUSB()
    {
      int success;
     

      // open the usb library

      usb_init();


      // find the usb device for DMX controller

      usb_find_busses();
      usb_find_devices();

      usb_device_descriptor *descr = 0x0;

      for ( bus = usb_busses; bus; bus = bus -> next ) {

        for ( dev = bus->devices; dev; dev = dev -> next ) {

          printf ( "%s: checking device [%s]\n" , ProgName , dev -> filename );

          descr = & dev->descriptor;

          if (      ( descr -> idVendor == VendorID )
                 && ( descr -> idProduct == ProdID  ) ) break;
        }
      }

      if ( !dev ) {
    printf ( "%s: DMX device not found on USB\n" , ProgName );     
    return ( 0 );
      }
     

      // open the device

      printf ( "%s: opening device [%s] ... " , ProgName , dev -> filename );

      udev = usb_open ( dev );

      if ( udev == 0x0 ) {
        printf ( "%s: error opening device\n" , ProgName );
        return ( 0 );
      }
      else {
         printf ( "ok\n" );
      }


      // claim the interface


    #if     defined(LIBUSB_HAS_GET_DRIVER_NP) \
         && defined(LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP)

      usb_detach_kernel_driver_np( udev, 0);

    #endif


      // set configuration


      usb_set_debug(4);

      success = usb_set_configuration ( udev, 1 );

      if ( success != 0 ) {
        printf ( "%s: configuration error [%d]\n" , ProgName , success );
        return ( 0 );
       
      }


      // claim the interface
         
      success = usb_claim_interface ( udev, 0 );

      if ( success != 0 ) {
         
        printf ( "%s: error claiming interface [%d]\n" , success );
        return ( 0 );
      }

      return ( 1 );
    }

    // ==========================================================================
    // writeUSB -- write a command to the USB interface
    // ==========================================================================

    int writeUSB ( ubyte *data , int numBytes )
    {
      int nSent;

      //  printf ( "%s: writing [%d] bytes " , ProgName , numBytes );
      //  for ( int b = 0; b < numBytes; b++ ) printf ( "[%d]" , data[b] );
      //  printf ( "\n" );

      // write the data

      nSent = usb_interrupt_write ( udev ,
                                    1,
                                    (char *) data,
                                    numBytes,
                                    200 );

      if ( nSent != numBytes ) {
         
        printf ( "%s: error writing [%d] bytes [%d]\n" , numBytes , nSent );
        return ( 0 );
      }

      return ( 1 );
     
    }


    // ==========================================================================
    // exitUSB -- terminate USB connection
    // ==========================================================================

    void exitUSB()
    {
        usb_close(udev);
    }

    // ==========================================================================
    // initSHM -- initialize shared memory segment
    // ==========================================================================

    int initSHM()
    {

      printf ( "%s: creating shared memory segment ... " , ProgName );


      // create the shared memory segment

      shmid = shmget ( 0x56444D58 , sizeof ( ubyte ) * 515 , IPC_CREAT | 0666 );

      if ( shmid == -1 ) {
        printf ( "error creating shared memory segment [%d]\n" , errno );
        return ( 0 );
      }
      else
        printf ( "ok\n" );


      // attach to segment and initialize


      printf ( "%s: intitalizing segment [0x%x] ... " , ProgName , shmid );

      shm = ( ubyte * ) shmat ( shmid , NULL , 0 );

      if ( shm == 0x0 ) {
        printf ( "error connecting to segment [%d]\n" , errno );
        return ( 0 );
      }
      else
        printf ( "ok\n" );


      memset ( shm , 0 , sizeof ( ubyte ) * 515 );


      // set up command & data registers

      maxChanAddr  = ( int * ) shm;
      *maxChanAddr = DefMaxChans;

      exitAddr     = ( ubyte * ) maxChanAddr + 2;
      chanData     = ( ubyte * ) maxChanAddr + 3;

      return ( 1 );
    }

    // ==========================================================================
    // exitSHM -- terminate shared memory segment
    // ==========================================================================

    void exitSHM()
    {
        shmdt(shm);
        shmctl(shmid,IPC_RMID,NULL);
    }

    // ==========================================================================
    // timediff | timeadd -- timing functions
    // ==========================================================================

    void timediff ( struct timeval *res, struct timeval *a, struct timeval *b)
    {
        long sec,usec;
        sec=a->tv_sec-b->tv_sec;
        usec=a->tv_usec-b->tv_usec;

        while (usec<0) {
            usec+=1000000;
            sec--;
        }
        if (sec<0) {
    res->tv_sec=0;
    res->tv_usec=0;
        } else {
    res->tv_sec=sec;
    res->tv_usec=usec;
        }
    }

    void timeadd(struct timeval *res, struct timeval *a, struct timeval *b)
    {
        res->tv_usec=a->tv_usec+b->tv_usec;
        res->tv_sec=a->tv_sec+b->tv_sec;
        while (res->tv_usec >= 1000000) {
    res->tv_usec-=1000000;
    res->tv_sec++;
        }
    }

    Makefile:

    CC=g++
    DEAMONOBJS=dmxd.o
    LIBOJBS=dmx.o
    OBJS=$(LIBOBJS) $(DEAMONOBJS)
    DEAMONBIN=dmxd.bin
    LIB=libdmx.a
    CFLAGS+=
    LDFLAGS+=-lusb -lm
    INCLUDES+=-I./

    all: $(LIB) $(DEAMONBIN) $(TESTBIN)

    %.o: %.c
    @rm -f $@
    $(CC) $(CFLAGS) $(INCLUDES) -g -c $< -o $@ -Wno-deprecated-declarations

    dmxd.bin: $(DEAMONOBJS)
    $(CC) -o $@ -Wl,--whole-archive $(DEAMONOBJS) $(LDFLAGS) -Wl,--no-whole-archive -rdynamic
    mv dmxd.bin ../deamon


    %.a: $(LIBOJBS)
    $(AR) r $@ $^
    mv $(LIB) ../lib
    cp dmx.h ../include

    clean:
    for i in $(OBJS); do (if test -e "$$i"; then ( rm $$i ); fi ); done
    @rm -f dmxd.bin $(LIB)

    Hello, I recently ran into a problem that I have not been having before, when trying to run DMXWheel.bin as normal, i am getting an error that states

    "** (DMXWheel.bin:1609): WARNING **: Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files"

    I have not changed any of my hardware and it has been working properly before. Does anyone know what could cause this error?

    Thanks!

    1 reply

    Hello EddieG39.

    I just ran into this same error. Were you able to figure out the issue? If so, can you share as this is the only issue I can't get through on this project.

    Thanks!

    I installed a Raspberry PI with OLA and a ENTTEC DMX Pro and it works very well with the free app Photon for iPad (https://photon-ios.com). Art-Net play my sequences, it's pretty.

    however, the raspberry have some lags sometimes, I think that a ENTTEC ODE is better...

    This is the iPad app preview if you are interested


    Well done mate! You've done a great job.

    I've been playing with the PI for a few years, but my knowledge is still pretty limited. Have you any idea how I go about making this kind of thing work with a different usb to dmx adaptor. My hope was that 'under-the-hood' mine would be the same as the velleman one, but when I execute the daemon I get an error about USB device not found. I guess it can't be that complicated! I feel up for a challenge!

    Well done. Amazed more people haven't done this. My application is basically for static LED architectural lighting in our church building, without having a lighting desk that fingers can twiddle! Then when we have events I can use a full desk or PC (freestyler) for more ambitious lighting (chases etc).

    Hi,

    Nice project as well, but i'm having the same issue described here:

    // acastellano-e 2 years ago

    // Hi!!
    // First of all, this is an amazing project.
    // I'm playing with the code and i can't control more than 6
    // channels at the same time, when i set values for 6 channels
    // if i set a value to 7th it doesn't changue. If i start to
    // set values from the 7th chanel it works but only for the
    // first 6 channels that i set, any idea?

    Could anyone help me?

    THansk in advance.

    P.:s. I'm rewriting as I cannot hit the reply botton to commit my comment to the existing entry .


    Or just install QLC+.

    I'm still trying to speak with the deamon via a python program. I have the deamon running. But nothing is happening on the DMX bus when I start the python script.

    import sysv_ipc

    memory=sysv_ipc.SharedMemory(0x56444D58 , 0666, 512)

    print memory

    shm=sysv_ipc.attach(491527)

    print shm

    for i in range(512):

    shm.write(str(unichr(100)),i)

    Could anybody help me, to get me a hint, how I can use or integrate this module in python?

    This project is really great. Thank you very much!.

    My whole application is written in Python.

    Can anybody help me with a python example sending only a single DMX value on one channel to the running deamon?

    This would help me very very much to create my own application in Python.

    "To get started, download the free DMXWheel application code from here using this page.

    Launch Midori ( from your desktop icon ), and enter this URL."

    Which page ? Which URL ? Why is this broken ?

    What a shame ! It's otherwise very well written !