Wednesday, May 18, 2022

¿Qué es Nylas, por qué me uní y porque debería importarles?



Me uní a Nylas más o menos hace 4 meses como su primer Senior Developer Advocate. Puede parecer un tiempo muy corto, pero en el mundo de los startups, el tiempo se mueve de forma diferente.

Aviso: Este post está escrito en Español, pensado en desarrolladores de habla hispana, pero no significa que Nylas ofrezca contenido, soporte o servicios en Español. Todo servicio es ofrecido únicamente en Inglés.

¿Qué es Nylas?


En palabras sencillas, Nylas es un grupo de APIs que nos permiten conectarnos de manera sencilla con cualquier proveedor de correo, calendario y contactos sin tener que pasar por ningún tipo de proceso largo y tedioso.

En otras palabras, hacemos el trabajo pesado para que ustedes puedan enfocarse en tu negocio.


Si hablamos de Email, ofrecemos “Un API de Correo para cualquier proveedor”. Esto significa que nuestro API de Correo es universal y puedes conectarte con varios proveedores sin tener la necesidad de escribir código específico para cada uno de ellos. Además, proveemos capacidades de tiempo real, sincronización bi-direccional, y full CRUD (Crear, Leer, Actualizar, Borrar). Si quieres saber más, solo tienes que ir a nuestra página Universal Email API.


Cuando se trata de Calendarios, ofrecemos las mismas capacidades que en nuestro API de Correo API, pero también sincronización de conferencias, metadata de eventos, y webhooks programables. Si quieres saber más, solo tienes que ir a nuestra página Universal Calendar API.


Si hablamos de Contactos, podemos crear, actualizar o eliminar contactos en cualquier proveedor compatible. Si quieres saber más, solo tienes que ir a nuestra página Universal Contacts API.


Con APIs para Correos, Calendarios, y Contactos, solo estamos comenzando. Miren que más ofrecemos por encima de esos APIs para proveer a los desarrolladores aún más poder.

Con Neural API, explorar el mundo de AI y ML es muy sencillo, con modelos listos para utilizar que pueden ser utilizados para limpiar conversaciones, extraer firmas, realizar OCR, y ejecutar análisis de sentimientos. Si quieres saber más, solo tienes que ir a nuestra página Neural API.With Neural API, exploring the world of AI and ML is easy, with ready-made models that can be used to clean conversations, extract signatures, perform OCR, and run sentiment analysis. If you want to learn more, just go to our Neural API page.


Nylas Streams es nuestra solución ETL que requiere muy poco o nada de código para transformar y consumir datos de comunicaciones para E-Commerce, Ventas, Fintech y Customer Success. Si quieres saber más, solo tienes que ir a nuestra página Nylas Streams.


Scheduler, un organizador completo con UI configurable. Si quieres saber más, solo tienes que ir a nuestra página Scheduler.


Components, widgets UI/UX completamente flexibles y listos para utilizar inmediatamente. Si quieres saber más, solo tienes que ir a nuestra página Components.


¿Por qué me uní?


Lo primero que llamó mi atención fue el hecho de que Nylas provee APIs que hacen que el manejo de comunicaciones sea mucho más sencillo. Manejar Correo, Calendarios y Contactos brinda mucho espacio para poder crear aplicaciones impresionantes.

Lo segundo que me atrajo de Nylas fue la cultura de la compañía. Todos se ven comprometidos los unos a los otros, puesto que vi mucho apoyo mutuo cuando la cuenta de Nylas posteaba algo en las redes sociales, y también mis entrevistas fueron más una conversación entre amigos que una entrevista de trabajo.

Lo tercero y probablemente más importante para mí, fue poder regresar a Developer Advocacy, que es algo que realmente me apasiona. Poder compartir con la comunidad de desarrolladores es algo que me hace sentir bien y que me hace una mejor persona y un mejor desarrollador.

Obviamente, estas 3 cosas no van a ser suficientes para convencerlos, así que he creado un par de pequeños ejemplos.

Para esto voy a utilizar uno de mis lenguajes de programación favoritos– R. Y aunque no soy un profesional de R ni tampoco un experto, es algo que me encanta, así que tenganme paciencia, deben hacer una manera mucho mejor de hacer esto.

Lo que vamos a hacer, es simplemente leer los primeros tres mensajes de nuestro inbox e imprimir los títulos.


El resultado va a ser:

A Nylas email 
Invitation: RRSP Webinar @ Tue Feb 8, 2022 1pm - 2pm (EST) (alvaro.t@nylas.com) 
Start here: Welcome to Clockwise


Obviamente, aunque R es un lenguaje asombroso utilizado por Estatistas y Data Scientists alrededor del mundo, no es un lenguaje utilizado por las masas.

Es por esto que Nylas provee SDKs para Python, Ruby, Node, y Java.

Veamos como podemos leer nuestro inbox utilizando el SDK de Python. Si quieres saber como instalar el SDK, puedes leer nuestra documentación Python Documentation.


El resultado va a ser:

A Nylas email 
Invitation: RRSP Webinar @ Tue Feb 8, 2022 1pm - 2pm (EST) (alvaro.t@nylas.com) 
Start here: Welcome to Clockwise

Como podemos ver, utilizar el SDK es mucho más sencillo, porque no tenemos que navegar la respuesta JSON ni tampoco averiguar que número de elemento tenemos que imprimir. Además, si algo cambia internamente podemos estar tranquilos y saber que el SDK va a ser actualizado para reflejar cualquier cambio mientras que llamar directamente al API va a requerir trabajo manual extra. Y lo mismo sucede con el Calendario, Contactos y el resto de nuestras propuestas.

¿Por qué debería importarles?


Bueno, para empezar, soy su amigable Developer Advocate así que ya saben que voy a mantenerlos informados con información constante e interesante acerca de las APIs de Nylas. Además, crearse una cuenta en Nylas es sencillo, no se necesita tarjeta de crédito y obtenemos 14 días para probar el producto. Listos para comenzar? Solo deben ir a https://dashboard.nylas.com/register y seguir las instrucciones.

Además, estoy trabajando en una serie de posts para ayudarlos a dar sus primeros pasos, hacer sus primeras llamadas a las APIs y en general, ayudarlos a obtener lo mejor de su experiencia con Nylas.

Pueden comenzar leyendo mi post How to Send Emails with the Nylas Python SDK

¿Piensas que Nylas no es para ti? Bueno, entonces recomiéndanos con tus amigos. Puedes conocer a alguien que se puede beneficiar de tener una manera rápida, sencilla y conveniente de acceder a APIs universales de comunicación.

Saturday, January 26, 2019

Un Vector Interior

Cuando terminé mi blog llamado “Hey Vector, a quien me parezco?” utilizando el Vector de Anki y los API's de Machine Learning de SAP Leonardo…Comencé a pensar en que debería empezar a trabajar…primero…obviamente me estaba quedándo sin ideas…pero después…de pronto…se ocurrió una buena idea…que pasaría si pudieramos controlar a Vector…desde adentro? Es decir…que pasaría si pudieramos simular que estamos adentro de Vector y que pudieramos ver a través de sus ojos y pudieramos controlarlo…

Así como el proyecto se inició 😉


La Idea


Así que, sabía que quería poder controlar a Vector…podía utilizar Amazon Alexa, pero por supuesto…eso dejaría fuera la parte “interior”…así que no era una opción…luego pensé en utilizar Unreal Engine…puesto que ya lo había utilizado para mi blog “API's de SAP Leonardo Machine Learning en el Go” donde utilicé las APIs de Machine Learning de SAP Machine, Unreal Engine y Oculus Go para poder demostrar las APIs de SAP Leonardo. Utilizar Unreal Engine y Oculus Go sonaba como la combinación perfecta, así que comencé a trabajar en eso.


Que vamos a utilizar?


Yo se que he mencionado muchas cosas…así que vamos a obtener un poco más de información 😉

Vector

La evolución de Cozmo por parte de Anki. Vector no solo trae más potencia y más independencia pero también un micrófono, así que finalmente puedes hablarle 😉 y además viene con Amazon Alexa…así que es un impresionante robotito…

Unreal Engine

Unreal Engine es sin lugar a dudas “El motor de creación más potente”. Puede ser programado utilizándo C++ o Blueprints (Programación Visual) y lo mejor de todo…es totalmente gratuito! A menos que hagas juegos comerciales que se vendan…en ese caso ellos solo piden el 5%


Blender

Blender es un paquete de creación de 3D Open Source. Modelamiento, rigging, animación, simulación, renderizado y un largo etcetera…incluído en la version 2.8, viene EEVEE (Extra Easy Virtual Environment Engine) un motor de renderizado en tiempo real.


HANA Cloud Platform

Base de Datos In-Memory orientada a columnas de SAP que corre en la nube. Que incluye Predictive Analysis, Spatial Data Processing, Text Analysis y mucho más. Además, es extremadamente veloz 😉


Python3

Lenguaje de programación interpretado de alto nivel y multipropósito. Es el lenguaje elegido para programar a Vector.



El Primer Problema


Como quería ver a través de los ojos de Vector…necesitaba mostrar el canal de video de Vector dentro de Unreal Engine…me la pasé buen tiempo pensándo como podía hacer eso…pero al final recordé que cuando utilizar el Microsoft HoloLens y lo enlazas a tu laptop para “streaming”, siempre hay un retrazo de 1 o 2 segundos…luego por supuesto recordé que los videos son solo cientos de imágenes que se muestran en secuencia a una velocidad muy alta…no me importa mucho la velocidad o estar cerca de tiempo real…tener un retrazo de 1 o 2 segundos…no algo tan malo...para nada…

Bueno…los problemas continuaron…Sabía que quería que Vector tome un foto cada 1 o 2 segundos…y luego esa imagen debería llegar a Unreal Engine…y fuera del hecho de que programo en Python en mi Ubuntu de mi Maquina Virtual y Unreal Engine en mi laptop Windows…no me convencía mucho la idea de mandar la imagen como un archivo…así que…Se me ocurrió codificar la imagen en Base 64 (Lo cual, sí…incrementa el tamaño…pero por lo menos te brinda un extremadamete largo String el cual puedes manipular) y enviarlo…pero cómo? Bueno…SAP Cloud Platform es un Base de Datos In-Memory…así que muy rápida…por qué no crear algunos REST APIs para poder manejar la creación , visualización y eliminación de los registros?…


Cada vez que Vector toma una imagen...se convierte a Base 64 y luego se envía a la nube, luego Unreal Engine lee el API, decodifica el Base 64 de nuevo a una imagen y lo muestra…eso me llevó a un segundo problema…

El Segundo Problema


Como codifico una imagen a Base 64 en Unreal Engine? Si bien se utilizar C++ bastante bien…cuando se trata de Unreal Engine por lo general utilizo Blueprints, que es programación visual y aunque en el fondo es C++, no todo está implementado…

Afortunadamente, una rápido paseo por la documentación de Unreal me dió la respuesta en la forma de una función que codifica/decodifica en Base 64…pero en C++ por supuesto…

Pero…lo bueno de Unreal Engine es que puedes crear un proyecto en C++…implementar tu clase de codificación de Base 64 y comenzar a crear Blueprints para consumirla…otro problema resuelto…

Eso fué lo que pensé…pero luego me di cuenta de que no era solo cuestión de tener la imagen de nuevo como una imagen…En realidad necesitaba un material dinámico donde pudiera mostrar las imágenes…busqué en la web y encontré algunos artículos interesántes…pero nada que pudiera ayudarme en realidad…al final…tomé partes de aquí y allá y lo mezcle con mi propia investigación…para finalmente hacerlo funcionar…

Y sí…si le estan preguntándo…había otro problema…

El Tercer Problema


Todo estaba funcionando bien y bonito…probé mi aplicación…inicialmente pasándo algunas imágenes en sequencia a la nube y luego a Unreal y luego utilizándo Vector…con un retrazo de 1 o 2 segundos…se vería como un video corriendo en un celular antiguo con una conexion a Internet barata en medio del desierto…lo suficientemente bueno para mí 😉

Pero…se supone que estamos dentro de Vector, no? Como se suponía que podía simular eso? Luego de no pensarlo por mucho tiempo…decidí utilizar Blender 2.8 el cual está actualmente en Beta 😊 y que viene con EEVEE (Que es un renderizador en tiempo real asombrozo). Hice un pequeño cuarto de control…con algunos botones y paneles llamativos…una silla donde poder sentarse mientras se está controlándo a Vector y una pantalla para poder vez lo que Vector está mirándo….

El Baking no está funcionándo en este momento…o por lo menos soy muy torpe para poder darme cuenta de como se utiliza en 2.8, así que utlizar texturas en Cycles estaba descartado…entonces…hice una prueba en EEVEE utilizándo solo materiales simples…la exporté a .FBX y funcionó perfectamente! Así que, comencé a trabajar y a probarlo en Unreal…por supuesto…no soy un experto en Blender, así que a pesar de que todo se ve bien…no todos los colores fueron renderizados corractement ☹ At least it looks fairly decent 😉

No más problemas


Así es…no es que todo haya funcionado bien y sin errores…pero por lo menos esos fueron los errores o problemas más críticos…así que finalmente podemos empezar con el post -:P 

Blender y El Cuarto de Control


Como ya lo dije…utilicé el renderizado de EEVEE en Blender 2.8 Beta para crear un cuarto de control que pudiera, de alguna manera, dar la impresión de estar dentro de Vector…por supuesto…una versión total y completamente poética porque a) Quién sabe como se ve Vector por adentro? b) No creo que haya suficiente espacio dentro de Vector como para poder acomodar nada más.

Primero, comencé poniendo algunos botones, perillas y teclados a un panel…luego añadí una especie de radares con deslizadores…


Luego, pensé que algunos interruptores y botones de varios colores serían una interesánte adición…


Finalmente, agregué una silla…porque tenemos qu entarnos en algun lugar, no?


La pantalla es simplemente un espacio vacio…casi igual que en un cine…


Miren, muy bonito en Blender, no? Bueno…no mucho en Unreal…no feo…ciertamente no optimizado…probablemente debido al echo de que uní todo y lo exporte como un bloque grande…pero eso está bien…no pienso cambiar eso…soy flojo 😊


Ya ven…no perfecto…pero tampoco mal 😉

Aquí está el archivo .FBX

Creándo las tablas y APIS en HANA Cloud Platform


El siguiente paso…Creé dos tablas en HANA Cloud Platform…Llamé a la primera tabla “VECTOREYES” porque es la tabla que va a contener las imágenes en Base 64. Aquí está el script para crear la tabla…

CREATE COLUMN TABLE "I830502"."VECTOREYES"(
 "TIMESTAMP" LONGDATE CS_LONGDATE NOT NULL,
 "VECTOREYE" CLOB MEMORY THRESHOLD 3000,
 PRIMARY KEY (
  "TIMESTAMP"
 )
) UNLOAD PRIORITY 5 AUTO MERGE;

Para la llave primaria utilicé un TIMESTAMP basicamente porque quería que si algo pasara en terminos de conexión no hubieran errores de llave repetida…

La siguiente tabla se llamará “VECTORCOMMAND” y va a contener…los comandos que vamos a enviar a Vector…

CREATE COLUMN TABLE "I830502"."VECTORCOMMAND"(
 "NID" INTEGER CS_INT,
 "COMMAND" NVARCHAR(50),
 PRIMARY KEY (
  "NID"
 )
) UNLOAD PRIORITY 5 AUTO MERGE;

En este caso…siempre va a existir un solo comando…así que utilicé una llave primaria simple de número entero.

Con las tablas creadas, podemos generar nuestro paquete de XS Engine…y simplemente llamarlo “VectorEyes”.

Debemos crear los siguientes archivos…

.xsaccess
{
     "exposed" : true,  
                  
     "authentication" :                                            
            {
               "method": "Basic"   
            },
  
     "cache_control" : "must-revalidate", 

     "cors" :                      
            {
             "enabled" : true,
             "allowMethods": [
   "GET",
   "POST",
   "HEAD",
   "OPTIONS"
   ]
            }, 
                     
     "enable_etags" : false,

     "force_ssl" : false,
     
     "prevent_xsrf" : false
}


.xsapp


Sip…no es un error…este archivo está total y completamente vacío…


AddVectorEye.xsjs
$.response.contentType = "text/html";

var conn = $.db.getConnection();

var content = $.request.body.asString();
content = JSON.parse(content);

var st = conn.prepareStatement("INSERT INTO \"YourSchema\".\"VECTOREYES\" values(?,?)");

st.setString(1,content.timestamp);
st.setString(2,content.vectoreye);

st.execute();
conn.commit();
st.close();
conn.close();

GetAddVectorEye.xsodata
service namespace "YourSchema"{
 "YourSchema"."VECTOREYES" as "vectoreye";
}

DeleteVectorEye.xsjs
$.response.contentType = "text/html";

var conn = $.db.getConnection();

var st = conn.prepareStatement("DELETE FROM \"YourSchema\".\"VECTOREYES\"");

st.execute();
conn.commit();
st.close();
conn.close();

Con esto, podemos insertar, leer o borrar la tabla VECTOREYES. Continuemos con los archivos para la tabla VECTORCOMMAND

AddVectorCommand.xsjs
$.response.contentType = "text/html";

var nid = $.request.parameters.get("nid");
var command = $.request.parameters.get("command");

var conn = $.db.getConnection();

var st = conn.prepareStatement("INSERT INTO \"YourSchema\".\"VECTORCOMMAND\" values(?,?)");

st.setString(1,nid);
st.setString(2,command);

st.execute();
conn.commit();
st.close();
conn.close();


GetVectorCommand.xsodata
service namespace "YourSchema"{
 "YourSchema"."VECTORCOMMAND" as "vectorcommand";
}


DeleteVectorCommand.xsjs
$.response.contentType = "text/html";

var conn = $.db.getConnection();

var st = conn.prepareStatement("DELETE FROM \"YourSchema\".\"VECTORCOMMAND\"");

st.execute();
conn.commit();
st.close();
conn.close();

Eso es todo 😊 Simplemente debemos activarlos y probarlos…de hecho que Postman es la mejor herramienta para esto 😉

 Creándo nuestro proyecto en Unreal Engine


Como mencioné anteriormente...Creé un proyecto vació de C++ utilizándo Mobile/Tablet, Scalable 3D or 2D y No starter content. Utilicé Unreal Engine versión 4.21.1 y llamé al proyecto “VectorOculusGo”




Cuando el proyecto está abierto, seleccioné “File --> New C++ Class”, y escogí “Actor”.


Llamé a la clase, “ImageParser” y utilicé los siguientes códigos para “ImageParser.h” y “ImageParser.cpp”

ImageParser.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ImageParser.generated.h"

UCLASS()
class VECTOROCULUSGO_API AImageParser : public AActor
{
 GENERATED_BODY()
 
public: 
 // Sets default values for this actor's properties
 AImageParser();

protected:
 // Called when the game starts or when spawned
 virtual void BeginPlay() override;

public: 
 // Called every frame
 virtual void Tick(float DeltaTime) override;

 UFUNCTION(BlueprintCallable, Category = "ImageParser")
  void ParseImage(FString encoded, TArray &decoded);
};

Aquí estamos creándo una función que será llamada desde Blueprints. Va a recibir un String y va a retornar un arreglo de Enteros.

ImageParser.cpp
#include "ImageParser.h"
#include "Misc/Base64.h"

// Sets default values
AImageParser::AImageParser()
{
  // Set this actor to call Tick() every frame.  
        // You can turn this off to improve performance if you don't need it.
 PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AImageParser::BeginPlay()
{
 Super::BeginPlay();
 
}

// Called every frame
void AImageParser::Tick(float DeltaTime)
{
 Super::Tick(DeltaTime);

}

void AImageParser::ParseImage(FString encoded, TArray &decoded)
{
 FBase64::Decode(encoded, decoded);
}

Aquí, simplemente llamamos al método Decode de la librería Base64. Esta va a tomar el String en Base 64 y convertirlo de vuelta a una imagen.

Para poder compilarlo, solo debemos hacer click derecho en el nombre del proyecto y seleccionar “Debug --> Start new instance”.


Una vez que la compilación termino, podemos simplemente para el debugging.

Antes de continuar…debemos descargar una librería para poder manajer APIs…se llama JSONQuery y es impresionante!

Simplemente, debemos cerrar Unreal, ir a la carpeta del proyecto y crear una nueva carpeta llamada “Plugins”, luego descargamos el .zip, lo descomprimos dentro de la carpeta “Plugins” y borramos las carpetas Binaries and Intermediate.

Luego, deberemos cambiar el código fuente un poco…

Dentro de la carpeta “JSONQuery”, debemos ir a “Source --> JSONQuery --> Classes --> JsonFieldData.h” y buscar “GetRequest”.

Luego de const FString& url debemos agregar const FString& auth

Luego debemos abrir “Source --> JSONQuery --> Private --> jsonfielddata.cpp” y volver a buscar “GetRequest”.

Aquí, agregamos el mismo const FString& auth.

Luego de HttpRequest->SetURL(CreateURL(url)); debemos agregar lo siguiente…

HttpRequest->SetHeader(TEXT("Authorization"), auth);

Guardamos ambos archivos y abrimos nuestro proyecto. Vamos a recibir un mensaje diciendo que parte de nuestro código necesita ser recompilado. Así que simplemente acepta y espera un poco hasta que todo haya sido compilado 😊

Para revisar que todo está bien, debemos ir a “Settings --> Plugins” e ir hasta el final hasta encontrar “Project --> Web” y JSON Query debería estar seleccionado. 😉




Excelente, ahora podemos continuar.

Para poder hacer que nuestro proyecto funciones con el Oculus Go, debemos configurar un par de cosas.

Configurándo el Oculus Go


Tu debes querer configurar tu Oculus si es que no lo haz hecho todavía 😊 Aquí le dejo un enlace muy interesánte con toda la explicación necesaria …

Configurándo Unreal para Oculus Go


Necesitamos instalar “Code Works for Android” que en realidad está incluído dentro de la instalación de Unreal. Así que, vamos a “Program Files --> Epic Games --> UE_4.21 --> Engine --> Extras --> AndroidWorks --> Win64” y ejecutamos “CodeWorksforAndroid-1R7u1-windows.exe”.

Nos daremos cuenta de que estamos dentro de la carpeta C++ Classes, así que haz click en el ícono de carpeta que está al lado y selecciona “Content”.



No prestemos atención a las carpetas por el momento.

Primero, grabemos el mapa por defecto y lo llamaremos “MainMap”. Luego vamos a “Edit --> Project Settings”. Busquemos “Maps & Modes” y seleccionemos “MainMap” en ambos “Editor Startup Map” y “Game Default Map”.


Luego debemos bajar y seleccionar “Engine --> Input”. En la sección “Mobile” debemos establecer la Default Touch Interface como None.


Nos movemos más abajo hasta “Platforms” y seleccionamos “Android”. Debemos hacer click en “Configure Now”. Luego nos movemos a “Android”. Y establecemos el minimum y target SDK version a “19”.

También debemos hacer click en “Enable Fullscreen Immersive on KitKat and above devices” para activarlo.

Buscamos “Configure the AndroidManifest for Deployment to Oculus” y lo activamos también.

Ahora, debemos hacer click en “Android SDK” y revisar la configuración. Si no tenemos las Variables del Sistema configuradas, entonces simplemente asignamos las rutas de las carpetas.

Finalmente, nos vamos a “Engine --> Rendering” y nos asegurámos de que “Mobile HDR” no esté seleccionado.

Si algo no está claro, simplemente vayan a este enlace 😉 

Listo, ahora finalmente podemos continuar 😊

Creándo un Material Dinámico


Hacemos click en “Add New --> Material” y lo llamamos “Dynamic_Mat”. Una vez dentro del editor de materiales, hacemos click derecho en un espacio vacio y buscamos “TextureSampleParameter2D”.




Una vez creado, lo llamaremos “Texture_Sample”. Viene con una textura por defecto que puedes cambiar si así lo quieres (Pero al final no importa si la cambias o no). Simplemente conecta el primer output al “Base Color” del nodo de “Dynamic_Mat”.


Grabalo y será aplicado automáticamente. Lo mejor de esta configuraciín es que Param2D es dinámico 😉 

Creándo nuestro primer Blueprint


Debemos crear una nueva carpeta llamada “Blueprints”. Aquí vamos a crear la pantalla donde las imágenes que vienen desde Vector van a ser mostradas.

Presionamos “Add New --> Blueprint Class”.


En vez de escoger “Actor” como la clase padre…vamos hacia abajo a “All Classes” y buscamos “Image Parser” y lo seleccionamos como clase padre.


Lo llamamos “ImageRenderer”.

Una vez creada, nos vamos a la pestaña Viewport y presionamos “Add Component --> Cube”. Simplemente le cambiamos la escala a “0.01, 1.0, 1.0”.



Luego nos vamos a la pestaña “Event Graph”. Aquí es donde vamos a construir nuestros Blueprints.

Pero primero, debemos crear un par de variables.

CubeMaterial --> Material Instance (Object Reference)


Este va a ser el material del cubo que hemos creado.

TempImg --> Texture 2D (Object Reference)


Aquí es donde vamos a almacenar la imagen luego de haber convertido de Base 64.

TempMat --> Material Instance (Object Reference)

Este es el material dinámico que vamos a asignar a nuestro cubo.

ImageJSON --> String

Este es el resultado de llamar al API…el String en Base 64.

Con las variables preparadas, podemos empezar creándo la primera parte del Blueprint.


Aquí, estamos diciendo que una vez que nuestra aplicación inicie (Event BeginPlay) vamos a llamar a una función llamada “Set Timer by Function Name”. Esta función va a llamar a otra función cada 2.0 segundos (puesto que hemos marcado Looping value). La función que llamaremos será “MyEvent”.



Aquí, estamos llamándo a la función “MyEvent”, la cual llamará a “Get JSON Request” pasándole el URL y el Auth. Esto estará enlazado al evento “OnGetResult”. El resultado de la llamada al JSON será extraída utilizándo Get Object Field, Get Object Array Field, un For Loop y finalmente un Get String Field para poder obtener la imagen en Base 64 y guardarla en la variable ImageJSON.


Luego de establecer la variable ImageJSON, llamamos a la API para borrar la tabla. Luego de esto…las cosas se ponen interesántes…


Aquí estamos llamándo a nuestra Clase en C++ “Parse Image” como si fuera otro elemento de Blueprints. Obtenemos el valor almacenado en ImageJSON para que sea decodificado como imagen. El resultado de decodificar en la cadena en Base 64 va a ir hacia “Import Buffer as Texture 2D”, el cual va a ir a la variable TempImg. Luego de esto “Create Dynamic Material Instance” va a aplicar un material dinámico a nuestro material Dynamic_Mat y asignarlo a TempMat que va a ser pásado como el destino de Set Texture Parameter Value, mientras que TempImg va a ser pasado como el valor de parámetro. Finalmente, un nodo Set Material va a establecer el material TempMat al cubo.

Para hacerlo más simple…tomamos la cadena en Base 64…la convertimos en imagen…creámos un material dinámico, lo utilizamos como valor para nuestro material dinámico y finalmente lo asignamos a nuestro cubo. Cada vez que obtengamos un nuevo valor en Base 64, obtendremos una nueva imagen y nuestro cubo podrá mostrárlo 😉

Importándo nuestro Modelo de Blender


Ahora, necesitamos simular que estamos dentro Vector…por lo tanto…debemos importar nuestro de Blender en formato .FBX 😉

Simplemente presionamos Import y seleccionamos el archivo .FBX  que pueden obtener en este enlace. Presionamos Import All y lo tendremos en pantalla.

Cambiemos los siguientes parámetros…


Ahora, agregamos un Point Light con los siguientes parámetros…


Luego, selecionamos el Blueprint “ImageRenderer” y lo arrastramos a la pantalla. Debemos cambiar los parámetros así…


Luego, presionamos “Build” y esperamos a que todo (incluídas las luces) sean construídas.


Una vez que termina…tendremos esto…


Impresionante! Todo está comenzándo a tomar forma 😊 Pero ahora…debemos añadir el verdadero soporte para Oculus Go 😉

Añadiéndo soporte para Oculus Go


Así que, configuramos nuestro proyecto para que trabaje en el Oculus Go…pero eso no es suficiente 😉 Debemos hacer un par de cosas extras…y por supuesto…y más importánte…debemos añadir una forma de controlar a Vector utilizándo el control del Oculus Go 😊

Creamos una nueva carpeta y la llamamos “Modes”. Luego creamos una nueve “Blueprint Class” pero esta vez escogemos “Pawn” y lo llamamos “Pawn Blueprint” (Ingenioso, no?).

Cuando carga, debemos ir a la sección de la izquierda y seleccionar “DefaultSceneRoot”, luego hacer click en “Add Component” y seleccionar “Scene” y cambiarle el nombre a “VRCameraRoot”.

Seleccionamos “VRCameraRoot” y agregamos un componente de “Camera”, y lo llamamos “VRCamera”.

Seleccionamos “VRCameraRoot” y agregamos un componente "Motion Controller", y lo llamamos “OculusGoController”.

Seleccionamos “OculusGoController” y agregamos un componente "Static Mesh", y lo llamamos “OculusGoMesh”.

Para hacer las cosas claras…aquí les dejo una imagen 😊


Con el “OculusGoMesh” seleccionado, vamos a sus propiedades y en la Static Mesh, escogemos el mesh “OculusGoController”.


Luego de esto, debemos crear algunas variables…la primera se llamará “CameraHeight” y será un “Vector” editable.



La segunda será llamada “request” y será un Json Field Data (Object Reference).

Finalmente, creamos una llamada “Lift” de tipo Boolean y una variable String llamada “Var”.



Si están preguntándo por el ojo al lado de “CameraHeight”, eso simplemente significa que es “Pública”, y puedes cambiarlo simplemente haciendo click en el ícono.

Ahora, podemos continuar con la pestaña “Event Graph”.


Aquí, queremos que  cuando la aplicación empiece (Evento BeginPlay) el tracking origin se posicione al nivel de nuestros ojos. El nodo SetRelativeLocation será llamado donde el destino será VRCameraRoot y la nueva ubicación será asignada en CameraHeight. En otras palabras, lo que vamos a ver va a estar al nivel de nuestros ojos.



Cuando presionamos el Thumbstick Arriba o Adelánte, Izquierda o Derecha, asignamos el resultado a nuestra variable Var, luego llamamos a la función Get JSON Request. El URL va a ser la direeción del API más el valor de la variable Var.


Aquí, queremos presionar el boton “Back” del Control del Oculus. La primera vez que lo presionamos, la variable  “Lift” va a ser "Falsa", así que la hacemos “Verdadera”. Si es “Verdadera” entonces enviamos el comando “up”. Si presionamos nuevamente, lo volvemos “Falsa” y pasamos el comando “down”. De esta manera podemos controlar como Vector mueve su brazo.

Listo, compilamos, salvamos y listo 😊 Simplemente debemos agregarlo a nuestra escena. Así que, arrástrenlo y cambiemos estos parámetros.


Además, esto es muy importánte…


Auto Possess Player debería de ser Player 0.

Ahora, presionamos “Build” y esperámos a que todo (incluídas las luces) se compilen.

Luego presionamos Play…y veremos esto…



Por supuesto, si tratan de mover su mouse…nada va a pasar…así que necesitamos enviarlo al Oculus Go 😉

Para hacer esto, simplemente anda a Launch y selecciona tu dispositivo…va a tomar mucho tiempo la primera vez porque todos los shaders, Blueprints y demás, necesitan ser compilados…pero luego de eso, podrás ponerte tu headset y dar un vistazo 😊 Aunque, sin embargo…no va a poder ver nada en la pantalla porque aún necesitamos tener a Vector listo y funcionándo 😉

Instalándo el SDK de Vector


Primero, debemos asegurárnos de que Vector está conectado a Internet utilizándo la aplicación de Vector en nuestro celular…aquí hay un video muy interesánte de como hacerlo…

Una vez que lo haz revisado, corta la aplicación en tu celular…puesto que podría interferir con tu aplicación, la cual va a solicitar el control de Vector…

Puedes instalar el SDK escribiéndo lo siguiente

python3 -m pip install --user anki_vector

Luego…auntenticar tu Vector escribiéndo…

python3 -m anki_vector.configure

Se te pedirá el nombre de Vector’s, su dirección IP y número de serie. Además, se te pedirán tus credenciales del Anki Cloud.

Para obtener esta información, simplemente coloca a Vector en su cargador…y presiona su cabeza dos veces. Esto te dará su nombre, luego sube y baja su brazo para poder obtener el IP. El número de serie está en la parte de abajo de Vector’s.

Creándo el Script de Vector


Este script es la última parte de nuestra aventura 😊 Simplemente debemos crear un nuevo archivo llamado VectorOculusGo.py

VectorOculusGo.py
import anki_vector  #Control Vector
import requests  #Use REST APIs
import json  #Consume JSON
import time  #Manage time
from anki_vector.util import degrees, distance_mm, speed_mmps
import base64 #Encode/Decode images
import datetime  #To get time and data

#URLs to manage upload of Base 64 images and to control Vector using the 
#Oculus Go controller
urlAddEye = "https://YourHANA.ondemand.com/VectorEyes/AddVectorEye.xsjs"
urlGetCommand = "https:// YourHANA.ondemand.com/VectorEyes/
                 GetVectorCommand.xsodata/vectorcommand"
urlDeleteCommand = "https:// YourHANA.ondemand.com/VectorEyes/
                    DeleteVectorCommand.xsjs"
   
def main():
    #We stablish a connection with Vector and enable his camara
    robot = anki_vector.Robot(enable_camera_feed=True)
    #We connect to Vector
    robot.connect()
    i = 0
    #We want this to loop forever…until we close the program
    while i == 0:
        #We instruct Vector to take a pictures
        image = robot.camera.latest_image
        #And save it
        image.save("./img/Temp.png")
        #Once saved, we open it
        with open("./img/Temp.png", "rb") as imageFile:
            #We get the time and create a timestamp
            ts = time.time()
            timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
            #We enconde the picture as an Base 64 string
            strImg = base64.b64encode(imageFile.read())
            #The payload is the parameters that we are sending to the REST API 
            payload = "{\"timestamp\":\"" + timestamp + "\",\"vectoreye\":\"" + 
                        strImg.decode('ascii') + "\"}"  

            #In the headers, we pass the authentication for the REST API        
            headers = {
                'Content-Type': "application/x-www-form-urlencoded",
                'Authorization': "YourAuthorization",
            }

            #We upload the Base 64 string of the image to the DB
            response = requests.request("POST", urlAddEye, data=payload, headers=headers)
            #We put the application to sleep for 2 seconds just not to overload the DB
            time.sleep(2)
            querystring = {"$format":"json"}
            #Right after uploading the Base 64 string, 
            #we want to get any commands coming through
            response = requests.request("GET", urlGetCommand, headers=headers, 
                                        params=querystring)
            #We convert the response to JSON
            json_response = json.loads(response.text)
            #We need to check if there’s any information first and then extract the command
            try:
                json_text = json_response['d']['results'][0]['COMMAND']
            except:
                json_text = ""
            #Depending on the command, we make Vector move forward, backward or 
            #lift his handle. If the lift was already up, we put it down first…
            if (json_text == 'forward'):
                robot.behavior.drive_straight(distance_mm(50), speed_mmps(50))
            elif (json_text == 'backward'):
                robot.behavior.drive_straight(distance_mm(-50), speed_mmps(50))
            elif(json_text == 'right'):
                robot.behavior.turn_in_place(degrees(-90))
            elif(json_text == 'left'):
                robot.behavior.turn_in_place(degrees(90))
            elif(json_text == 'up'):
                robot.behavior.set_lift_height(0.0)
                robot.behavior.set_lift_height(1.0)
            elif(json_text == 'down'):
                robot.behavior.set_lift_height(0.0)
            #After receiving the command, we simply delete it from the DB
            response = requests.request("GET", urlDeleteCommand, headers=headers)
                
if __name__ == '__main__':
    main()

Excelente, el código es bastante sencillo…pero aún así…veamos que sucede con esta aplicación…

Queremos que Vector tome una foto cada 2 segundos…una vez que la foto es tomada, queremos convertirla a una cadena de Base 64 y luego junto con un Timestamp (que es un día con horas, minutos y segundos) enviarlo a la Base de Datos. Una vez que eso está hecho…descanzamos por 2 segundos y revisamos si hay algún comando disponible. Si hay alguno, hacemos que Vector actué de acuerdo al comando…y simplemente para evitar estar repitiéndo el mismo comado…simplemente lo borramos de la Database, y así podemos tranquilamente enviar un nuevo comando.

Juntando todo


Perfecto! Ahora tenemos nuestra aplicación ejecutándose en el Oculus Go y nuestro Vector listo para ejecutar nuestro script.

Entonces…ten listo un CMD o Terminal y escribe lo siguiente…

python3 VectorOculusGo.py

Colocate tu lentes Oculus Go, agarra tu control y presiona “Enter” en tu teclado. Nuestro script comenzará a ejecutarse y verás lo que Vector está mirándo…algo como esto…


Yo lo sé…eso está funcionándo en Unreal Engine y no en el Oculus…pero para eso es el video 😉


Espero que le haya gustado este blog y disfruten controlar a Vector desde el interior! -:D

Saludos,

Blag.
SAP Labs Network.