Blynk + Node.js + Johnny-Five: drive a Pan-Tilt PTZ SG90 kit on Orange Pi with an Arduino / Firmata

In the previous tutorial, we saw how to replace the GPIO of the Orange Pi with an Arduino (using the Firmata firmware) and then how to create a Javascript script to drive a Led from a smartphone with the Blynk and Johnny-Five library. In this tutorial we will implement a new method to drive a PTZ articulated system based on servo motors.

Reminder of previous episodes and presentation of the project

We have already seen several methods of driving a Pan-Tilt system based on SG90 servo motors:

In this new tutorial, we will use an Arduino/Firmata which will replace the GPIO of the Orange Pi, which is fishing because of its lack of successful libraries to manage the GPIO. For this we will develop a script in Javascript which will be executed by Node.js. We will use the Johnny-Five library (all articles on Johnny-Five) as well as the Blynk bookstore for Node.js. The Blynk library will link the mobile application to the local (or official) Blynk server and the Node.js. The Johnny-Five library will be used to control the actuators of the Pan and Tilt axes. Here is a small diagram that summarizes the architecture of the project.

blynk nodejs johnny-five orangepi arduino firmata ptz pan tilt kit layout

A short video preview

Matériel nécessaire

Suivez ce guide étape par étape pour le montage de votre kit Pan-Tilt PTZ.

raspberry pi 3 raspi 3 Blynk server on Raspberry Pi  or Orange Pi (optionnal)

How to install a blynk server on a Raspberry Pi 3 or Orange Pi (Armbian)

orange pi lite h3 computer board Orange Pi Lite (WiFi version) or One (Ethernet)
chargeur 5v 3a orange pi dc4mm 5V/3A micro-usb power supply
arduino nano v3 atmega328p 5v 16mhz Arduino Nano v3 5V/16MHz
mini kit fpv pan tilt sg90 Mini Kit FPV Pan Tilt 2x SG90

Guide de montage

jumper dupont Jumper Dupont

Circuit

blynk nodejs johnny-five orangepi arduino firmata servo sg90 ptz pan tilt kit_

Install Firmata firmware on the Arduino

The Firmata firmware provides access to all Arduino features via the serial port (using a USB cable). Connect the card to the computer and open the Arduino IDE. In the examples menu you will find a submenu named Firmata. Select the firmware that fits your need. The most common is to use the standard firmware. There is also a Plus version for communicating with peripheral devices via serial link UART, USART or SoftwareSerial. Simply upload the firmware to the card. It’s ready ! To customize the firmware, read this article.

ide arduino install firmata

Installing Node.js on Armbian or Raspbian

Node.js is a runtime engine that allows Javascript scripts to run on a computer or mini-PC (Raspberry Pi, Orange Pi …). It is a multiplatform engine, meaning that code written on an environment can work identically (provided that the hardware resources also exist) on another environment. Node.js is available for Windows, MacOS, Linux (x86 and ARM).

nodejs download macos windows linux arm

First, make sure that Node.js is not already installed on your distribution

# node -v && npm -v
v5.12.0
3.8.6

If you get an error message, install Node.js 4.x (sufficient) as well as Python and Build

curl -sL https://deb.nodesource.com/setup_4.x | sudo bash -
sudo apt-get install -y build-essential python-dev nodejs

Installing the required Node.js plugins: Blynk, Johnny-Five

For this project, we will need to install the Blynk (for Nodejs) and Johnny-Five packages. Run this command to install them. The sudo command is preferred on Unix systems. The -g option allows you to install the packages glabalement, allowing them to be used in all scripts. The dependencies required for the packages will be automatically installed at the same time (magic npm).

npm install -g blynk-library johnny-five
Note. Here we will use an Arduino/Firmata as a GPIO. If you want to use the Raspberry Pi GPIO, you will need to install the io-plugin package. The complete list is here.

Blynk project on mobile application

Launch Blynk on your smartphone or tablet. If you have a local server, connect to it by changing the source as shown in the screenshot below.

 To get started with the Blynk application, follow this tutorial.

blynk create account local server

Add 2 sliders. The first V0 will control the PAN servo. The second V1 will control the servo TILT. For both sliders, check Send values on release only if you want the servo to move only when the slider is released. Change the maximum output level to 180 (for 180 degrees).

blynk slider pan

You can also add 4 buttons

  • V2 (Center): reposition the 2 axes in the center (90 °, 90 °)
  • V3 (Stop): Stop all current movements
  • V4 (Pan Sweep): horizontal scanning
  • V5 (Tilt Sweep): sweeping Vertical

Here is the project obtained

Javascript code of the project (Node.js)

Your environment must be ready before proceeding. Connect to the Orange Pi (or Raspberry Pi) in SSH (or live). Create a new directory (nodebot) and place inside

cd ../ ..
mkdir nodebot && cd nodebot;

Create a new javascript script

nano j5PanTilt.js

At the beginning of the script, we will call the different libraries necessary:

  • Blynk: blynk-library
  • Johnny-Five
  • Events: Allows you to send and receive events.
var Blynk = require('blynk-library');
var five = require("johnny-five");
var EventEmitter = require('events').EventEmitter;

Then we will create several objects:

  • board: it is the basic object that allows to use the Johnny-Five API, for example to control the servos, turn on the LEDs …
  • event: This object is used to send and receive Javascripts events
  • blynk: allows you to use the Blynk API
  • connector: object containing the HTTP connection to the local Blynk server
  • Vx: objects to exchange data with the Blynk server
var board = new five.Board();                   // Objet permettant l'appel à l'API J5 - Object to call J5 API
var AUTH = 'b065eb0a6e36434da42367b3fa7c3340';  // Remplacer par votre Token Blynk - Replace by your Blynk Token

var event = new EventEmitter();                 // Evenements javascript - Javascript Events
var DEBUG = true; //false;                      // Active les messages de mise au point - Activate debug message

// Setup Blynk
var blynk = new Blynk.Blynk(AUTH, options = {
  // Connecteur au serveur Blynk local - Local Blynk server connector
  connector : new Blynk.TcpClient( options = { addr:"xxx.xxx.xxx.xxx", port:8442 } )
});
var V0 = new blynk.VirtualPin(0);  // Pan servo           
var V1 = new blynk.VirtualPin(1);  // Tilt servo
var V2 = new blynk.VirtualPin(2);  // Reset position

It is very easy to monitor the connection status of the Blynk server at any time and “plug in” a function that is triggered when an event is issued by the object. For example, one can monitor whether one is connected (connect) to the server, or on the contrary that one is disconnected. It is possible, for example, to carry out a treatment in the event of disconnection. Here, we will simply display a message when connected to the server, or if the script is disconnected.

blynk.on('connect', function() { console.log("Blynk ready."); });
blynk.on('disconnect', function() { console.log("DISCONNECT"); });

You must wait until communication with the Arduino card is established before you can use the Johnny-Five API. To do this, we will plug into the ready event like this. The ready event does not return any information.

board.on("ready", function() {
  // code
  console.log("J5 Board is Ready");
})

How to drive a servo with Johnny-Five?

Johnny-Five offers two classes to drive the servo motors:

  • servo: A servo motor is individually controlled. The complete documentation can be found here
  • servos: two actuators can be operated simultaneously. The complete documentation can be found here. This API is recommended if you want to create perfectly synchronized movements of several servos. All the methods of the servo API are available!

The servo API offers many functions:

  • to (deg ms, rate): moves the servo to the indicated position (deg). Ms is used to indicate the time to perform the movement and misses the number of steps. For example servo.to (90,500,10) will move the servo at the 90 ° angle in 500ms in 10 steps.
  • min: moves the servo to the mini position. Default 0 °. It is possible to modify the possible range of movement of the servo at initialization. For example 30 ° to 150 °.
var servo = new five.Servo({
  pin: 10, 
  range: [ 30, 150 ]
});
  • max: idem but maximum. Default is 180 °.
  • center: positions the servo in the center position. It is calculated at the center of the range. By default 0 – 180 °, the center will be at 90 °
  • home: returns the servo to the position defined by the startAt parameter
var servo = new five.Servo({
  pin: 10,
  startAt: 20
});

// Set horn to 90 degrees
servo.to(90);

// Return to startAt value of 20 degrees
servo.home();
  • sweep: alternate sweep between min and max
  • sweep([low, high]): alternate sweep from low to high
  • sweep(options): sweep with options. Range: [start position, end position], interval: half-displacement (ms) duration, step: step-by-step
  • stop: stops the current movement
  • cw(speed 0-1): continuous movement in the clockwise direction
  • ccw(speed 0-1): continuous movement counterclockwise

Preparing the Pan and Tilt Servo Moves

We will take advantage of it to test some functions very quickly thanks to Johnny-Five. One could, for example, develop a small surveillance camera system that would regularly scan horizontally. We will add a function to stop all movements in progress and one last one to return the axes Pan and Tilt to their central position.

In the board.on(“ready”) function, the two servos

var pan = new five.Servo(PIN_PAN);
 var tilt = new five.Servo(PIN_TILT);

Then we will plug in treatments by listening to events. For example, the PAN event will cause the Pan servo to move to the position passed as a parameter

event.on('PAN', function(position){
  if ( DEBUG ) { console.log("Move Pan servo to ", position); }
  pan.to(position);
});

event.on('PAN_SWEEP', function(position){
  if ( DEBUG ) { console.log("Move Pan servo to ", position); }
  pan.to(position);
});
It is mandatory to process the movements in the board.on (“ready”) function. This is a Javascript constraint that is an asynchronous language.

Now just after the board.on(“ready”) function, a message will be sent as soon as we receive an order from the Blynk application. In Javascript, simply call the event object (created at the beginning of the program) and use the emit method. The emit method takes two parameters. The first one is a string that allows you to name the event. The optional second is a parameter. It can be a string, a numeric value, a Boolean … or a JSON object. Here, the angle is sent as an integer. To do this, use the parseInt function to convert the string to integer.

V0.on('write', function(param){
  if ( DEBUG ) { console.log("V0 (Pan) ", param); }
  event.emit('PAN',parseInt(param) );
});

Full Project Code

Paste the following code into the previously opened file without forgetting to change the IP address of your local Blynk server and the token of the project.

A LED can be connected to pin 11. It flashes during the movements
var Blynk = require('blynk-library');
var five = require("johnny-five");
var EventEmitter = require('events').EventEmitter;

var board = new five.Board();                   // Objet permettant l'appel à l'API J5 - Object to call J5 API
var AUTH = 'b065eb0a6e36434da42367b3fa7c3340';  // Remplacer par votre Token Blynk - Replace by your Blynk Token

var event = new EventEmitter();                 // Evenements javascript - Javascript Events
var DEBUG = true; //false;                      // Active les messages de mise au point - Activate debug message

var DEBUG = true; //false;
var PIN_PAN = 10;
var PIN_TILT = 9;

// Configure l'objet Blynk - Setup Blynk object
var blynk = new Blynk.Blynk(AUTH, options = {
  connector : new Blynk.TcpClient( options = { addr:"192.168.1.24", port:8442 } )
});

var V0 = new blynk.VirtualPin(0);  // Pan servo
var V1 = new blynk.VirtualPin(1);  // Tilt servo
var V2 = new blynk.VirtualPin(2);  // Retourne à la position centrale - Go to center position
var V3 = new blynk.VirtualPin(3);  // Stop tous les mouvements - Stop all movements
var V4 = new blynk.VirtualPin(4);  // Balayage horizontal - Pan sweep
var V5 = new blynk.VirtualPin(5);  // Balayage vertical - Tilt sweep

blynk.on('connect', function() { console.log("Blynk ready."); });
blynk.on('disconnect', function() { console.log("DISCONNECT"); });

board.on("ready", function() {
  console.log("Board J5 Ready ");
  var led = new five.Led(11);

  var pan = new five.Servo(PIN_PAN);
  var tilt = new five.Servo(PIN_TILT);

  function stopBlink(){
    led.stop();
    led.off();
  };

  event.on('PAN', function(position){
    if ( DEBUG ) { console.log("> Move Pan servo to ", position); led.blink();}
    pan.to(position);
    stopBlink();
  });

  event.on('PAN_SWEEP', function(position){
    if ( DEBUG ) { console.log("> Sweep Pan servo "); led.blink();}
    pan.sweep();
  });

  event.on('TILT', function(position){
    if ( DEBUG ) { console.log("> Move Tilt servo to ", position); led.blink();}
    tilt.to(position);
    stopBlink();
 });

  event.on('TILT_SWEEP', function(){
    if ( DEBUG ) { console.log("> Sweep Tilt servo "); led.blink();}
    tilt.sweep();
  });

  event.on('CENTER', function(position){
    if ( DEBUG ) { console.log("> Go Home Pan/Tilt servos"); led.blink();}
    pan.center();
    tilt.center();
    stopBlink();
  });

  event.on('STOP', function(){
    if ( DEBUG ) { console.log("> Stop All movements"); led.blink();}
    pan.stop();
    tilt.stop();
    stopBlink();
  });
});

V0.on('write', function(param){
  if ( DEBUG ) { console.log("V0 (Pan) ", param); }
  event.emit('PAN',parseInt(param) );
});

V1.on('write', function(param){
  if ( DEBUG ) { console.log("V1 (Tilt) ", param); }
  event.emit('TILT',parseInt(param) );
});

V2.on('write', function(param){
  if ( DEBUG ) { console.log("GO Home position "); }
  event.emit('CENTER');
});

V3.on('write', function(param){
  if ( DEBUG ) { console.log("STOP all movements"); }
  event.emit('STOP');
});

V4.on('write', function(param){
  if ( DEBUG ) { console.log("SWEEP Pan servo"); }
  event.emit('PAN_SWEEP');
});

V5.on('write', function(param){
  if ( DEBUG ) { console.log("SWEEP Tilt servo"); }
  event.emit('TILT_SWEEP');
});

Save the file with CTRL + X then Y. Start the script with the command node j5PanTilt.js , if you have enabled debug, you will be able to follow the arrival of the commands from the Blynk server; The execution of the command is preceded by a ‘>’.

# node j5PanTilt.js 
Connecting to TCP: 192.168.1.24 8442
Connected
1490105773157 Device(s) /dev/ttyUSB0  
1490105773264 Connected /dev/ttyUSB0  
Authorized
Blynk ready.
1490105774854 Repl Initialized  
>> Board J5 Ready 
V0 (Pan)  [ '99' ]
> Move Pan servo to  99
V0 (Pan)  [ '31' ]
> Move Pan servo to  31
SWEEP Pan servo
> Sweep Pan servo

A short demonstration video to conclude this tutorial.

Subscribe to the weekly newsletter

No spam and no other use will be made of your email. You can unsubscribe anytime.

DIY Projects