Nearly two years has passed since I wrote the article that introduced Johnny-Five as a new way to program Arduino microcontrollers with JavaScript on Node.js. In those two years a lot of exciting things have been created, despite the potentially restrictive paradigm that Johnny-Five programs exist in. The underlying Firmata platform protocol forces Johnny-Five programs to follow a host/client model: the JavaScript that you write is not executed on the target devices directly; instead, a controller program sends messages to the Arduino.
This has never been an impediment to the success of projects I’ve created with Johnny-Five; which range from trivial input/output demonstration to objectively non–trivial 2, 3, 6, and 12 degree of freedom bipedal and quadrupedal robots. Regardless, all of these projects remain tethered – by cable or wifi signal – to a host machine.
What if JavaScript could run in a full Node.js environment directly on the board and harness the massive eco-system of open-source shields and components that make Arduino UNO such a richly attractive platform? The Espruino and Tessel projects focus on creating ARM based, low-power, JavaScript programmable boards, however neither offers a Node.js JavaScript runtime or the UNO form factor. Raspberry Pi and BeagleBone Black provide a Linux OS with a complete Node.js installation, but both devices deviate from the UNO form factor.
Enter the Intel Galileo.
The Intel® Galileo board is a microcontroller board based on the Intel® Quark SoC X1000 application processor, a 32-bit Intel® Pentium® brand system on a chip (SoC). It is the first board based on Intel® architecture designed to be hardware and software pin-compatible with shields designed for the Arduino Uno* R3.
As the image above shows, the Galileo provides an UNO compatible form factor. For a simple comparison, the following table contains very basic data points for each of the boards mentioned:
Board | JS Environment | JS Runtime | UNO Form Factor |
---|---|---|---|
Rasberry Pi | Node.js | v8 | No |
BeagleBone Black | Node.js | v8 | No |
Espruino | Espruino | Espruino JavaScript | No |
Tessel | Node.js | Embedded Lua runtime | No |
Galileo | Node.js | v8 | Yes |
Teaching Johnny-Five to speak GPIO
Until now, Johnny-Five has relied on the Firmata protocol to communicate over a serial connection. Now that we can run JavaScript programs directly on the board, the Firmata + SerialPort dependency must be replaced with a layer that is observably identical in API and semantics, however implemented to communicate with the board via native GPIO sysfs.
(At this time, those that wish to actually follow along with their Galileo should read through Sparkfun’s Galileo Getting Started Guide or ROS.org’s Intel Galileo initial Yocto image install. To setup wireless networking, I followed Sergey Kiselev’s Intel Galileo Meets Wireless.)
A thorough overview of GPIO is out of scope for this article, but I highly recommend another article by Sergey Kiselev: Intel Galileo – Programming GPIO From Linux. In the simplest terms, GPIO programming can be described as a series of filesystem IO operations. Here’s a simple example of how programming GPIO looks:
#!/bin/bash
# Initialize the port for output:
echo -n "3" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio3/direction
# Turn the on-board Led on:
echo "1" > /sys/class/gpio/gpio3/value
# Now turn it off:
echo "0" > /sys/class/gpio/gpio3/value
In order to teach the Johnny-Five framework how to speak GPIO, we first introduced a plugin mechanism that will allow user code to specify a custom IO layer. Johnny-Five IO Plugins provide a mechanism to override the the default Firmata + SerialPort IO system with a custom “translation” layer that implements the specified interface. The interface protocol defines a minimal API surface with corresponding semantics to enable “drop-in” replacement. As long as the interface contract is fullfilled, the following two examples must produce the same result:
var Board = require("firmata").Board;
var board = new Board("/dev/path-to-device");
board.on("ready", function() {
var byte = 1;
var pin = 13;
this.pinMode(pin, this.MODES.OUTPUT);
setInterval(function() {
this.digitalWrite(pin, (byte ^= 1));
}.bind(this), 500);
});
// This file executes ON the board!!
var Plugin = require("plugin-io");
var board = new Plugin();
board.on("ready", function() {
var byte = 1;
var pin = 13;
this.pinMode(pin, this.MODES.OUTPUT);
setInterval(function() {
this.digitalWrite(pin, (byte ^= 1));
}.bind(this), 500);
});
At the Johnny-Five level:
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// ...
});
var five = require("johnny-five");
var Plugin = require("plugin-io");
var board = new five.Board({
io: new Plugin()
});
board.on("ready", function() {
// ...
});
Galileo-IO
Galileo-IO is both a standalone module and a Johnny-Five IO Plugin. The module is still in its early stages but implements enough of the IO Plugin protocol to support a large class of both existing or new Johnny-Five programs. In practice, this means these two programs produce the same result:
var five = require("johnny-five");
var board = five.Board();
board.on("ready", function() {
new five.Led(13).blink(500);
});
// This file executes ON the board!!
var five = require("johnny-five");
var Galileo = require("galileo");
var board = five.Board({
io: new Galileo()
});
board.on("ready", function() {
new five.Led(13).blink(500);
});
Now that Johnny-Five is capable of on-board execution applications, I’m excited to see what users build. As of this writing, Johnny-Five IO Plugins for BeagleBone Black, Raspberry Pi, and Spark Core (Spark-IO is host/client) are in development. Earlier this month, linino.org published a guide to installing Node.js and Johnny-Five for the Arduino Yún – a great opportunity to create a IO plugin. Once the Arduino Tre and Intel Edison become available, we will work to prepare plugins for these platforms as well.
UPDATE
Since publishing this article, several IO Plugins have been contributed by members of the Nodebots community, a list is available here: Johnny-Five IO Plugins