After getting the automatic chicken door working (see my previous Forum post), I decided to try something I've want to do for a long time: to be able to use my favorite software development tool to create "control panels" to remotely control an Arduino. "Remote" is relative: for now, it means via a serial port and N inches/feet of wire. Eventually I hope to work my way up to doing it with Zigbee or Bluetooth...
So I have a software tool (called LiveCode) that lets me build GUI interfaces and talk to a serial port with very, very few lines of easy-to-understand code. I plan to offer an intro class in LiveCode very soon. For now, if you'd like to see what it's about, check:
http://runrev.comOn my laptop, I created a small control panel to turn an LED on/off or make it blink at a user-selectable rate:

I then defined a set of command-strings to send over the serial port:
"0"= LED off
"1"= LED on
"Bnnnn" = blink the LED every nnnn milliseconds
And finally I wrote and debugged (and debugged...) the Arduino sketch to read the command-strings, parse them, and execute them:
Code:
// Remote control of an LED via the serial port
// Larry Walker 11/14/10
// turn an LED on/off according to input from the serial port
// received char = 0 means turn LED off
// received char = 1 means turn LED on
byte incomingByte = 0; // for incoming serial data
int delayVal = 0; // duration of blink, in millis (0 means no blinking in effect)
int delayCnt = 0; // counter to step through the delayVal
int blinkState = LOW; // state variable for blinking LED
const int LED1 = 13; // define pin for LED1
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
// initialize the digital pin as an output.
// Pin 13 has an LED connected on most Arduino boards:
pinMode(LED1, OUTPUT);
}
void loop() {
// see if there's a command waiting
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.print(incomingByte, BYTE);
// decide what to do to the LED
switch (incomingByte) {
case '0':
// turn the LED off when command equals ascii 0
digitalWrite(LED1, LOW);
Serial.println(" turning LED off...");
delayVal = 0; // suppress any pending blinking
break;
case '1':
// turn the LED on when command equals ascii 1
digitalWrite(LED1, HIGH);
Serial.println(" turning LED on...");
delayVal = 0; // suppress any pending blinking
break;
case 'B':
// start blinking the LED when command equals ascii B
// suck up the delay value
delayVal = 0;
while (Serial.available() > 0) {
// read the next incoming byte:
incomingByte = Serial.read();
if ((incomingByte >= '0') && (incomingByte <= '9')) {
delayVal = (10*delayVal) + (int(incomingByte) - '0');
}
}
delayCnt = 0;
Serial.print(" blinking LED every ");
Serial.print(delayVal, DEC);
Serial.println(" ms...");
delayCnt = delayVal-1; // suppress any pending blinking
break;
default:
// if nothing else matches, do the default
Serial.print(" Invalid command!");
} // end of switch (incomingByte)
} // end of if (Serial.available)
else
{
// no incoming command, see if we need to do blinking thing
if (delayVal != 0) {
// we have a delayVal, so we're blinking
delayCnt++;
// time to toggle the LED?
if (delayCnt == delayVal) {
blinkState = !blinkState;
digitalWrite(LED1, blinkState);
delayCnt = 0; // restart the delay period
} // end of if (delay expired)
} //end of if (delay in effect)
delay(1);
} // end of else see about blinking
} //end of loop
Short video of the pair of apps working together:
http://walkerphotographix.com/vidclips/remote_LED.movI know I need to do some serious refactoring before it's a general-purpose tool, like learning more about Arduino C's string handling libraries so I can parse a more complex command syntax...
So what's it good for?
I want to be able to do this for two general cases:
1) to make an "operator's console" to control a complex Arduino project (permanently connected)
2) to make a "maintenance console" to tweak/calibrate/configure even a simple Arduino project (occasionally connected)
One last detail: if you've ever tried to program GUIs (graphic user interfaces) in conventional languages, you know what a pain it can be and you won't believe how painless LiveCode is. I wrote zero lines of code to build the GUI itself: I just dragged & dropped 5 Button objects, 2 Label objects and a Slider object from a tool palette, positioning them where I wanted them with no long gnarly create_object() calls or set_object_position() calls.
The code to send the messages to the Arduino was almost laughably short and simple. The messiest were the code for the Open Port and the Blink LED objects:
Open Port:
Code:
global usbSerial
on mouseUp
open driver usbSerial for binary update
enable button "Close Port"
enable button "LED On"
enable button "LED Off"
enable button "Blink LED"
disable me
end mouseUp
Blink LED:
Code:
global usbSerial
on mouseUp
enable field "delayLabel"
enable scrollbar "Delay"
enable button "LED On"
enable button "LED Off"
put the thumbPosition of scrollbar "Delay" into delayVal
write "B" & delayVal & return to driver usbSerial
end mouseUp
Notice that over half the lines of code are mostly showing off: they just control which buttons are dimmed when they aren't appropriate (i.e. it doesn't make sense to let the user click LED On until the port has been opened). Without that feature, the actual working code is 2 executable lines per object...
Whew! That was the most software fun I've had in years!
I'll be demo'ing this app and the chicken-door prototype at the December Sector67 meeting, if you have any questions...
Larry Walker