How to Program an Arduino with JavaScript

Introduction

As you probably know (or have heard), Arduino is a great platform to learn and hack on electronics that would otherwise be very difficult to use for a beginner. Its a great introduction in to programming, electronics, and engineering in general. But even then, as much of an improvement as Arduino is over the traditional way of working with electronics, it can still be a little daunting writing the C-like code. So what if you could use a higher-level language like JavaScript instead?

With languages like JavaScript, you don't need to worry about the low-level details of things like pointers and memory allocation, which can be confusing for beginners. Instead, you get to focus on the application logic and utilize the hundreds of thousands of open source libraries to give your project all kinds of functionality with just a few lines of code.

Johnny Five

The Johnny Five library is what allows you to control an Arduino (or Raspberry Pi, Beaglebone, Photon, and many more) with JavaScript.

Now, like many good things, there is a small catch. The JavaScript code doesn't actually run directly on the Arduino, it actually must run on a host computer, and communicate its instructions at run-time to the device via a USB cable, or some other serial protocol/medium. For some applications, this is a deal-breaker since they can't have this physical tether on their project (like on a drone), but for others it might not be a big deal. For example, if all you need to do is control a robotic arm on your desk, Johnny Five might just be the perfect fit. After all, it's main focus is on robotics, hence the name.

The library works by taking advantage of the Firmata protocol, which is a way for communicating with microcontrollers from software on a host computer (or smartphone/tablet, etc). This means you can run all of the program logic on your computer, but any time you need to do any IO on the device like read a GPIO pin, send data over SPI, etc., the desktop program will use the Firmata protocol to tell the Arduino to perform the specific IO.

The code below, for example, just blinks the LED on pin 13. So the only time it communicates with the Arduino is when it wants to turn the LED on or off, otherwise the Arduino just sits there and waits to receive instructions from the host computer.

var five = require('johnny-five');

var board = new five.Board();

board.on('ready', function() {  
    var led = new five.Led(13);
    led.blink(500);
});

To run it, you must first load the Arduino Firmata code on to the board. Do this by opening the Arduino IDE, and then clicking File->Examples->Firmata->StandardFirmata. This will open the code in the editor window. Finally (assuming your board is connected via USB), click Upload.

To run the Johnny-Five portion of the code, navigate to the project's directory, make sure you've run npm install, and then run node index.js, assuming the file is named index.js.

The nice thing about Johnny Five is that, in typical Node fashion, there is a library for just about everything. They author has already written all the code you need to do typical robotics tasks, like turn motors, read sensor inputs, interface with communication devices, and more. You can find a huge list of useful examples here.

Example: Johnny Five + Arduino + Hacker News

This example has a nice mix of high level API programming, like you'd see in a typical Node app, as well as some Johnny Five code to help interface with an LCD screen. I thought it would serve as a good example to show you how two very different platforms can work together.

The project I created retrieves the top 10 links from Hacker News and displays them on an LCD screen controlled by an Arduino Uno.

I started off by using the request-promise library and Hacker News' API to retrieve the titles for the top 10 links (or 'stories' as they call them), which is returned as an array.

var util = require('util');  
var Promise = require('bluebird');  
var request = require('request-promise');

var topPostsLink = 'https://hacker-news.firebaseio.com/v0/topstories.json';  
var storyLinkTemplate = 'https://hacker-news.firebaseio.com/v0/item/%s.json';

var retrieveHnTitles = function() {  
    return request(topPostsLink).then(function(json) {
        var ids = JSON.parse(json);
        ids = ids.splice(0, 10);

        var storyRequests = [];
        ids.forEach(function(id) {
            var storyUrl = util.format(storyLinkTemplate, id);
            storyRequests.push(request(storyUrl));
        });

        return Promise.all(storyRequests);
    }).then(function(stories) {
        stories = stories.map(JSON.parse);

        var titles = stories.map(function(story) {
            return story.title;
        });

        return titles;
    }).catch(console.error);
};

When the board event 'ready' triggers we call the above function, construct a string containing all the titles from HN that we just received, and then send it to the LCD using the built-in Johnny-Five LCD functions.

board.on('ready', function() {  
    var lcd = new five.LCD({ 
        controller: 'PCF8574'
    });

    retrieveHnTitles().then(function(titles) {
        var titlesString = '';
        for (var i = 0; i < titles.length; i++) {
            var title = titles[i];
            var spaces = '';
            if (title.length > 32) title = title.substring(0, 29) + '...';
            if (title.length < 32) spaces = new Array(32 - title.length + 1).join(' ');
            titlesString += title + spaces;
        }

        lcd.autoscroll().print(titlesString);
    });
});

The autoscroll() function is very convenient here since we have such a long string. The top 10 story titles should scroll across you the screen, with only one story on the screen at a time.

HN Links on LCD Screen The top 3 HN link titles from 9/19/15.

If I were to put some more effort in to the project, the next thing I might do is schedule this to run every 5 or 10 minutes using the cron library. That way you don't have to run it manually (which kind of defeats the purpose). Another thing you might want to do is show the number of upvotes each link has, or maybe number of comments. But then you might need to get a larger screen :)

Troubleshooting

Whenever you're programming with hardware, things don't always go as smoothly as they do with a higher level server or desktop application (and even then there is a lot of troubleshooting), so I thought it would be helpful to provide some help to the most common problems people face. If you get an error when you first run the program (can't connect or connection timeout), then try one of these solutions.

Did You Load the Firmware?

As simple as this sounds, I've made this mistake a few times myself. I would try to run a Johnny Five application, just to realize that it won't connect because I forgot to load the Firmata firmware on to the Arduino. When switching between projects often, I run in to this a lot, and it's usually the first thing to consider when you can't connect with a device.

Is Your Hardware Supported?

The first time I ever tried to use Johnny Five I was using an Arduino Duemilanove and I kept getting a "Connection timed out" error. After some basic troubleshooting, I finally checked the compatibility list to see that the Duemilanove was not listed. I had thought since it is so similar to the Uno it would work, but apparently not.

Are You Using Windows?

Yes, Windows is supported, however, sometimes Windows systems will fail to compile the native dependencies. To fix this, try installing Johnny Five with the following command:

npm install johnny-five --msvs_version=2012  

Build it Yourself

This is a fairly cheap project to build yourself. Here is the parts list of everything I used:

  • Arduino Uno
  • LCD Screen (2x16, I2C)
  • Male-to-Female Dupont Wires
  • USB Type-A to Type-B cable

You can probably get away without buying the Dupont wires as long as you have some other simple wire sitting around and a way to strip the plastic casing on each end. I just listed these since they're more convenient.

You can also use a different LCD screen, but only the PCF8574, PCF8574A, and JHD1313M1 I2C-to-parallel controllers are officially supported by Johnny Five. Depending on the I2C implementation, other controllers may work as well.

Conclusion

Hopefully from this article and the examples I've shown you have a better idea as to what is possible using Johnny Five/JavaScript with Arduino, Raspberry Pi, Beaglebone, etc. Sure, C/C++ may dominate the field of embedded electronics, but with libraries like Johnny Five and the Firmata protocol you can easily dive in using familiar tools and prototype even faster than before.

Be sure to head over to the Johnny Five documentation to learn more. There are some great tutorials and troubleshooting guides for when you get stuck.

Are there any projects or examples you'd like to see made with Johnny Five? Let us know in the comments!