Matt Hughes i like to grow tiny trees and tinker on stuff

Serial communication with Node.js and Arduino

I recently came across ServoMeter, a project that monitors API performance with an Arduino. It was pretty similar to a project I have been wanting to build myself, so I was very interested!

I noticed in the bill of materials that there wasn't an ethernet or wifi component, which intrigued me. With my pretty limited Arduino experience, I did not realize that you could use a different device to connect to the internet, and send data to the Arduino over the USB connection. This changed everything for me!

I used Jacob's example code and the node-serialport examples as a starting point for my development. The serialPort examples on GitHub worked, but unfortunately there was not much explanation why or how they worked. I hope that my findings might help someone else out.

Here is an extremely basic proof of concept that sends data from node.js to an Arduino via serial-over-USB. This example only sends data from Node.js to Arduino, not vice versa. Two-way communication is possible, but necessary for my project.

Arduino sketch

const int ledPin = 13;
String incoming = "";

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  while (Serial.available()) {          
      digitalWrite(ledPin, LOW); //LED on while receiving

    incoming = Serial.readString();
    Serial.println(incoming);
  }

  digitalWrite(ledPin, LOW); //LED off while not receiving
}

If you are developing on OSX or Linux, you can use the terminal command screen to monitor the node.js output as well:

screen /dev/ttyUSB0 9600

The only caveat to using screen instead of the Arduino serial monitor is that I had to run my node script with sudo. I assume this is so the script has permission to access the serial port being used by screen, but I'm not 100% positive.

node.js script

var serialPort = require("serialport");
var SerialPort = require("serialport").SerialPort;

var sp = new SerialPort("/dev/ttyUSB0", {
      baudrate: 9600
}, false);

console.log("Starting up serial host...");

var message = "DATA GOES HERE";

function write() {
    sp.open(function(err) {
        console.log("Writing serial data: " + message);
        sp.write(message, function(err, res) {
                if (err) { console.log(err); }
                sp.close();
        });
    });
}

setTimeout(write, 1000); //wait 1s for everything to initialize correctly
setInterval(write, 5000); //write data every 5s

You will need to install serialport with npm to run this script:

npm install serialport

I ran into a lot of trouble with only one or two random characters showing up in my Arduino serial monitor, until I finally figured out the problem. The sp.close() line is the key! Without closing the serial connection, the data sent over the serial connection gets garbled.

Serial output without sp.close():

DATA DDDDDDDDDA DDDREDDDDDDDDDDDDDDDDODDGODDDGD DEEODD DHD
DDDD
DDDED
DDEDRD
DD
DDD
DDSDDDDDDDDDDDEDD
D DH DHD
DD
DDDADODDD DAD
DDDATA

Serial output with sp.close():

DATA GOES HERE
DATA GOES HERE
DATA GOES HERE
DATA GOES HERE
DATA GOES HERE
DATA GOES HERE
DATA GOES HERE
DATA GOES HERE

So there you have it... now you can send whatever string-like data you want from node.js to your Arduino!

Get the source code for yourself at GitHub.