I’m thinking about a protocol to change different parameters of effects running on FastLED. To be used on platforms like RFDuino (BLE), Photon (Wifi) or the ESP (wifi). So I later can use an app to control this or a a simple interface to create nice effects.
I was wondering what other people are using and if there are some best practices.
I did once an implementation like this (inspired by midi):
char cmdType;
int cmdTypeId;
int cmdId;
float cmdValue;
But now I’m thinking in using JSON or OSC. However I think a lightweight protocol might be the best (less processing time), however I prefer using a standard over using my own protocol. Maybe some start-stop byte implementation?
midi’s data rate is shitty. like really shitty. did i mention that it is shitty?
I’ve played around with OSC and really like it. Some things with OSC, though, to keep in mind on low cpu speed MCU’s (and the RFDuino, while arm, is only 16Mhz):
Math: floating point numbers are really expensive. Just don’t send/parse them.
Also, string parsing/navigation can be REALLY expensive. One nice thing with OSC is you can use really expressive paths to describe things. However, then you burn a bunch of CPU time parsing your messages, so when I was playing with OSC I replaced all my paths with much shorter paths, e.g.
/disc/speed became /d/s
then your parsing can become a chain of switch statements on the single character path components
WIth BLE you have a limit of 20-22 bytes per packet (though you can group six packets in a single ‘cycle’) - in which case you’d want an even more compact representation.
(Can you tell i’ve been spending a lot of time on this? Would it surprise anyone that there’s a framework slowly coming together that may see a future home next to FastLED?
@marmil The readability for others, but I’m just curious of there are better ways of doing it.
@Daniel_Garcia
The 22 bytes per packet is interesting info. I like the OSC structure as well, because it’s readable. However you’ll lose it if you shorten it. JSON is something that’s more used in the IoT scene I think. Also readable, but indeed every character counts.
Maybe sticking with my own protocol (of course without floats, I learned that lesson already in this group :)) is the best option.
I think the balance is between readability and speed, so then I’d prefer speed.
I referred to midi, not because of the speed, but the message setup:
status byte, data byte, data byte
I don’t like to use ‘pure’ bytes, because you can’t write them all in the serial monitor (for example 10 is a newline). So I do , something like this:
cmdType = Serial.read(); // this is a byte
cmdTypeId = Serial.parseInt(); // 2 bytes
cmdId = Serial.parseInt(); // 2 bytes
cmdValue = Serial.parseInt(); // 2 bytes
In between I put spaces or a comma (I think this costs a byte then) and I’ll end with a newline. So this structure costs 11 bytes.
Here the parsing code I use to read my commands:
What do you mean with the 6 packets ‘cycle’. Do you mean you send a message bigger than 20 bytes in multiple chunks (I could find something on that).
Any ideas about the parseInt() speed. Is this smart to use or does it cost way more CPU cycles than readByte?
For, for the parseInt, you’re definitely going to burn more cycles. For one, you’re going to be reading 2-4 bytes instead of just 1 byte for a 1 byte number. (1-3 digits and then a terminator/separator of some kind). For another, you have to read in the multiple bytes.
Because that reading is going to be blocking, it’s going to take some minimum amount of time based on the data rate. The question is, can the rest of the parsing/number conversion work that has to happen to turn those characters into a number fit in between each of the bytes, or is it still going to leave you burning cycles even after the bytes have physically come in over the wire?
Eh - maybe, especially if you’re using a slower data rate. So, it’s probably not the worst thing in the world, but you’re sending 2-4 times as much data as you need to (also, if the data has already come in over the wire and been buffered, then you are absolutely wasting cpu cycles parsing int data). Whereas if you’re sending bytes you can do:
and now you have everything nicely packaged in a structure. (Barring worrying about byte order issues
And extra wow, is their code stupid on a performance front. The most common thing that you will be looking for when parsing integers are DIGITS. So, why do they do that check after the rest? Also, they do the check for the character type twice, even … gah… I may need to “fix” this and do a pull request…
blah - also, Stream.parseInt is returning a long - which is four bytes. This means that it is likely that this call is going to have at least 8 cycles of overhead for dealing with returning a 4 byte value. That’s half a microsend on a 16Mhz avr.
Mmm, I get it. Nice example with the structure. However means that it’s not easy just to give a command from the Serial monitor. However I already had in mind to do a quick Processing interface with controlP5 so I can control everything with a sliders, buttons and knobs.
What do you mean with byte order issues? They might switch? Or you mean because if we miss a byte, everything gets messed up. Any suggestion on how to solve that simply? Check for a certain start pattern (2 bytes) and otherwise flush the whole buffer?
No, I mean whenever you have multiple byte integer values (e.g. a 2 byte short or a 4 byte long) there’s a question of what order the bytes come in (and/or are represented in memory). In a big endian system, the first byte is the high byte of the number, and the next byte is the next highest byte, etc… while in a little endian system, the first byte is the low byte of the number, and the next byte is the next lowest, etc… (see also - https://en.wikipedia.org/wiki/Endianness ). For the most part, mere mortals don’t ever really have to care about this, because byte ordering is pretty constant on a single machine (some exceptions, but not worth going into here :).
The problem comes into play when you do network transfers though. Let’s say you have one machine that’s big endian, and you have another machine that’s little endian. On the big endian machine, the value 0xFF00 will be stored with the 0xFF first then the 0x00. If you send those bytes, in that order over the network, and the receiver puts the m in memory with the 0xFF in byte 0 and the 0x00 in byte 1, the 16-bit value there will be 0x00FF – oops, not what was sent! (In fact, ip protocols specify big endian for networking - there’s convinience functions ntohl, ntohs, htonl, htons ( for Net TO Host Long or Net TO Host Short or Host TO Net Long, or Host To Net Short) that you can use to ensure the right ordering (on a bigendian machine, these functions are effectively noops, whereas on a little endian machine they have to byte swap).
Amusingly, 8-bit AVR is little endian, while the 32-bit AVR32 is big endian. (Amusingly? maybe that should be irritatingly)
I understand now how important timing are.
However, I understood @Kasper_Kamperman 's original idea to look for a method to change color settings and start/stop animations. A while ago @Thomas_Eldredge put a great post of his work online with BTcontrol - and also a Chrome extension.
He is using Serial.parseInt() and the sketch is working also with WS2812.
There are still some glitches, but maybe the existing code is worth for improvements.
I have been working on connected light too, for quiet some time. I’am still waiting for my Photons to arrive (sucks!) and the delivery delay have really pushed me back! I thought they were about to arrive, so i have just been waiting for a loong time…
Well… I’ve had the same thoughts, and i really like the OSC protocol, blazing fast compared to the other protocols i tried, but as you say it is quiet heavy compared to what is needed in the end. But i like’ed that it was so easy to format, but I’ve kind of leaned that in the meantime.
I’am not really in to JSON yet, but this could be an opportunity to get it.
One may say that it is a little overkill to talk about 1-2 bytes in a case where you are just controlling a few variables at a time, but who knows!
For streaming pixels i like to use ArtNet, but I have only tested it with 160 pixels on the Spark Core. I haven’t stress tested it, but I wasn’t seeing any lag with 30 fps.
The responsiveness makes it really fun to play with the lights!
So i would just hear if you have come up with anything?
I am considering weather to make a ChromeApp or android app, my concerns about the ChromeApp is that it may be hard to access android related things, such as accelerometer, sound and other sensors.
Are you aware of any GOOD existing solution to controlling connected leds? Then i may just save my time making one…
I am working on something similar but targeted for wearables, so no constant stream of commands. I’m making a config of patterns / presets / colors / parameters that can be stored in EEPROM (and updated over bluetooth / usb / etc.).
I’ve used OPC whenever I had a host connected and streaming prerendered pixels.