bluebrowncustomgreenorangepinkredturquoiseyellow
  • Layout Style
  • Texture for Boxed, Framed, Rounded Layout Background

  • Font
    • Body:

    • Menu:

    • Title:

    * Fonts are used to example. You able to use 600+ google web fonts in the backend.

Mail info@moldeointeractive.com.ar
Blog - Moldeo Coop.

Uso de Beacons para Apps en Android y iOS – Cordova

Muchos se encuentran al tanto de nuestros desarrollos de la Tera-App y el Tera-Streaming para la obra Teravision, realizada hace poco en el Centro de Experimentación del Teatro Colón. La realidad es que se trata de una de las obras más complejas que hemos llevado a cabo a nivel técnico, y nos ha dejado -entre otras cosas- mucho material producto de la experimentación y la innovación que nos caracteriza. Tal es el caso de utilizar dispositivos Beacons para la obra. Los Beacons son pequeños dispositivos -como pastillas grandes- que transmiten señal a través de Bluetooth Low Energy (BLE). Esto quiere decir, que cualquier dispositivo móvil con acceso a Bluetooth 4.0 (más del 90% de los dispositivos, según Bluetooth SIG predice para este año) podrá obtener la distancia a la que se encuentra de dicho Beacon. Para Teravision empleamos los Beacons de Onyx Beacon, el modelo básico, pero se comercializa también un modelo especial con mejor señal y otros agregados (impermeabilidad, alarma, etc).

Nuestra idea de desarrollo de Apps siempre tiende a utilizar el framework Cordova, ya que nos permite desarrollar una app híbrida en lugar de una app por sistema (en grupos reducidos de trabajo, como el nuestro, suele ser la diferencia entre poder llegar a tiempo con el desarrollo y no poder). Como no podía ser de otra manera, existe un plugin para Cordova que hace uso del SDK de Beacons (cordova-beacon de unarin) para utilizarlo en JavaScript, y también está la opción de utilizar el plugin BLE, aunque sin resultados aparentes. La configuración es por demás sencilla, se requiere simplemente el UUID (un número en 5 bloques) del fabricante (en este caso Onyx Beacon) para poder poner todas las Beacons en lo que se conoce como una región. La región de Beacons es propia de cada App y puede estar constituida por Beacons de distintos fabricantes, el plugin de Cordova tiene opciones para dicha configuración. Para reconocerlos se utilizan los valores major y minor (cuya combinación es única para cada dispositivo de cada fabricante) o bien un número de Mac Address (también único).

La primer opción era utilizar los Beacons como triggers/disparadores de cada escena dentro de la obra, cuando la persona se acerque lo suficiente a uno de ellos. Sin embargo, la realidad tecnológica no nos permitió poder desarrollarlo en su totalidad. El valor de accuracy supuestamente devuelve un número decimal que es el equivalente en metros a la distancia entre dispositivo y Beacon. No esperábamos encontrarnos con un dato real de distancia, pero en muchos casos no era ni aproximado. Por tal motivo, abandonamos el uso de Beacons para producir una obra 100% autónoma y surgió la idea de emplearlos como dispositivos de monitoreo de usuarios. Y así fue, pudimos conseguir datos de como se movía cada usuario en el espacio, el tiempo que se mantenía quieto y si repetía o no la experiencia. Esto no solo sirvió como control a la hora de llevarse a cabo la obra, sino que también produjo una base de datos interesante para mejorar el recorrido y la experiencia en un futuro.

¿Y que conclusiones tenemos a partir del uso de Beacons? En principio, que la respuesta de estos dispositivos no es para nada “tiempo real”, hay un retraso importante al utilizar el SDK de Android o de iOS; y no se trata de que la App esté construida en Cordova, ya que internamente el motor que obtiene los valores de los Beacons es el propio SDK. Para más complicaciones, la precisión de dichos valores es completamente ridícula. Sí, al estar mas lejos del Beacon el valor sube, al acercarse el valor decrece; pero sin ningún parámetro que pueda explicar el porque en dispositivos Android devolvía un valor de 2.5 al estar a 10 metros de distancia, mientras que en muchos iPhone se conseguían valores superiores a 15 para la misma distancia. Lo que parece dar a entender que los fabricantes de Beacons desean que los desarrolladores utilicemos APIs con licencia como Tracko o similar (las cuales se pagan anualmente y no son alternativas libres).

Entonces, ¿Es una buena opción el uso de Beacons? ¡Por supuesto! Para monitoreo del público en un espacio determinado, para instalaciones museológicas, incluso para estacionamientos. Los problemas pueden ajustarse con estrategias desde el software mientras se desarrollan mejores hardwares. Lo que nos queda claro son dos cosas: estos dispositivos llegaron para quedarse y son sumamente inestables -todavía- para emplearse en todo tipo de obra.

Teravision - Desarrollo de la TeraApp

En estos días se está llevando a cabo en el Centro de Experimentación del Teatro Colón la obra Teravisión, ideada y dirigida por Edgardo Mercado y Augusto Zanela. Esta especie de "instalación teatral" plantea un recorrido en completa oscuridad, donde los espectadores ven en sus celulares (mediante una aplicación) video en vivo de las distintas salas, captados por una red de cámaras infrarrojas. Moldeo Interactive estuvo a cargo del desarrollo tanto del sistema de cámaras infrarrojas y del servidor, como así también del desarrollo de una App para dispositivos Android y iOS que sea capas de recibir el Streaming, reproducir audios, video e imágenes. En esta ocasión, vengo a hablar de esta segunda instancia, sobre cómo desarrollamos la aplicación.

El desarrollo comenzó con Angular, nos interesaba tener una App híbrida (es decir, que funcione en Android y en iOS al mismo tiempo, sin tener que programar dos aplicaciones) ya que sólo contábamos con un mes para el desarrollo, las pruebas y el ensayo. De ese modo, la integración Angular con Cordova se convierte en una opción excelente, sin perder gran rendimiento (el webview de ambos sistemas permite un desarrollo ágil y con resultados satisfactorios). Cerca de los últimos ensayos, este desarrollo tomó una nueva dimensión ya que las Apps se ejecutan (actualmente) en el navegador de cada teléfono. Con esto pudimos cubrir una cuota baja pero existente de teléfonos Windows Phone, y se democratizó un poco más la instalación en todas las plataformas.

En Cordova se emplearon diversos plugins dedicados parar llevar la App a otro nivel, como device-motion para obtener datos del acelerómetro, o WifiWizard para datos de la Red (el cual, a pesar de estar discontinuado, funciona mejor que su proyecto sucesor WifiWizard2). Naturalmente que para la versión que ejecuta en el navegador estos plugins no funcionan, pero el device-motion puede reemplazarse con el listener ondevicemotion, nativo de JavaScript. En el caso del WifiWizard realmente no nos preocupó demasiado, ya que la única red disponible en el espacio eran las de TERAVISION. También implementamos un plugin para detectar los iBeacons, pero eso es material para otro artículo.

En el caso del APK, la compatibilidad con Android anteriores a la versión 5 fue un verdadero desafío. Como muchos saben, la versión 5 utiliza un WebView que internamente es un Chrome, actualizable. Pero en versiones anteriores el WebView es un navegador Webkit que se quedó estancado en el tiempo. Para todo esto, existe un sistema que vuelve compatible los Android a partir del 4., mediante la inserción de un núcleo de Chrome en la App. Esto suma alrededor de 50 mb a la App, pero permite que un buen número de dispositivos disfruten de la aplicación. Si bien al momento del estreno preferimos utilizar la versión en navegador (más que nada por la agilidad que nos provee) fue interesante la investigación y el desarrollo de la App con el CrossWalker.

¿Cómo captabamos el Streaming? Sencillamente reemplazando la imagen de fondo de un DIV por la imagen del streaming en cuestión a la frecuencia de FPS, la cual controlamos desde el server dependiendo la cantidad de público. Del mismo modo, los contenidos como Audios, Videos e Imágenes se mandan a través del server, haciendo que la aplicación APK pese tan solo 7 mb y en su versión de navegador menos de 500 kb.

Galería de capturas de la App:

 

Próximamente estaremos escribiendo sobre el desarrollo de la red de cámaras infrarrojas, streaming de video, servidor dedicado, el uso de beacons para instalaciones museológicas y distintas experiencias del uso de tecnología en espacios como el CETC. 

Esta semana serán las últimas 4 funciones de Teravisión, los días 15, 16, 17 y 18 de Marzo, en el CETC.

Demo de MIRU (AR) versión Web - Angular y Facetracker

Estamos contentos de anunciar que nuestra versión de Facetracker en la web ya está funcionando con un rendimiento digno.

Como muchos saben, a principio de año desarrollamos una integración de OpenFace a nuestro software Moldeo, para poder realizar trackeo de rostros en 3D dentro de instalaciones interactivas. Los resultados fueron más que favorables, llegando a realizar una instalación en la Alianza Francesa de Buenos Aires, dentro de Noviembre Digital. Sin embargo, hemos logrado un objetivo todavía más superador, y es lograr implementar dicho sistema en la web, gracias a la tecnología de Angular. De este modo, ya tenemos funcionando la Demo de MIRU(AR) Web, del cual puede verse un video demo en el siguiente link:

 

https://www.youtube.com/watch?v=l9c0IRLo-94

 

Seguiremos informando muy pronto!

Angular y JSFeat (OpenCV.js) - Computer Vision en JavaScript

Es muy posible que, realizada una breve investigación por la web (especialmente sitios como GitHub), los programadores se encuentren con intentos de migración del famoso paquete de librerías OpenCV, especializada en procesamiento de imagen en tiempo real, a JavaScript. Muchos de los trabajos realizados son dignos de destacar, como el caso de js-objectdetect con su excelente rendimiento, o tracking.js con sus resultados finales. Sin embargo, es posible que al día de la fecha ninguno se asemeje a las posibilidades ofrecidas por JSFeat, una librería para JavaScript que ofrece Features similares a las de OpenCV. Y ahi radican sus resultados: no intenta ser una migración de OpenCV a JavaScript, sino que utiliza el lenguaje de JavaScript para conseguir resultados acordes al entorno de trabajo (browser). Y cómo no, si está en JavaScript en Moldeo Interactive queremos que funcione en Angular.

Pero para la correcta integración de JSFeat con Angular es necesario comprender el funcionamiento interno de esta librería, especialmente porque los ejemplos disponibles están un poco entorpecidos por otras dependencias que no vienen al caso (jQuery, gui, profiler, etc). JSFeat aplica sus funciones matemáticas sobre un Canvas, esto quiere decir que nuestra captura de video de la WebCam debe estar en un Canvas. Y para dicha tarea, vamos a tener que conseguir la imagen de nuestra WebCam desde la tag Video con Angular y, empleando el propio Angular, enviarla a un Canvas. Existen diversas formas de realizar esta tarea, pero en principio necesitamos incluir en el HTML del componente una tag video oculta y una tag canvas, que identificaremos para poder acceder a ambas:

<video width="640" height="480" #hardwareVideo [hidden]="true"></video>
<canvas id="canvas" width="640" height="480"></canvas>

En este caso, ya se definieron los valores de ancho y alto, no obstante es posible (y recomendable) hacerlo desde la clase de TypeScript correspondiente, la cual de todas formas necesitamos modificar. En primer lugar, vamos a dejar preparado el entorno, importando el OnInit y el ViewChild de Angular:

import { Component, OnInit, ViewChild } from '@angular/core';

Acto seguido, y teniendo acceso a todo lo necesario, vamos a declarar nuestras variables a utilizar en nuestra clase:

@ViewChild('hardwareVideo') hardwareVideo: any;
constraints: any;
canvas: any;
context: any;

La variable hardwareVideo recupera el elemento HTML con ese mismo nombre (que si revisamos previamente, es el nombre que le pusimos a nuestra tag video). Por otra parte, la variable constraints se utiliza para darle directivas al stream de video; canvas será donde llamaremos nuestro elemento canvas; y context la encargada de almacenar el contexto de canvas. Nada nuevo bajo el sol, comencemos a ensamblar. Dejaremos el constructor vacío ya que nada estará inicializado desde ahí. Entonces, armaremos el ngOnInit de la siguiente forma:

ngOnInit(){
 this.constraints = {
     audio: false,
     video: {
      width: {ideal:640},
      height: {ideal:480}
    }
  };

  this.videoStart();
}

¿Qué pasa acá en el ngOnInit? Le ponemos contenido a nuestra variable constraints (que en este caso no aporta casi nada, pero podemos definirle los FPS o el aspecto del video si nos interesa) e inicializamos la función videoStart que contiene lo siguiente:

videoStart(){
    let video = this.hardwareVideo.nativeElement;
    let n = <any>navigator;

    n.getUserMedia = ( n.getUserMedia || n.webkitGetUserMedia || n.mozGetUserMedia  || n.msGetUserMedia );

    n.mediaDevices.getUserMedia(this.constraints).then(function(stream) {
      if ("srcObject" in video) {
        video.srcObject = stream;
      } else {
        video.src = window.URL.createObjectURL(stream);
      }
      video.onloadedmetadata = function(e) {
        video.play();
      };
    });

    this.canvas = document.getElementById('canvas');
    this.context = this.canvas.getContext('2d');

    this.loop();
}

Acá hay parte de la magia. Ya que esta función se llama en el ngOnInit y solo se ejecutará una vez, directamente se utiliza para el conocido objecto mediaDevices de navigator, y de este la función getUserMedia, que nos permite acceder a los dispositivos multimedia conectados a la computadora. Lo lógico sería hacer unas condicionales de compatibilidad con el navegador un poco más exhaustivas, pero para una primera prueba es suficiente. Finalmente, se le asigna el elemento canvas a la variable canvas, y luego el contexto (en este caso es 2D) a la variable context. Pero vemos al final un elemento desconocido, estamos llamando una función llamada loop, ¿dónde está y que contiene?

loop = () =>{
    this.context.drawImage(this.hardwareVideo.nativeElement, 0, 0, this.canvas.width, this.canvas.height);

    requestAnimationFrame(this.loop);
}

Recordemos algo rápidamente, la función videoStart solo se ejecuta una vez, lo cual es útil para inicializar ciertas funciones. Pero tenemos un problema, necesitamos pasar constantemente la imagen de la tag video al contexto de canvas. Para esto, llegó a nuestro rescate la función requestAnimationFrame(). Sin entrar en mucho detalle, la estructura de esta función loop permite ejecutar constantemente su contenido, algo que nos viene perfecto. Si compilamos el código, deberíamos poder ver la imagen de nuestra WebCam, solo que no se trata de una imagen de la tag video, sino que del canvas. Ahora sí, hora de integrar JSFeat, para esto vamos a instalarlo mediante npm:

npm install jsfeat --save

Simplemente nos limitaremos a importarlo a la clase de TypeScript que necesitemos (en este caso, la misma donde aplicamos el video al canvas):

import * as jsfeat from 'jsfeat';

Solo con esto ya podremos empezar a aplicar las funciones de JSFeat, siempre llamando al objecto jsfeat antes que nada. ¿Cómo se aplica? Lo ideal es utilizar la propia función loop, y del mismo modo que con JavaScript se debe utilizar un getImageData() del contexto del canvas. La función loop quedaría entonces de este modo:

loop = () =>{
    this.context.drawImage(this.hardwareVideo.nativeElement, 0, 0, this.canvas.width, this.canvas.height);
    var imageData = this.context.getImageData(0, 0, 640, 480);

    jsfeat.imgproc.grayscale(imageData.data, 640, 480, this.img_u8);

    var data_u32 = new Uint32Array(imageData.data.buffer);
    var alpha = (0xff << 24);
    var i = this.img_u8.cols*this.img_u8.rows, pix = 0;
    while(--i >= 0) {
        pix = this.img_u8.data[i];
        data_u32[i] = alpha | (pix << 16) | (pix << 8) | pix;
    }
    this.context.putImageData(imageData, 0, 0);

    requestAnimationFrame(this.loop);
}

Aquí simplemente se aplica una función para pasar la imagen a escala de grises; lo que le sigue previo al requestAnimationFrame() es la manera de aplicar la transformación denuevo al contexto del canvas (sino por más que realice el proceso no podremos verlo). Nota: la variable this.img_u8 está creada también de formaglobal, e inicializada en el ngOnInit de este modo this.img_u8 = new jsfeat.matrix_t(640, 480, jsfeat.U8C1_t), forma parte de una clase propia de jsfeat (matrices) que se necesita para aplicar gran parte de sus funciones.

De esta manera tendremos funcionando JSFeat en un entorno Angular, permitiendo optimizar el rendimiento (más aún si cabe) en lo que producción de código se refiere. Actualmente estamos utilizando esta implementación como Resource en nuestra producción de MoldeoJS. ¿Siguiente paso? Quizás potenciar los resultados mediante el uso de GPU. Los mantendremos informados.

Repositorio del código ngJSFeat, con filtro grayscale y blur: https://github.com/ibuioli/ngJSFeat

Utilizar BLE en apps de Cordova - Android e iOS

En los diversos proyectos donde nos hemos visto involucrados, suele necesitarse una forma personalizada de capturar datos (mediante sensores), procesarlos y enviarlos a un dispositivo para su posterior uso. Lo natural es pensar en implementar Bluetooth, por su eficacia al transmitir a dispositivos cercanos y la posibilidad de implementarlo con micro-controladores Arduino. Por otro lado, es muy probable que necesitemos desarrollar una app para dispositivos móviles, que posteriormente almacene la información o la envíe a un servidor. Y así como venimos utilizando, nos interesa que dicha app se pueda desarrollar con Apache Córdova por sus posibilidades tanto en producción como en testeo al valerse de JavaScript.

Es común encontrar diversos módulos Bluetooth para Arduino, desde los primeros HM01 hasta los más modernos. El problema aparece con las compatibilidades y iOS. Los módulos HM01 son de funcionamiento sencillo, mientras que los más modernos como los HM10 y HM11 (por ejemplo, el modelo CC2541) utilizan la tecnología Bluetooth Low Energy (BLE).  Estos módulos tienen una serie de ventajas frente al resto en el mercado:

 

- Son económicos y se consiguen de diversas formas mediante importadores locales (a diferencia de los iBeacons).

- Se pueden utilizar en cualquier Arduino o incluso familias de micro-controladores que implementen comunicación Serial.

- Consumen poca energía para transmitir o recibir datos, utilizando 3.3v de Arduino y no 5v como la mayoría de los módulos.

- No necesitan ser emparejados con un dispositivo.

- No necesitan tener un disociador de voltaje en el puerto TX.

- Son compatibles con Android (a partir de la 4.3) y con iOS (es el único hardware de bluetooth compatible con iOS de todas formas).

 

Es por esto que, muy probablemente, estemos interesados en utilizarlos. Existen muchas maneras de conectar el módulo HM10/11 y no nos vamos a centrar en eso ahora. Tiene seis terminales pero solo necesitamos conectar 4: GND, VCC (3.3v, con 5v se quemará), TX y RX. En internet pueden encontrarse circuitos de complejidad baja, e incluso el código que no es más que un código donde el dato que queremos enviar por Bluetooth se debe escribir en el Serial (el Serial es conveniente generarlo nosotros, usando la librería de Arduino SoftwareSerial, asignando entonces un TX y RX personalizados).

Para el caso de una app Cordova será necesario desarrollar de forma distinta a un módulo Bluetooth convencional, y en eso si vamos a centrarnos. Para empezar, vamos a necesitar un plugin específico llamado BLE Central, el cual no tiene un ejemplo funcional para los módulos HM10/11. Aún así, podemos utilizar el ejemplo desarrollado para el módulo Adafruit Bluefruit LE, ya que su funcionamiento interno es compatible con los HM10/11 (en caso de poseer un módulo Adafruit Bluefruit LE, utilizando ese ejemplo sin modificaciones será suficiente).

El cambio dentro del código es muy sencillo y está relacionado con la UUID del módulo Bluetooth BLE HM10/11. En el ejemplo del Adafruit Bluefruit LE buscamos el archivo www/js/index.js, y ahí mismo buscamos la siguiente declaración de JavaScript:

 

// this is Nordic's UART service
var bluefruit = {
    serviceUUID: '6e400001-b5a3-f393-e0a9-e50e24dcca9e',
    txCharacteristic: '6e400002-b5a3-f393-e0a9-e50e24dcca9e', // transmit is from the phone's perspective
    rxCharacteristic: '6e400003-b5a3-f393-e0a9-e50e24dcca9e'  // receive is from the phone's perspective
};

 

Podemos ver que este fragmento simplemente declara la UUID y los puertos TX y RX que la app necesita para escuchar/enviar. Lo vamos a modificar de la siguiente manera:

 

var bluefruit = {
    serviceUUID: 'ffe0',
    txCharacteristic: 'ffe1', // transmit is from the phone's perspective
    rxCharacteristic: 'ffe1'  // receive is from the phone's perspective
};

 

Esta declaración hará que la app esté buscando todos los dispositivos con BLE y no un dispositivo en particular. Al compilar la app y ejecutarla desde un teléfono móvil (con el Bluetooth activado) podremos ver que la app va a encontrar un dispositivo llamado, generalmente, BT05 y que será nuestro Arduino conectado a un módulo BLE. También es posible encontrar dispositivos llamados unknow, que suelen tratarse de dispositivos que se encuentran cerca pero a los cuales no tenemos acceso.

Migrando la impresora fiscal a v9

Bueno... es eso. Es todo un trabajo, para nada trivial. Por lo pronto hay que agregar el router /web/database/get_list e implementarlo en Odoo. Así que va a llevar su esfuerzo, no es un cambio de API como uno se imaginaba al principio. Luego de eso, seguiremos trabajando para que desde la extensión se pueda acceder Odoo. Y una vez que pasó eso, debe poderse desde la extensión de Chrome ejecutarse un test-corto, y luego un test largo. El paso siguiente es poder realizar lo mismo con el módulo odoo_fpoc.

Así que lo vamos a mantener al tanto del trabajo