OK! I thought it would be good to post my complete solution, in case anyone finds it useful.
The following allows a user to control a DotStar 5 m LED strip with 30 LEDs per meter. The user can control the location, intensity, and size of the source of light from 3 Makie.sliders. The whole thing is pretty snappy!
using LibSerialPort, Makie
n = 150
s = open("/dev/ttyACM0", 115200)
psl, pol = textslider(1:n, "Position", start = 1);
ssl, sol = textslider(1:2:21, "Size", start = 1);
isl, iol = textslider(0:255, "Intensity", start = 0);
sc = hbox(psl, ssl, isl)
msg = lift(pol, iol, sol) do p, i, s
p = p - (s - 1)/2 - 1
if p < 0
s += p
p = 0.0
end
pend = p + s
if pend > n - 1
s = n - 1
end
[UInt8(p), UInt8(i), UInt8(s)]
end
on(msg) do m
write(s, m)
end
Nice! It’d be great to see a video of it in action.
One potential issue is that if your serial stream ever gets desynchronized there’s no way to recover - i.e. if the Arduino drops a byte or something then everything will be shifted over by a byte. One solution is to reserve a value (like 0xFF) that is never allowed to be part of your data and using that as a frame separator.
Might not be a problem in practice, but the strip ever starts acting wonky that might be what’s going on.
read “infinitely” until I get the frame separator byte.
read the n bytes I know are in one frame, and test if the last byte is indeed my separator byte. If it is not, then and only then keep reading bytes (and tossing them) until I get to the next separator byte.
Methods #1 is simple, but then I’m testing for the separator every loop. In method #2 I’m checking for the separator byte only once a frame. On the other hand I think I miss one extra frame, which is fine.
I suspect I’m fretting over virtually nothing…
@ssfrr, one more question: I need to operate 4 strips. Each has 150 LEDs. I’m considering connecting the 4 strips serially, to the one Arduino. I’ll then need to have a location of more than 255 (==256).
I’m trying to figure out how to do that on the Julia and the Adruino sides…
In Julia, something like this:
n = rand(0:600)
b1 = UInt8(n ÷ 255)
b2 = UInt8(mod(n, 255))
@assert 255b1 + b2 == n
It’s more involved, but you find something similar in other UART protocols. This example is from the u-blox GPS chipset. A message header, register, length, payload, and finally a checksum. It’s a bit more work to read, as you have to validate parts of the message as it comes in, and have a timeout to make sure it doesn’t get stuck at a partial frame.
Wow, COBS looks really cool. How would I encode my payload COBS-like? Also, wow, didn’t know there were libraries for stuff like this. I feel I should explore some more, maybe I’ll find other useful libraries for the Arduino…
I suggest you use the millis() function which keeps a track of the number of milliseconds since the last restart of the board.
now = millis() - where now is an unsigned long integer ( you also need to assign ‘prev’ ( previous )
if (( now - prev ) > 200 )
{
…
prev = now ; }
This is a way of doing something every 200mS but not holding up the processing of other routines.