Introduction
Since I got my Spark Core, I've been fiddling without really knowing what I wanted to do with it. Lately, I've also been playing with my Rapiro again, and that's when I got the idea to build a physical controller for the robot, with at its heart a Spark Core.
The controller would be used to send different MQTT messages depending on which button was pressed. Rapiro (or any other IoT device, really) would be configured with a MQTT client and would be able trigger certain actions based on the received messages.
This post is about building the controller and performing some initial tests.
Prototype
Yesterday evening, I started browsing my different bins of parts to find the necessary components to build the controller I had in mind. The list of required components was the following:
- Spark Core
- prototyping board
- pushbuttons (14)
- 1x12 female header (2)
- 4xAA battery pack
Having found everything I needed, I proceeded by laying out the different components on the prototyping board. Luckily enough, everything fit and I moved on to soldering all the buttons and making the connections.
The layout is pretty basic:
- centrally, the Spark Core with the RGB LED used to display status information
- on the left, five buttons which can be used for movement actions
- on the right, nine buttons which can be used for various functions
Code
For the code, I used Chris Howard's port of Nick O'Leary's PubSubClient for Arduino, combined with my sketch below. I've added comments in the code, so it should be clear what I'm trying to achieve, but to summarise:
- every pin is set as an input which is HIGH by default, using an internal pull-up resistor
- pressing a button will pull the pin down to ground, setting it LOW
- the onboard RGB LED is used to display status information:
- red: not connected to MQTT broker
- green: connected to MQTT broker
- blue: button is being pressed
- check if connected to broker, if not: reconnect
- check if button is pressed, if yes: publish MQTT message
int BTN_A0 = A0; int BTN_A1 = A1; int BTN_A2 = A2; int BTN_A3 = A3; int BTN_A4 = A4; int BTN_A5 = A5; int BTN_A6 = A6; int BTN_A7 = A7; int BTN_D0 = D0; int BTN_D1 = D1; int BTN_D2 = D2; int BTN_D3 = D3; int BTN_D4 = D4; int BTN_D5 = D5; int BTN_D6 = D6; int BTN_D7 = D7; long lastRetry = 0; TCPClient tcpClient; PubSubClient client("iot.eclipse.org", 1883, 0, tcpClient); void setup() { // onboard RGB LED will be used RGB.control(true); // use internal pull-ups, all pins HIGH by default pinMode(BTN_A0, INPUT_PULLUP); pinMode(BTN_A1, INPUT_PULLUP); pinMode(BTN_A2, INPUT_PULLUP); pinMode(BTN_A3, INPUT_PULLUP); pinMode(BTN_A4, INPUT_PULLUP); pinMode(BTN_A5, INPUT_PULLUP); pinMode(BTN_A6, INPUT_PULLUP); pinMode(BTN_A7, INPUT_PULLUP); pinMode(BTN_D0, INPUT_PULLUP); pinMode(BTN_D1, INPUT_PULLUP); pinMode(BTN_D2, INPUT_PULLUP); pinMode(BTN_D3, INPUT_PULLUP); pinMode(BTN_D4, INPUT_PULLUP); pinMode(BTN_D5, INPUT_PULLUP); pinMode(BTN_D6, INPUT_PULLUP); pinMode(BTN_D7, INPUT_PULLUP); // wait for wifi to be ready while( !WiFi.ready() ){ // wait } } void loop() { // check if connected to MQTT broker // only retry every 5 seconds, don't bash the broker if(!client.connected() && (millis() - lastRetry) > 5000) { // set last retry to now lastRetry = millis(); // not connected, turn LED red RGB.color(255, 0, 0); // connect to MQTT broker if (client.connect("SparkCoreController")) { // connected, turn LED green RGB.color(0, 255, 0); // send notification about connection client.publish("SparkCoreController/Init", "Connected to broker."); } } else { client.loop(); // check which buttons have been pressed buttonPressed(BTN_A0, "SparkCoreController/Command", "DOWN"); buttonPressed(BTN_A1, "SparkCoreController/Command", "LEFT"); buttonPressed(BTN_A2, "SparkCoreController/Command", "UP"); buttonPressed(BTN_A3, "SparkCoreController/Command", "STOP"); buttonPressed(BTN_A4, "SparkCoreController/Command", "RIGHT"); buttonPressed(BTN_A5, "SparkCoreController/Command", "F9"); buttonPressed(BTN_A6, "SparkCoreController/Command", "F8"); buttonPressed(BTN_A7, "SparkCoreController/Command", "F7"); buttonPressed(BTN_D0, "SparkCoreController/Command", "0"); buttonPressed(BTN_D1, "SparkCoreController/Command", "F6"); buttonPressed(BTN_D2, "SparkCoreController/Command", "F5"); buttonPressed(BTN_D3, "SparkCoreController/Command", "0"); buttonPressed(BTN_D4, "SparkCoreController/Command", "F4"); buttonPressed(BTN_D5, "SparkCoreController/Command", "F3"); buttonPressed(BTN_D6, "SparkCoreController/Command", "F2"); buttonPressed(BTN_D7, "SparkCoreController/Command", "F1"); } } void buttonPressed(int button, char topic[], char command[]) { // if button has been pressed if(digitalRead(button) == LOW) { // button pressed, turn LED blue RGB.color(0, 0, 255); // publish the command to the provided topic client.publish(topic, command); // wait a little delay(250); // turn the LED back to green RGB.color(0, 255, 0); } }
Demo
Here's a short video with a brief explanation of the controller, followed by a demo:
Next Steps
I'll probably have this circuit made properly by designing a simple PCB for it. And using my 3D printer, I should be able to make a proper enclosure and buttons for it as well.
Any suggestions for improvements are welcome!