Serial coms protocol for an Arduino-Based Button Box

I'm designing a hardware control panel for a flight simulator: buttons and dials connected to an Arduino Mega, talking over serial to a helper application running in Python on a PC. It's essentially a fancy "button box" project: flip a switch or turn a knob on the hardware panel, the python program receives a message over serial, then sends the corresponding action on to the flight sim.

It's trivial to get this working with raw serial bytes, but before going further I'm wondering if there would be value in implementing a more robust serial coms protocol to do some error detection, retransmit missing packets, and protect against buffer overruns. I'd eventually like to get the PC sending signals back to the Arduino that can control neopixels and servos, which I realize increases the chance of hardware interrupts that make a mess of serial coms.

Importantly the program needs to have very little latency: if the PC sends a "make the LED red" signal it needs to be parsed and usable by the Arduino very quickly, and I know protocols using strings can slow this down perceptibly.

If you were building this project would you do it on top of Firmata, or maybe a library I haven't heard of? Is there really any advantage to this, or is the USB-serial implementation already handling potential issues at a low level? What would you do to increase the chances that serial, servo, and neopixels all play nice with eachother?

I've tried successfully Processing.

CANbus. Even e-bikes are using it.

Nice looking box :+1:

What do you mean by "raw"?

It always is.

If you implement a proper protocol where the receiver has to echo received bytes before the sender sends the next one, interrupts will not (or hardly) be an issue. As sender, send one byte, wait for echo, send next byte, wait for echo etc. The receiver can send a status back once it has received and validated a complete command; e.g. OK, CRC error, OVF error. The acjnowledgement can also be done after the command has been executed if validation was successful.

I don't know anything about servos but for NeoPixels it highly depends on the number of pixels how much delay there will be.

Keep messages short, use high baudrates.

I don't know which libraries you know :slight_smile:

Because I'm reasonably familiar with serial protocols, I do roll my own. Reason is that it's easier tp maintain if I know every detail of what is going on; with a library I might have to dig through the library to understand why things don't work or it does not have the functionalities that I need.

Having said that, I'm aware of the SerialTransfer library by @Power_Broker (available in the library manager); GitHub - PowerBroker2/SerialTransfer: Arduino library to transfer dynamic, packetized data fast and reliably via Serial, I2C, or SPI. As far as I know this is the accompanying python side: GitHub - PowerBroker2/pySerialTransfer: Python package to transfer data in a fast, reliable, and packetized form.

My suggestion is to disregard everything else here and go for simplicity: Use a Teensy MCU (i.e Teensy 3.5) with built-in HID capability. This will allow your box to act as a native gamepad for your flight sim without a bunch of Python, Processing, etc in between.

On the side: How did you make the box? The instrument panel part is exquisite - do you do it in house or have it manufactured by a company?

It's my understanding that the box eventually needs to receive data as well. As far as I know it still needs a serial transfer for that? Or are there ways to achieve it with HID only?

Thank you for these responses! I was feeling a bit daunted by the idea of rolling my own robust protocol but @sterretje seeing your suggestion to just echo each byte makes sense to me, I think I can wrap my head around that and it would certainly be highly resilient. By "raw" I just meant not wrapped in any protocol, or, at least not much of one.

So far my protocol is, well... pretty simple:

void sendButtonPress(int pinNumber) {
  uint8_t message[3];
  message[0] = 1;           // First byte denotes the "button press" event, code 1
  message[1] = pinNumber;   //Second byte is the pin mumner
  message[2] = 0;           //Third byte is null, indicating end of command
 Serial.write(message, 3);  //Send all three
}

Doesn't get much easier than that! Although I suppose if you really wanted to you could pack it all into one byte. I was thinking about ways to do a checksum or parity or ACK commands... but the suggestion to just echo everything really simplifies it I think, I'll work on that now.

Regarding the HID question:

For sure agreed that HID is the easy approach but there are a few reasons the flight sim folks usually end up moving away from it: it's not great for sending analog values (for lots of sliders/dials etc), it's painful to get data back from the PC onto the panel (LEDs, servos, etc), and maybe most importantly: the Arduino MEGA won't act as a HID without mofification. I eventually intend to have lots of buttons and analog potentiopmeters, and you just can't turn down that massive number of pins, especially analog pins, on the MEGA. This is why flightsim projects like Airmanager, Mobiflight and DCSBios exist as a go-between from hardware and PC application: the helper program in the middle allows serial coms which opens up more possibilities than just emulating a keyboard/mouse/joystick.

Thanks! I'm somewhat proud of this, it's taken me years to zero in on a method that works well. Believe it or not the panel you're seeing there is just paper printed on an ordinary office laser printer, spray-glue mounted to a piece of acrylic from a dollarstore picture frame. It even backlights beautifully, because the back side of the paper was printed with a mask layer that helps occlude light in the "solid" regions. You need a good office printer that'll print a full CKYK registration black to get it to look really good, but nothing too crazy. I made a video: https://www.youtube.com/watch?v=royY2o2t3Po



1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.