WPF Data Binding to physical objects (updated)
I had some spare time tonight, so I thought I'd have a go at controlling a small servo I had lying around using an Arduino Uno. That was pretty easy (it is explained on the Arduino website over here), so I decided to take it a step further. What about writing a .NET application that can control the servo? Right, Windows Forms? Nah... boring... WPF! And to make the code nice and shiny, let's use data binding.Here is a picture:
What does this take?
A little bit of code on the Arduino that listens for commands to change the servo position on the serial interface.
A .NET class that represents the physical servo, which has a "Position" property (to which we can data bind) and which sends out a command on the serial port when the position changes.
Let's now use this class to data bind the position of a slider control to the position of the physical servo:The XAML:
Side note: for some reason my little servo does not like to go below 30 degrees, that is why the minimum of my slider is 30, you might want to set that to 0.The C# code:
Of course there are a million other ways to do this and there is a lot of room for improvement, but I find it quite remarkable that it can be done in such an elegant way and with so little code.
Update 14/06: After posting this yesterday, fellow MSP François Remy remarked that it would be nice if it worked both ways. If there is logic running on the Arduino that decides to change the position of the servo, then the data bound slider should update as well. He was of course absolutely right! I have updated the code to add this functionality. The Arduino now sweeps the servo from left to right continuously and sends the position to the pc over serial. When the pc sends a position over serial to the Arduino, this overrides the sweep for 1.5 seconds. In other words, the Arduino listens to the pc, until it hasn't received a new position for 1.5 seconds, then it continues the sweep.Here is a video: The code for the Arduino: And the C# Servo class:
As you can see, I have implemented INotifyPropertyChanged (refer to this) and used async/await instead of having to deal with threads (refer to this). Although this adds some complexity, the Servo class is still fairly straightforward.
Also worth noting: the Arduino resets the ATMega when a serial connection is opened. This is useful when using the Arduino software to program it (a reset causes the bootloader to run), but kind of annoying when writing an application that uses serial communication. I have disabled the auto-reset by cutting the trace between the pads labeled RESET-EN on the PCB using a Stanley knife. If you prefer a less destructive method: refer to this forum thread.