A few months ago I made a BIG update to the existing CmdMessenger library. My aim was to make it into a full-featured communication library as well as adding a PC based C# counterpart. I got a lot of positive reactions and mails. In fact, a few of these mails came from a start-up that is considering to use it in a product. So thank you all!
I also got a lot of questions about existing and non-existing functionality. Looking back, the theme seems to be: more devices, more communication protocols (USB, WiFi, Bluetooth, ZigBee), etc) and more speeds.
First of all, the updated library can be downloaded here:
Or at the Github repository:
An overview of all articles on CmdMessenger can be found here:
The start-up that asked me about CmdMessenger is planning to control a quadcopter and is looking for the best way to wirelessly connect the base station to the quadcopter. While the Arduino CmdMessenger library was already prepared for different transport layers (just inject it as a stream), in the C# version the transport layer was not nicely separated from the communication protocol. I fixed this, and now you can easily create a new mode of transport and inject it in the library as long as it implements the following interface:
public interface ITransport
void Write(byte buffer);
event EventHandler NewDataReceived;
I found out that CmdMessenger is used for a large range of transmission speeds. Let’s consider the quadcopter. I’m no expert on aerial communication, but I imagine that depending on things like distance and line-of-sight, the speed may vary and even may become intermittent. At the other side of the spectrum is the Teensy 3. Like the Arduino, the Teensy 3 implements a virtual serial port over USB. unlike the Arduino, the Teensy 3 lets the serial port run on full USB speed.
Other developers discovered that the .Net implementation of the serial port is not able to cope with these speeds. To be more specific: the
NewDataReceived event that notifies us on new data in the serial port buffer, does this by polling the buffer with an interval that matches traditional serial port speeds (4800, 9600, 19200, 38400, 57600 and 115200 bit/s). Because the Teensy is that much faster (12 Mbit/sec), the buffer may overflow in between polling.
In the last version I had implemented my own
NewDataReceived event that polls the serial buffer, because the Mono implementation did not support the .NET event. I now added adaptive throttling (similar to what is described in this blog, but generalized. This means that at low communication speeds the buffer polling happens at a relatively large interval, reducing system load. If data comes in faster, the polling speeds ramps up (at the expense of a higher system load).
I have tested this with the Teensy 3, and it seems to run quite smoothly with CmdMessenger.
CmdMessenger has also become more responsive due another big change I introduced: both the send- and receive-commands are now being queued. At the request of a CmdMessenger user I wrote two small applications that have a simple user interface (DataLogging and ArduinoController ). Both worked with the previous version of command messenger, but I was not really satisfied with either of them: Using ArduinoController I noticed that when I pulled the slider that changed the blinking frequency of a led, the slider (called track-bar in .NET) moved very choppy, halting and then make a big jump. The reason is that for every
TrackBarValueChanged event a new command was issued to the Arduino and the application blocked until this was done. This is a bad thing, you should never perform time-consuming work on the user interface thread.
Instead commands the track-bar issues are now queued, and the UI thread can continue immediately after queuing them. The commands on the queue are sent in the background as fast as the Arduino can receive them. This queue uses the same adaptive throttling as the buffer polling described above.
The queue command syntax is:
void QueueCommand(SendCommand commandToSend)
The old send command still exists and the syntax has not changed. However, under the bonnet it also uses the send queue, but places the command at the front of the queue instead of at the end. This means that
SendCommand is also asynchronous and exits immediately. There is one exception to this: if you want to receive an acknowledgment from the Arduino,
SendCommand will block and wait until the command has been received or the timeout interval has expired.
SendCommand also has a new, optional argument that will clear the send queue and/or the receive queue after the command has been send. This is used int the new example TemperatureController to halt data acquisition immediately.
I also implemented a queue for receiving commands, for similar reasons. In the example of the charting application DataLogging, it may happen that the data from the Arduino or Teensy comes in faster than it can be plotted. This means that (serial) buffer will be filled faster than it is being emptied, also resulting in a buffer overflow. We solve this by getting the raw serial data out the buffer and put them as commands on the receive queue.
You may have noticed that queuing is happening on the PC side alone. The reason is that I want to keep the Arduino library as lightweight as possible, while on the PC we have memory and performance to spare. This means that issues can still arise when a connection is intermittent: The Arduino will block on sending the command, halting until data has been send. So far I have not seen this happen, but I will keep an eye out for this, and maybe at some point implement a Arduino buffer similar to the arduino-buffered-serial library.
Generally speaking, the queues are there to buffer incidental speed differences between the sending- and receiving party. However, if the speed difference is structural the queues will continue to expand and eventually grow too large, even for a PC. The only way to remedy this is by throwing away commands. This leads me to the next improvement:
The main question is: how to decide which commands to throw away? The short answer is: I don’t know.
The slightly longer answer is: I don’t know, since it depends on the application and the commands in question. Only the writer of the application knows how to deal with this.
The good thing is you can decide for yourself by using specific queue strategies.
Let me give an example: Recall the track-bar that we implemented. when we move the slider, the
TrackBarValueChanged event is called many times, resulting in a queue full of
SetBlinkFrequency commands. However, we are only interested in sending the most up-to-date (the last) blink frequency.
For this reason we can wrap the commands in a
CollapseCommandStrategy. This strategy walks through the queue, and if it finds an other
SetBlinkFrequency command, it will replace it at that position in the queue. If there is no
SetBlinkFrequency command in the queue, it will add the command to the back of the queue.
var command = new SendCommand((int)Command.SetLedFrequency,ledFrequency);
Another example, but now for the DataLogging example. If the data comes in fast than we can plot it, the queue will expand and the chart will lag more and more. To remedy this, we remove commands that have been longer on the queue than 1000 milliseconds. In this way, no matter how fast the data comes in, the lag will always be less than 1000 ms. Because we cannot wrap individual commands, we implement a general command strategy
I’ve implemented one other strategy that a command at the front of a queue:
If your situation requires its own strategy, you can easily make your own, the classes are extremely simple. The only thing you have to do is implement a function that enqueues the command, or a function that dequeues in a way that you want, or both.
The collapse strategy only overrides the default enqueue functionality:
public override void Enqueue()
// find if there already is a command with the same CmdId
var index = CommandQueue.FindIndex(strategy => strategy.Command.CmdId == Command.CmdId);
if (index < 0)
// if not, add to the back of the queue
// if on the queue, replace with new command
CommandQueue[index] = this;
CmdMessenger Arduino updates
On the Arduino side I only made two small updates. My thanks go to Nate who suggested these changes
1. Added the ability to send longs:
2. Added the ability to see if the last argument fetched is well formed:
In the last few weeks I have been working on an Arduino based thermostat. It uses a K type thermocouple and a MAX31855 / Max6675 breakout board to measure temperature, a Solid State Relay to turn a heater on and off, and a PID controller implementation to steer the temperature optimally (no overshoots) to the goal temperature. My personal aim is to update update or Gaggia Classic espresso machine with temperature stabilization, but this sample set up to be so generic that you can use it for everything: brewing beer, controlling a clay oven, etc.
I recommend starting simple. I bought a simple 10 euro electric water boiler, put the relay in the power cable, en let the thermocouple hang in the water.
So now to the program. I plan to write a detailed how to later on, so for now just a short description.
With the trackbar the goal temperature is changed, which is queued to be sent to the Arduino. The top chart shows a scrolling chart of the measured temperature and the goal temperature. The bottom chart shows the control value of the heater, with a value between 0 and 1.
Since the the heater is controlled using a solid state relay, it can only be turned on or off. In order control the heater power we modulate the power. Below is a representation of such a Pulse Width Modulated signal with changing duty cycles
We have set our duty cycle time to 3s, in order not switch too often, and we let the PID controller control duty cycle percentage. The resulting PWM cycle is also shown in the bottom chart.
The library is now flexible enough to work with different hardware platforms, and I would really like to try this out for more platforms. As said before, the library is already running nicely on a Teensy 3. The next step is getting it to run on a wireless device such as the Flutter , Spark Core or RFDuino. Who knows, I might get sponsored