A few weeks ago I wrote a post on how to use an Arduino to control a DC motor’s speed and direction as part of an on-going project of building a WebRTC controlled webcam.
This week we’re taking that same build to the next level by adding the ability to control last week’s build remotely, and in real-time, using WebRTC.
This IOT project will consist of a client coded on Electron (previously atom shell), and a NodeJS server to handle communications with PubNub’s implementation of WebRTC tying it all together.
By dragging a slider left or right on our client, we’ll send to the server the direction in which the motor should spin, and depending on how far from the center of the slider we go, it will determine the speed value we will send to the server as well.
For our server to be able to communicate with the Arduino board we are going to need a NodeJS library which allows for such abstractions, luckily, there’s an npm package called Johnny-Five which does just that.
Test code for Johnny-Five in NodeJS
To get started, as a proof of concept, I took the Arduino code I had originally used in Part I of this project and translated it into Johnny-Five.
This is what the original code looked like:
And after some trial and error I ended up with this code based on Johnny-Five’s API:
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
//pin 8 = direction
//pin 11 = enable
this.pinMode(8, five.Pin.OUTPUT);
this.pinMode(11, five.Pin.PWM);
back_n_forth(this);
});
function back_n_forth(target_board){
target_board.digitalWrite(8, 1);//forward
target_board.analogWrite(11, 30);//~12% PWM
target_board.wait(2000,function(){
target_board.analogWrite(11, 0);//turn enable pin off
target_board.wait(1000,function(){
target_board.digitalWrite(8, 0);//backward
target_board.analogWrite(11, 30);//~12% PWM
target_board.wait(2000,function(){
target_board.analogWrite(11, 0);//turn enable pin off
target_board.wait(1000,function(){
back_n_forth(target_board);//loop
});
});
});
});
}
It’s worth noting that Johnny-Five’s abstraction deviates quite a bit from Arduino’s original API. Especially the way loops are treated. In Johnny-Five, loops are more like intervals in that they have a set time in milliseconds for each iteration, which is why I ended up using this tree-like wait
structure.
In order to run the previous code, simply save it as back_n_forth.js
and from your console, in the directory where the file is saved run the following:
npm install johnny-five
node back_n_forth.js
Just as in the previous installment of this tutorial, you should see this:
Arduino controller server using NodeJS and PubNub’s WebRTC SDK
I have used PubNub’s implementation of WebRTC in a few projects before, including my Applying Effects to WebRTC Video in Real Time tutorial.
The original SDK can be found at:
In order to use it with NodeJS for this project I had to go ahead and make the following npm package:
https://github.com/jeanlescure/node-pubnub-webrtc
To get started creating our NodeJS server we’ll need the following files:
package.json
server.js
In our package.json
we’ll need at least the following:
{
"name": "WebRTC-Arduino-Motor-Server-Demo",
"version": "0.0.1",
"description": "Some description...",
"dependencies": {
}
}
Here’s a pretty neat interactive guide to package.json
files.
And to add the dependencies to our package we run:
$ npm install --save johnny-five
...
$ npm install --save node-pubnub-webrtc
Now that we are sure that our package and its dependencies are good to go we move on to the server.js
file:
First we instantiate our webrtc PubNub phone:
var phone = require('node-pubnub-webrtc')({
number : 'pubduino.server',
publish_key : PUBLISH_KEY,
subscribe_key : SUBSCRIBE_KEY,
ssl : true
});
Next we need access to the arduino board, so just as before, using johnny-five:
var five = require("johnny-five");
var board = new five.Board();
A couple of global variables to communicate speed and direction between the phone
and the board
:
var direction = 0;
var speed = 0;
Here’s the code for the board where we see how easy it is to digest the direction and speed values:
board.on("ready", function() {
//pin 8 = direction
//pin 11 = enable
this.pinMode(8, five.Pin.OUTPUT);
this.pinMode(11, five.Pin.PWM);
board.loop(250,function(){
board.digitalWrite(8, direction);
board.analogWrite(11, speed);
});
});
And to add the cherry on top of our server code, the WebRTC implementation which grabs the direction and speed values off of a JSON we’ll be sending using the RTCDataChannel
:
phone.message(function(session, message){
has_direction = (typeof message.direction !== 'undefined');
has_speed = (typeof message.speed !== 'undefined');
if (has_direction && has_speed){
if (message.speed >= 0 && message.speed <= 255){
direction = (message.direction) ? 1 : 0;
speed = message.speed;
}
}
});
Easy as pie!