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
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:
In this code I used several improvements:
I replaced your increment +
if
for the x value with an increment and a modulus calculation.I used improved typing:
double
constants wherever possible (32767.0
instead of32767
) so the program doesn't cast theint
to adouble
in each run.int dmxValue
instead of casting toint
multiple times.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 withboolean
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 youfineDmxValue
as 255 andcoarseDmxValue
as 0. But for a value of 256 fordmxValue
, thefineDmxValue
will be 0 while thecoarseDmxValue
will be 1.The calculation of fine and coarse is independent of the way you generate your waveform in
dmxValue
.