A few months ago I started this thread to show the changes I made to the CmdMessenger library. I got a lot of positive reactions on my blog as well as a lot of e-mails. Thanks for your support!
I also got a lot of questions about existing and non-existing functionality. I implemented a lot of new stuff, around the themes: support for more devices, more forms of communication and support for a wider range of speeds.
You can still download the library here:
http://thijs.elenbaas.net/downloads/?did=9
Or at the Github repository:
https://github.com/thijse/Arduino-Libraries/tree/master/CmdMessenger
And find a more detailed explanation of the changes here
http://thijs.elenbaas.net/2013/11/arduino-to-pc-messaging-more-devices-protocols-speeds/
and
http://thijs.elenbaas.net/2013/09/arduino-to-pc-messaging/
Transport Layers
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, if it implements the following interface:
public interface ITransport
{
int BytesInBuffer();
byte[] Read();
bool StartListening();
bool StopListening();
void Write(byte[] buffer);
event EventHandler NewDataReceived;
}
Communication speed
I was contracted by a company that wants to use the library in a quadcopter. I'm no expert on arial 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 speed spectrum is the Teensy 3. Like the Arduino, the Teensy 3 implements a virtual serial port over USB. However, unlike the Arduino, the Teensy 3 lets the serial port run on full USB speed (12Mbit/s). For this reason I added adaptive throttling (similar to what is described in this blog). 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 of a friend, and it seems to run quite smoothly with CmdMessenger. Sorry, no benchmarks yet.
Command Queues
CmdMessenger has also become more responsive due another significant change I introduced: both the send- and receive-commands are now being queued.
In my previous post I introduced two small applications with a simple GUI (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 moved very choppy, halting and then make a big jump. The reason is that, for every slider movement an event is raised that issues a new command the Arduino. This happened in the GUI thread, and the GUI blocked until this was done.
In the new version the commands that are generated when the slider is moved are now queued, and the UI thread can continue immediately after putting them on the queue . The commands on the queue are sent in the background as fast as the Arduino can receive them. I also implemented a queue for receiving commands, for similar reasons as explained in my blog post.
Queue strategies
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, or by even writing your own.
Let me give an example: recall the slider that changes the blink frequency. when we move the slider, the "SliderValueChanged" event is called many, 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 so-called "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.
The usage is simple:
var command = new SendCommand((int)Command.SetLedFrequency,ledFrequency);
_cmdMessenger.QueueCommand(new CollapseCommandStrategy(command));
For more examples of strategies that throw away stale commands, put commands at the front of the queue instead of at the back, have a look at my blogpost http://thijs.elenbaas.net/2013/11/arduino-to-pc-messaging-more-devices-protocols-speeds/
CmdMessenger Arduino updates
On the Arduino side I two small updates. My thanks go to Nate who suggested these changes
- Added the ability to send longs:
long readLongArg()
- Added the ability to see if the last argument fetched is well formed:
isArgOk()
TemperatureController example
I also added an actually useful sample of a PC controlled, 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, spliced the power cable and inserted the solid state relay and let the thermocouple just hang in the water.
With the trackbar the goal temperature is changed. Also here, every slider change queues a command 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 need to 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.
Next steps
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.