0

I’m (still) working on a small project controlling DMX-lights (using Art-Net). At the moment I’m working on the “Movement-generator” and what I basically do is to use sine and cosine to calculate the DMX values (0-255) for the pan- and tilt-channel, like with this method:

public void runSineMovement() {

    double degrees = x;
    double radians = Math.toRadians(degrees);
    double sine = Math.sin(radians);

    double dmxValue = (int) ((sine * 127) + 127);

    dmxValuesOBJ.setDmxValuesInArray(1, (int) dmxValue);

    SendArtnet.SendArtnetNow();

    x = x + 1;

    if (x > 360) {

        x = 1;

    }

}

x = 1

I then have a ScheduledExecutorService that will call that method on a regular interval, like this:

int speed = 100;
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(SineMovement::runSineMovement, 0, 100000 * speed, TimeUnit.NANOSECONDS);

Above is working just fine, moving head (tilt-channel in this example) is moving perfectly. Now I want to use the “fine-channel”, that is, go from 8bit to 16bit (from 1 channel to 2 channels controlling the tilt-channel) so I can get smooth movement even at very slow speed. Remember, "fine-channel" have to go from 0 to 255 first and then "coarse-channel" can go to 1, then "fine-channel" from 0 to 255 and then "coarse-channel" to 2, and so on.

Earlier I build a movement-generator with “triangle-effect” where I looped from 0 to 65.536 and back to 0 and so on, and on every run I calculated the “coarse-channel” (counter/256) and the “fine-channel” (counter % 256) and that approach is working just fine.

Any ideas on how to approach this when using sine and cosine when generating the effect? Can I use the approach from the triangle-generator calculating “coarse” and “fine” using division and modulus?

EDIT: When thinking about it, I don't think the "fine" should have the form as a sine-wave, I mean, the "fine" will (if using sine) go very, very, fast, both up and down, and that will mess things up if the "coarse" is still going "up". I guess the correct is that the "fine" will always have the sawtooth-shape -> sawtooth from zero to max when coarse is going up, and sawtooth from max to zero when coarse is going down. Does that makes sense?

Thanks

droid
  • 103
  • 1
  • 15
  • just calculate sine/cosine, add offset to value is always between 0-2, then scale by 32767 – OldProgrammer Feb 15 '23 at 20:12
  • Thanks, but I'm not sure I can follow you. I mean, I can use that for getting the coarse value but when calculating the fine-value it is like the resolution is wrong, it jumps way too much (at very low run speed so I can see what is going on), i need to have the fine to go from 1 to 2, 2 to 3 and so on. Regards – droid Feb 15 '23 at 20:25

1 Answers1

3

You should calculate the sine-wave just for the values 0 - 65535 and then use the splitting method you used for the triangle waveform to part it to the two channels like this:

public void runSineMovement() {

    x = (x + 1) % 360; // this increments x and "wraps around" between 0-359

    double radians = Math.toRadians(x);
    double sine = Math.sin(radians);

    int dmxValue = (int) (sine * 32767.0 + 32767.0);

    int fineDmxValue = dmxValue & 255; // "lowByte"
    int coarseDmxValue = (dmxValue >> 8) & 255; // "hiByte"

    // TODO: set your DMX values here and send them
}

In this code I used several improvements:

  1. I replaced your increment + if for the x value with an increment and a modulus calculation.

  2. I used improved typing:

    • double constants wherever possible (32767.0 instead of 32767) so the program doesn't cast the int to a double in each run.
    • have int dmxValue instead of casting to int multiple times.
  3. Instead of division and modulus for your coarse and fine values I used the faster bit shift right (>>) and binary and (&) operators.

The fine value consists of the 8 least significant bits of your number, so you can simply "mask out" all the others with a binary and operation.

The coarse value consist of the "other" 8 bits (most significant bits of a 16-bit value, that you are effectively using), so you can bring them 8 bits ot the right (equals a division by 2 to the power of 8), and then - just to make sure, again mask out all other bits.

Don't mix up the logical AND (&&) with the binary AND & used here, the former one can only be used with boolean values.

Why will this work: the fine value will not oscillate between 0 and 255 (in a sine form!) for each change of the coarse value, because the code calculates just one sine wave and "splits" the values into fine and coarse. So if you have e.g. a value of 255 for dmxValue, this will give you fineDmxValue as 255 and coarseDmxValue as 0. But for a value of 256 for dmxValue, the fineDmxValue will be 0 while the coarseDmxValue will be 1.

The calculation of fine and coarse is independent of the way you generate your waveform in dmxValue.

cyberbrain
  • 3,433
  • 1
  • 12
  • 22
  • Hi cyberbrain. Thank you very much for your reply. I guess it all makes sense, thank you very much for your detailed answer. But, it is not working as expected. It won't make a slow and smotth movement. Its working fine with medium/fast movements but when slow movements the fine-channel is not doing its job. When the fine-values are printed in the console I can see that the fine-values jumps a lot - I thought it should always go from 1->255 or 255->1 as this will make very slow smooth movements possible (and only do coarse +1 when fine have done 0->255 or 255->0? – droid Feb 22 '23 at 15:58
  • 1
    I used a spreadsheet to calculate some individual values, when starting with x=0, I got a change of the coarse value by ~2 for each angle in degrees like 127, 129, 132, 134, 136, 138, 141, 143, 145, 147. When you think that for x = 0 to 360 the coarse value will have to go from 0 to 65535 (not with that start and end) in only 360 steps - so it just cannot be smooth with that resolution. You would have to increment only about 1/182 degrees per step to get a smoother experience, but remember that for the "flat" parts of the curve you will have the same output values for different inputs. – cyberbrain Feb 22 '23 at 16:24
  • Hi cyberbrain, thanks :) I have an updated version of my own code with your inputs, seems to do smooth movements at low speeds, can I show it to you in any way? Kind Regards – droid Feb 22 '23 at 16:31
  • Do you have any specific question with it or just need an overall code review? – cyberbrain Feb 22 '23 at 16:39
  • My question is whether it is a complete stupid way to do it :) Can I make a new post somewhere else with the updated code? – droid Feb 22 '23 at 16:51
  • OK, you want to get a code review - you could make a post on [codereview.se] and paste the link to that here, so over there you also get other opinions than mine (but I also will have a look at it) – cyberbrain Feb 22 '23 at 18:17
  • Hi cyberbrain. Code review is here: https://codereview.stackexchange.com/questions/283500/java-code-for-generating-16bit-dmx-values-using-sine-and-cosine thanks. – droid Feb 22 '23 at 18:44