IoT Applications with PCDuino and Node.js

mdiaconescu's picture

IoT (Internet of Things) applications are now accessible to almost anyone which likes the idea of creating DIY projects by putting hardware components (sensors, actuators and HID devices) along with software components and Web technologies (and not only).

Many technologies and frameworks are available for IoT-enabled projects. This article focuses on using Node.js (software wise) and the PCDuino v3 controller (hardware wise). With an actual price of about 50€ in Germany, PCDuino v3 is a small but powerful mini-PC and development board providing access to hardware GPIOs (General Input and Output Pins). The physical arrangement of the GPIO pins is identical with the one of the well known Arduino UNO board. As operating system, for now it is possible to use Android 4.2 and Ubuntu 12.04. Node.js can be installed when using Ubuntu and allows to be used for hardware resources access (e.g., used to read a temperature sensor) as well as to provide a HTTP server instances and create web applications. Getting access to the hardware resources requires to use the iotduino open source module available from the official npm repository. 

The iotduino module is capable to replicate the following well known Arduino specific functionality:

  • pinMode( pin, state) - sets the pin mode to INPUT (0x0), OUTPUT (0x1) or INPUT_PULLUP (0x2)
  • digitalRead( pin) - reads the current state of the selected pin.
  • digitalWrite( pin, state) - sets the pin state to LOW (0x0) or HIGH ( 0x1) after pinMode was called withOUTPUT as state parameter
  • analogRead( pin) - reads the value of the analogous pin. Pins A0 and A1 have 6 bits ADC resolution (so the method returns values in the interval [0, 63]) while the pins A2, A3, A4 and A5 have 12 bits ADC resolution (so the method returns values in the interval [0, 4095]). Notice that the ADC voltage reference is 3.3V (well, almost and depends on many factors), so one can measure positive voltage up to 3.3V (resistor divider circuits can be used to measure higher voltages if needed).
  • analogWrite( pin, value) - creates a PWM effect on the selected pin. The supported pins are GPIO3, GPIO5, GPIO6, GPIO9, GPIO10 and GPIO11. The value parameter is an integer number in range [0, 255]. The method is used in combination with setPwmFrequency method.
  • setPwmFrequency( pin, frequency) - sets the PWM frequency for the specified pin. Pins GPIO5 and GPIO6 supports only: 195Hz, 260Hz, 390Hz, 520Hz and 781Hz while pins GPIO3, GPIO9, GPIO10 and GPIO11 supports integer values in the range [126, 2000]Hz.
  • pulseIn( pin, state, timeout) - reads a pulse time for the specified pin and provided state. It returns the value in microseconds.
  • micros() - reads the number of microseconds ( modulo unsigned long type in C/C++) elapsed from Epoch (01.01.1970, 00:00:00 UTC).
  • delay( milliseconds) - pauses the code execution for the specified number of milliseconds. 
  • delayMicroseconds( microseconds) - pauses the code execution for the specified number of microseconds. 

The following constant groups are available for code reading simplification reasons :

  • PinMode - defines the pin mode states. Possible values: INPUT, OUTPUT and INPUT_PULLUP. Alternative: use 0, 1 and 2.
  • PinState - defines the possible pin states. Possible values: LOW and HIGH. Alternative: use 0 and 1.
  • Pins - defines the existing pins. Possible values: GPIO0, GPIO1, ... GPIO23, A0, A1, A2, A3, A4, A5. Alternative: use 0, 1, ..., 23 to identify GPIOs and 0, 1, 2, 3, 4, 5 to identify the analog pins.

Installing this module is easy:

  npm install iotduino

for local installation (only available to a specific application), or

  npm install -g iotduino

for global installation (available to any node application):

One has to use sudo or to login as root on Linux systems for being able to install this module globally.

In case of the following error during installation:

  Error: Cannot find module 'iotduino'

check the NODE_PATH variable (use echo $NODE_MODULES) to verify if it points to the right location (normally this is /usr/local/lib/node_modules). 

As the most basic usage example, lets consider a LED blinking scenario:

  var duino = require( 'iotduino'),
      pinMode = duino.PinMode, pinState = duino.PinState,
      pins = duino.Pins, ledPin = pins.GPIO13;

  // pin 13 (GPIO13) is set as OUTPUT
  duino.pinMode( ledPin, pinMode.OUTPUT);
  // repeat every 500 milliseconds, 2 times per second
  setInterval( function () { 
    // alternate the pin state between HIGH and LOW 
    duino.digitalWrite( ledPin, !duino.digitalRead( ledPin));
  }, 500);

GPIO13 is connected to a built-in LED on the PCDuino v3 board, same as in the case or Arduino UNO board, so this example simply works without any additional effort or external components. Create a blink.js file, copy/paste the above code, save it then execute:

  node blink.js 

The onboard LED should blink now about two times per second.

Reading a HC-SR04 ultrasonic sensor (used to measure distances of up to 4 meters with an accuracy of about 2 centimeters) is also quite simple:

  var duino = require( 'iotduino'),
      pinMode = duino.PinMode, pinState = duino.PinState,
      pins = duino.Pins, trigPin = pins.GPIO2, echoPin = pins.GPIO3, 
      distanceCm = -1;

  // the trigger pin (GPIO2) is set as OUTPUT
  duino.pinMode( trigPin, pinMode.OUTPUT);
  // the echo pin (GPIO3) is set as INPUT
  duino.pinMode( echoPin, pinMode.INPUT);
  // read the sensor every 333 milliseconds, ~3 times per second
  setInterval ( function () { 
    // the sensor receives LOW at the trigger pin, 
    // to prepare it for data reading
    duino.digitalWrite( trigPin, pinState.LOW);
    // wait for the sensor to get ready
    duino.delayMicroseconds( 2);
    // inform the sensor that we want to make a reading
    duino.digitalWrite( trigPin, pinState.HIGH);
    duino.delayMicroseconds( 10);
    // end the commands chain to the sensor
    duino.digitalWrite( trigPin, pinState.LOW);
    // read the value HIGH time period from the sensor
    // and compute the distance based on it and the physical laws
    distanceCm = duino.pulseIn( echoPin, pinState.HIGH, 100000) / 58.0; 
    // show the distance value in the console
    console.log( "Distance: " + distanceCm.toFixed(2) + " cm");
  }, 333);

The following hardware connections are required for the above example:

  • the sensor's trig pin is connected to GPIO2 pin of the PCDuino board
  • the echo pin of the sensor is connected to GPIO3 pin of the PCDuino board
  • VCC pin of the sensor goes to 5V from the power supply
  • GND pin of the sensorconnects to GND from the power supply.

NOTE: The HC-SR04 sensor board requires a 5V power supply. While the PCDuino v3 GPIO pins have the same (or almost the same) functionality as the ones of the Arduino UNO board, they are NOT 5V tolerant. Therefore a hardware voltage level translator from 5V to 3.3V and back is required to avoid permanent damages on the GPIOs and the board.

The iotduino module was written by using native C/C++ code. Benchmarks with PCDuino v3 board reveals that a digitalWrite operation takes 6-7 microseconds (~ 140 - 160 KHz) and a digitalRead operation takes 4-5 microseconds (~200 - 250 KHz). The tests were made by using one million (1.000.000) read/write operations.

The native code execution is fast enough to be used with the custom 1-Wire communication protocol used by the DHT22 temperature and humidity sensor (the communication with this sensor is really time sensitive). 

The code source of this module is available for download on github.