Como interactuar con el mundo físico mediante Javascript y NodeJS

2
13996

Como interactuar con el mundo físico mediante Javascript y NodeJS

Índice

Introducción

En este tutorial aprenderás como con NodeJS puedes crear una aplicación en Javascript que interactue con el mundo físico mediante un circuito creado por nosotros mismos.

Para el ejemplo, construiremos un semáforo con leds y un pulsador para activarlo. El semáforo y el pulsador serán controlados desde la aplicación Javascript corriendo en NodeJS en una placa Raspberry PI con linux Debian «Wheezy»

Para que el tutorial sea más claro y fácil de entender, el lenguaje de programación usado será CoffeeScript.

Manos a la obra

Para seguir este tutorial necesitas:

  • Rapsberry Pi: Ordenador del tamaño de una tarjeta de crédito. Tiene un interfaz de entrada y salida de propósito general que nos servirá para conectar nuestro circuito (Raspberry Pi).
  • NodeJS: Es una plataforma basada en el runtime javascript de Google Chrome (NodeJS). Vamos a usar la ultima versión de NodeJS asi que lo mejos es bajarse los fuentes y compilarlo en la Raspberry Pi
  • Protoboard, 3 leds de diferentes colores, resistencias, pulsador y cables: Es el hardware que vamos a controlar desde nuestra aplicación Javascript.
  • GruntJS: Herramienta que nos simplificará el build de la aplicación (GruntJS).

Lo primero que vamos a hacer es configurar nuestro entorno de desarrollo. En primer lugar vamos a instalar GruntJS, para ello usamos el comando npm install -g grunt. Probablemente
necesitemos permisos de administrador ya que lo vamos a instalar de forma global.

Una vez instalado, creamos nuestro fichero de build siguiendo el siguiente ejemplo:

        module.exports = function (grunt) {
            'use strict';

        grunt.initConfig({
            pkg: '',

            // delete the dist folder
            delete: {
                dist: {
                    src: ''
                }
            },
            // lint CoffeeScript
            coffeeLint: {
                scripts: {
                    src: '/**/*.coffee',
                    indentation: {
                        value: 1,
                        level: 'error'
                    },
                    max_line_length: {
                        level: 'ignore'
                    },
                    no_tabs: {
                        level: 'ignore'
                    }
                }
            },

            // compile CoffeeScript to JavaScript
            coffee: {
                    dist: {
                        src: '**/*.coffee',
                        dest: '',
                        bare: true
                    }
                }
            });

            grunt.loadNpmTasks('grunt-hustler');
            grunt.registerTask('default', 'delete coffeeLint coffee');
        };
        

Como podemos comprobar, hemos definido tres tareas, una para borrar el directorio destino, otra para pasar CoffeeLint y comprobar que nuestro código sigue un estilo correcto y por ulitmo
la tarea de compilación de nuestro código CoffeeScript a Javascript para poder ser ejecutado por NodeJS.

Como siguiente paso crearemos el fichero descriptor de nuestro proyecto package.json en el raíz del mismo:

            {
              "name": "RaspberryPI-gpio-semaforos",
              "description": "Ejemplo de control de interfaz GPIO en Raspberry PI",
              "version": "0.0.1",
              "author": {
                "name": "Paulino Corujo",
                "email": "pcorujo@gmail.com"
              },
              "engines": {
                "node": "node >= 0.8.1"
              },
              "dependencies": {
                "grunt": "~0.3.17",
                "grunt-hustler": "*",
                "gpio": "*"
              },
              "src": "./src/",
              "dist": "./dist/"
            }
        

En este fichero definiremos, entre otros, las dependencias con los paquetes grunt y grunt-hustler que nos permitirán compilar de forma sencilla nuestro código. Por último
declararemos la dependencia con la librería gpio de NodeJS para interactuar con el GPIO de nuestra Raspberry Pi y crearemos las variables usadas en GruntJS.

Por último, y para dejar nuestro entorno de desarrollo listo, ejecutaremos el comando npm install en el directorio donde se encuentra el fichero package.json para
descargar las dependencias que vamos a necesitar en nuestro ejemplo.

Ya tenemos nuestro entorno de desarrollo listo, ahora prepararemos nuestra protoboard o breadboard con el circuito que vamos a utilizar, para ello conectaremos tres leds de distinto color (Verde, Ambar, Rojo)
en nuestro tablero, el polo positivo del led (pata mas larga) será el que conectemos a la alimentación de uno de los pines de nuestra RaspPI (+3.3 V.).
el polo negativo del led lo conectaremos a una tierra (0 V.) con una resistencia de por medio. Para calcular la resistencia que necesitamos usaremos la formula conocida:
(V – Vl) = I* R
En el ejemplo, los pines del GPIO de RaspPI proporcionan 3.3v. Los leds del ejemplo trabajan a 2v. y la intensidad es de 4mA con lo que usaremos una resistencia de 330ohm. Es importante calcular
bien estos valores ya que podrías dañar la placa o hacer que el led no brille lo suficiente si se elige una resistencia inadecuada.

Ahora conectaremos los leds a los GPIO de la RaspPI, para ello, según la documentación, elegiremos los siguientes pines:

  • Para el led rojo el GPIO 17 (pin 11)
  • Para el led ambar el GPIO 21 (pin 13)
  • Para el led verde el GPIO 18 (pin 12)

En el ejemplo cada cable corresponde al color de led que alimenta.Conectaremos ahora tambien el cable de tierra, que corresponde con el pin 6 del esquema de la documentación.
Por último conectaremos la salida de 5v (pin 2) a la alimentación del pulsador y la otra pata del mismo al GPIO 25 (pin 22) acordándose tambien de poner una resistencia en el contacto a tierra (en el ejemplo de 10k ohm).

Quedando el circuito y nuestra RaspPi de la siguiente forma:

Con todo esto preparado, solo queda programar nuestro simulador. Para el ejemplo crearemos el model del Semáforo el cual lanzará eventos de encendido y apagado de las luces usando el EventEmitter de NodeJS.
Para proporcionar dos vistas del estado del semáforo, crearemos dos clases que escucharán dichos eventos, una mostrará el estado en consola y otra lo mostrará encendiendo y apagando los leds en nuestra protoboard:

Para mantener el estado de nuestro semáforo, crearemos la clase Semaforo en el fichero src/Semaforo.coffee:

            Events = require "events"

            #Modelo del semáforo
            class Semaforo extends Events.EventEmitter

                @Estados =
                    ROJO  : 0
                    AMBAR : 1
                    VERDE : 2

                #Inicializamos el semaforo al estado Verde
                inicializa : ->
                    @cambiaEstado Semaforo.Estados.VERDE
                    @cambiandoEstado = false

                #Al cambiar el estado dispararemos un evento para apagar y encender
                cambiaEstado : (estado) ->
                    @emit "apagar",
                        estado: @estadoActual
                    @estadoActual = estado

                    @emit "encender",
                        estado: @estadoActual

                getEstado: () ->
                    return @estadoActual

                ###
                 Este método será invocado al pulsar el pulsador en nuestro circuito, la lógica para cambiar a rojo es un tiempo de dos segundos de espera
                 para pasar a color Ambar, otros dos segundos de espera para pasar a color Rojo y diez segundos de espera para volver al color verde
                ###
                cambiaRojo : ->
                    if @getEstado() is Semaforo.Estados.VERDE and not @cambiandoEstado
                        @cambiandoEstado = true
                        setTimeout =>
                            @cambiaEstado(Semaforo.Estados.AMBAR)
                            setTimeout =>
                                @cambiaEstado(Semaforo.Estados.ROJO)
                                setTimeout =>
                                    @cambiandoEstado = false
                                    @cambiaEstado(Semaforo.Estados.VERDE)
                                , 10000
                            , 2000
                        , 2000

            module.exports = Semaforo
         

Y a continuación crearemos nuestro fichero src/Simulador.coffee, que tendrá las dos vistas e inicializará nuestra aplicación:

            Semaforo = require "./Semaforo"
            gpio = require "gpio"

            semaforo = new Semaforo

            #Vista para mostrar los eventos en consola
            class SemaforoViewConsola

                MENSAJES_ENCENDER = [
                    "Encendiendo Rojo"
                    "Encendiendo Ambar"
                    "Encendiendo Verde"
                    ]

                MENSAJES_APAGAR = [
                    "Apagando Rojo"
                    "Apagando Ambar"
                    "Apagando Verde"
                    ]

                constructor : (@semaforo) ->
                    semaforo.on "encender", (data) ->
                        console.log MENSAJES_ENCENDER[data.estado]

                    semaforo.on "apagar", (data) ->
                        if data.estado != undefined
                            console.log MENSAJES_APAGAR[data.estado]

            #Vista para mostrar los eventos en los leds
            class SemaforoViewLED

                LEDS = [
                    gpio.export 17, ready:{}
                    gpio.export 21, ready:{}
                    gpio.export 18, ready:{}
                    ]

                constructor : (@semaforo) ->
                    semaforo.on "encender", (data) ->
                        LEDS[data.estado].set()

                    semaforo.on "apagar", (data) ->
                        if data.estado != undefined
                            LEDS[data.estado].set(0)

            #Creamos las instancias de cada vista y suscribimos los escuchadores
            vista = new SemaforoViewConsola semaforo
            vista = new SemaforoViewLED semaforo

            #Inicializamos el pulsador
            boton = gpio.export 25, {
                direction: "in"
                ready:()->
                    console.log "Preparado"
                }

            #Registramos el evento "change" del pulsador para cambiar nuestro semaforo a color Rojo
            boton.on "change", (value) ->
                semaforo.cambiaRojo()

            #Esperamos un segundo para inicializar los pines GPIO
            setTimeout =>
                semaforo.inicializa()
            , 1000

            

Nuestro sistema operativo mapea los pines del GPIO al dispositivo lógico /sys/class/gpio/ con lo cual la escritura de 1 o 0 en dicho dispositivo
implicará el proporcionar 3.3v o 0v a los pines seleccionados siempre y cuando estemos en modo escritura. Para el modo lectura (necesario para el pulsador)
haremos la operación contraria, se leerá de dicho dispositivo los valores 0 o 1. En nuestro ejemplo el pulsador (conectado al pin de alimentacion 5v) no
permite el paso de corriente, luego nuestro pin de lectura no tendrá nada que leer y no habrá eventos de cambio. Cuando es pulsado, el circuito se cierra
circulando corriente y proporcionando al pin en modo lectura corriente y, por tanto, un valor para leer en el dispositivo logico.

Por último solo queda compilar nuestro código a Javascript para que pueda ser ejecutado en NodeJS, para ello lanzamos grunt en el directorio donde tenemos
el fichero grunt.js, una vez finalizado, tendremos en el directorio dist dos ficheros, Semaforo.js y Simulador.js. Lanzaremos
con el comando node Simulador nuestro ejemplo para ejecutarlo (Hay que tener en cuenta que se necesita ser root para acceder al dispositivo GPIO):

Conclusiones

En este tutorial hemos visto como de forma sencilla mediante NodeJS podemos interactuar con el mundo fisico, éste es solo un ejemplo simple
para controlar leds pero las posibilidades son todas las que puedas imaginar, y, todo ello, usando un lenguaje conocido y extendido como Javascript o CoffeeScript.

2 COMENTARIOS

  1. Muy buen tutorial!

    Estoy haciendo mis pinitos con Arduino, pero la diferencia de potencia que presenta Rasperry me resulta mucho más interesante.

    Aquí en Madrid dónde puedo comprar un Rapserry Pi B?

    Gracias, por tu tutorial.

  2. Hola gente. Muy buen trabajo!
    No tengo conocimientos de este tema pero tengo una necesidad.
    Necesito un interrupor fisico que me genere un evento en JavaScript. La idea seria un pulsador o varios que pudiera configurarlo para generar distinos eventos, y esos eventos poder tomarlos desde javascript. Una suerte de mini teclado convencional pero desde un pulsador.
    si alguien puede ayudarme donde conseguir informacion o por donde empezar. Muchas gracias!!!

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad