javaloops16-bitdmx512

In Java: How to make a DMX moving generator that uses 16Bit


I working one a small Java project controlling a DMX-light, a “moving head”. So far, I can control the moving head using Art-Net, doing the most simple stuff – like setting a value for a channel.

Now I’m working on moving the moving head. The moving head supports 16bit and this troubles me. I know that the 16bit comes from using two “channels”. 1 channel is one byte, 8 bits, so the maximum value for 1 channel is 255. When using two channels the maximum increases to 65.356 which will give much more precise movement on the pan- & tilt-channel. So, a 16bit moving head uses 4 channels for controlling pan and tilt.

Now I want to create a simple movement generator in Java. Simple looping the pan- and tilt-value from 1 to 255. If I understand it correct, when using 16bit moving head, it means, first setting the pan “fine” (pan only in this example) from 1 to 255 and when pan “fine” reaches 255 then increasing pan “course” with 1, like this: Pan “fine” 1->255, when reaching 255 increase pan course with 1 then again Pan “fine” 1->255, when reaching 255 increase pan course with 1 and then again Pan “fine” 1->255, when reaching 255 increase pan course with 1, and so on.

I need to have some kind of delay in the movement generator and I can see on various places that it is best to avoid Thread.sleep() (and while loops) as it can drift, so I have decided to built the generator in its own method and then call this method with an Executor Service (scheduleAtFixedRate), like this:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Main {

    public static void main(String[] args) {

        test test = new test();

        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

        executorService.scheduleAtFixedRate(test::run, 0, 10000000, TimeUnit.NANOSECONDS);

    }

}

“run” is the method with the generator and “test” is the class containing the method. That part is working well.

This is the method in test which should serve as the movement generator: public class test {

    int start = 1;
    int end = 255;
    int counterFine = 1;
    int counterCourse = 255;
    boolean startOverCourse = false;

    public void run() {

        if (!startOverCourse) {

            counterFine++;

        }

        if (startOverCourse) {

            counterFine--;

        }

        if (counterFine == end) {

            counterCourse++;

        }

        if (counterCourse == end) {

            startOverCourse = true;
            counterFine = end;

        }

    }

}

Yes, I know it is not much to give you, sorry for that, but I can't figure out what to do now and the reason is this: When “course” reaches (I starts at 1, and increases with 1 when “fine” reaches 255) 255, course will need to start to count down, 255 becoming 254 and so on. But, that will also mean that when course reaches 255 then fine also have to decrease, going from 255-> (before it was 1->255).

Maybe some of you guys can figure out what I want to archive, maybe I’m doing it complete wrong, then please tell me how to approach it.

So, in Java, how to do a simple Pan & Tilt movement generator using 16bit. I know how to do it in 8 bit, using two channels, but I don’t know how to include the fine-channels and making it 16bit.

Kind Regards 😊

EDIT: This is what my test class look like now:

public class test {

    DmxValues dmxValuesOBJ;
    SendArtnet SendArtnet;
    int start = 1;
    int end = 255;
    int counterFine = 1;
    int counterCourse = 1;
    boolean startOverCourse = false;

    test(DmxValues obj1, SendArtnet obj2) {

        dmxValuesOBJ = obj1;
        SendArtnet = obj2;

    }

    public void run() {

        dmxValuesOBJ.setdmxvalues(4 - 1, counterFine);
        dmxValuesOBJ.setdmxvalues(2 - 1, counterFine);
        SendArtnet.testSend();


        if (counterFine == end && !startOverCourse) {

            dmxValuesOBJ.setdmxvalues(3 - 1, counterCourse);
            dmxValuesOBJ.setdmxvalues(1 - 1, counterCourse);
            SendArtnet.testSend();

            counterCourse++;

        }

        if (counterFine == end && startOverCourse) {

            dmxValuesOBJ.setdmxvalues(3 - 1, counterCourse);
            dmxValuesOBJ.setdmxvalues(1 - 1, counterCourse);
            SendArtnet.testSend();

            counterCourse--;

        }

        if (counterFine == end) {

            counterFine = start;

        }

        if (counterCourse == end) {

            startOverCourse = true;

        }

        if (counterCourse == start) {

            startOverCourse = false;

        }

        System.out.println(counterFine);

        counterFine++;

    }

}

SendArtnet and DmxValues are classes for sending and containing the dmx-data, should not be relevant, it's there so I can see in my dmx-monitor what is going on.

Above test class does what I want when it comes to the course-value (counterCourse), goes up to 255 and down to 1. The issue is I can not figure out how to do the same with the fine value (counterfine) - now it runs in one direction (from 1 to 255) but I need it to change direction when countercourse reaches 255, from 255 to 1.

I hate all those "if" - any smarter way to do all this?


Solution

  • Conceptually, you're trying to smoothly ramp a single 16 bit value (between 0 and 65535), and the two 8-bit values are simply a way of expressing that data in a way that works with DMX512. Trying to express the ramping/counting in terms of separate coarse and fine counters is complicating the logic significantly since you're essentially implementing your own arithmetic carry, in a way.

    Keep a single counter, sweep it between 0 and 65535 (or your range of interest), and convert it at each step: the coarse part is counter / 256, and the fine part is counter % 256.