Category Archives: Conceptos

Comandos por BLE – (Parte 2 de 2) – El Transmisor (TX)

22 Jul , 2017,
Jose Nunez
, , , , , ,
No Comments

Como lo prometido es deuda, acá está la 2da entrega referente a controlar cosas con telefonos celulares mediante Bluetooth Low Energy (BLE) usando IONIC 3.

En esta segunda parte, implementaremos una App (Android y IOS) usando IONIC 3 que le envía comandos al micro-controlador mediante el sistema BLE del teléfono.

Para ver la Parte 1 haz clic acá

(!) Antes de seguir estas instrucciones asegúrese de entender las Condiciones de Uso de nuestro sitio.

Programando el App

En resumen:

  1. IONIC 3 es un sistema para crear aplicaciones móviles usando tecnologías híbridas (cordova, angularjs 4, typescript, html, css, etc.)
  2. Necesitaremos configurar IONIC3 en nuestro computador; esto incluye NodeJS, NVM, NPM y IONIC.
  3. También necesitaremos un muy buen editor de código para TypeScript. Puedo recomendarles Visual Studio Code o Atom.
  4. Descargamos el código del app de ejemplo de mi repositorio de Github y lo abrimos con el IDE de ARDUINO.git clone https://github.com/janunezc/robotics.gitEl código se ubica en ~/robotics/intel_curie/ble_command_app/
  5. En el celular podemos utilizar el sistema Ionic View (descargado del App Store o Google Play) y previsualizar el app 03B50F88Las siguientes imágenes muestran la operación del app

 

Seguidamente mostramos las partes más importantes del código original del programa con los comentarios detallados sobre su funcionamiento. Es realmente sencillo; podemos resumirlo en:

  1. El tab “SCAN” implementa un proceso básico de búsqueda de dispositivos Bluetooth. No vamos a detallar mucho en este tutorial sobre ese tab.
  2. El tab “LED” implementa la búsqueda de un dispositivo específico y una vez que lo encuentra permite interactuar con el LED para encenderlo y apagarlo.
    1. Los componentes (tabs) de la aplicación IONIC3 se dividen en 3 elementos principales: una vista o view (led.html), un controlador (led.ts) y un modelo que corresponde a los datos que va a manejar la aplicación y que se ubican en el objeto this y sus propiedades públicas.
    2. El archivo led.html es realmente simple. Aparte de los párrafos de texto expicativo y títulos, posee un botón que tiene algunas características importantes de AngularJS como lo son el atributo [disabled] ligado a una variable del modelo denominada “ejecutandoComando”. Cuando la variable tiene un valor verdadero (true) el atributo disabled se activa y el botón se deshabilita. A su vez tiene una directiva (click) que ejecuta la función “Command()” del controlador.
    3. Una parte importante del archivo led.html es el último párrafo en la línea 11. Este utiliza una directiva *ngFor para iterar sobre la variable “messages” y mostrar cada mensaje como un párrafo ( <p> ) individual. Esto nos permite mostrar mensajes de aclaración conforme se ejecutan los procesos en el controlador.
  3. Exploremos ahora el archivo led.ts. Se trata de un script escrito en TypeScript. Un pseudo-lenguaje basado en JavaScript que permite una orientación a objetos más elaborada.
    1. Lo primero que se realiza en led.ts es importar las librerías necesarias. Dos de las más notorias serán BLE y ApplicationRef. La primera permite comunicación BLE, y la segunda permite manipular el framework de Angular para refrescar la pantalla cuando sea necesario.
    2. La siguiente parte super importante es el constructor, el cual implementa una serie de inyecciones de dependencia que vale la pena mencionar.
    3. Nótese la forma en que se inyectan en el constructor tanto la librería BLE como la librería de Angular ApplicationRef. En el constructor también se inicializan variables importantes tales como el ID de servicio y el ID de Característica que se van a manipular.
    4. Las funciones más interesantes en este archivo son:
      1. findDevice() que busca un dispositivo particular y una vez que lo encuentra cambia el modo de comandos para encender o apagar un LED. Para esto usa la funcion de BLE nativo denominada ble.scan()
      2. txData() que utiliza ble.connect y ble.write para conectarse al dispositivo y hacerle llegar un mensaje.
      3. SetMessage() tambien merece ser mecionado como la forma que tenemos de agregar mensajes de control que nos permitan entender cómo se está ejectuando el programa.

Espero que este artículo les sea de utilidad junto con el anterior para aprender a enviar comandos a un dispositivo BLE basado en Intel Curie, mediante el teléfono celular.

Los dejo con estos enlaces de utilidad:

  1. Aprender TypeScript: https://www.typescriptlang.org/docs/home.html
  2. Aprender Ionic 3: https://ionicframework.com/
  3. Aprender Angular 4: https://www.youtube.com/watch?v=kFTmoLm9Jwg

Que estén bien!


led.html

<ion-header>
   <ion-navbar>
   <ion-title>LED</ion-title>
   <p>Acá podemos operar el LED que está implementado en TinyTILE</p>
   <button ion-button [disabled]="ejecutandoComando" (click)="Command()">{{ComandoTXT}}</button>
</ion-navbar>
</ion-header>
<ion-content padding>
   <p>Histórico de Ejecución: ({{myCount}} | {{test}})</p>
   <hr />
   <p *ngFor="let message of messages">{{message}}</p>
</ion-content>

led.ts

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { BLE } from '@ionic-native/ble';
import { ApplicationRef } from '@angular/core';

@Component({
  selector: 'page-led',
  templateUrl: 'led.html'
})

export class LEDPage {

  public messages = []; //Histórico de ejecución
  public ejecutandoComando = false;
  public BLE;
  public ComandoTXT = "";
  public Value = "";
  public TargetDevice;
  private appRef;

  /**
   * CONSTANTES que serán usadas a lo largo del controlador
   */
  public constants  = {
      DEVICE_NAME: "COMANDO LED",
      CMD_FIND_DEVICE:"FIND DEVICE",
      CMD_STOP_SCAN:"Escaneando... (Clic para parar)",
      CMD_TOGGLE_LED:"CAMBIAR LED",
      ON:"ON",
      OFF:"OFF"
    };

  /**
   * Constructor para el controlador. Todo comienza acá...
   */
  constructor(public navCtrl: NavController, private ble: BLE /*Librería BLE nativa*/, private applicationRef : ApplicationRef /*Librería ApplicationRef de Angular*/ ) {
    this.appRef = applicationRef; //Referencia a la aplicación ANGULAR
    this.SetMessage("Constructor: Iniciado!");
    this.BLE = ble; //Acceso a la librería BLE Nativa
    this.ComandoTXT = this.constants.CMD_FIND_DEVICE;
    this.Value = "ON"; //VALOR PARA ENVIAR
    this.TargetDevice = {}; //Dispositivo al cual conectarse. Inicialmente vacío... se llenará cuando se encuentre el dispositivo en el escaneo.
    this['service_id'] = "db938b80-f010-44b6-8aa9-1835adf9419a"; //Identificador del servicio BLE a conectarse
    this['characteristic_id'] = "9906064e-9bbe-4eba-b415-bbd223f7d3d9"; //Identificador de la característica BLE a conectarse
    this.SetMessage("Constructor: Finalizado!");
  }

  /**
   * This is triggered when the button is clicked.
   */
  public Command(){
    this.ejecutandoComando = true;
    this.SetMessage("Command() - Comando recibido!");
    this.SetMessage(this["ComandoTXT"]);
    this.SetMessage("Interpretando comando...");

    if(this['ComandoTXT']===this.constants.CMD_FIND_DEVICE) {
      this.SetMessage("Ejecutando Comando: FIND DEVICE");
      this['ComandoTXT'] = this.constants.CMD_STOP_SCAN;
      this.findDevice();

    } else if (this['ComandoTXT']===this.constants.CMD_STOP_SCAN) {
      this.SetMessage("Ejecutando Comando: STOP SCAN");
      clearInterval(this['intervalHandle']);
      this['ComandoTXT'] = this.constants.CMD_FIND_DEVICE;
      this.ejecutandoComando = false;

    } else if(this['ComandoTXT']=== this.constants.CMD_TOGGLE_LED){
      this.SetMessage("Ejecutando Comando: TOGGLE LED: " + this.Value);
      this.SetMessage("Acá es donde enviamos un valor al dispositivo BLE");
      this.txData();
    }
  }

  /**
   * This searches for DEVICE in the AIR using SCAN technique.
   */
  private findDevice(){
      this.SetMessage("FindDevice() - INICIO!");
      let  ble = this.BLE;

      this.SetMessage("FindDevice() - ENABLE!");
      ble.enable();

      this.SetMessage("FindDevice() - SET INTERVAL!");
      this['intervalHandle'] = setInterval(() => { // PROGRAMAR UN TIMER DE 2.1 SEGUNDOS
        this.SetMessage("INTERVAL: INICIO! LLAMANDO A BLE SCAN...");
        ble.scan([], 2 /*seconds (0) */).subscribe( data => { //REALIZAR SCAN BLE POR 2 SEGUNDOS
          this.SetMessage("BLE SCAN CALLBACK: " + data['id'] + ' | ' + data['name'] + ' | ' + data['rssi']);
          if(data['name']==this.constants.DEVICE_NAME){
            this.SetMessage(this.constants.DEVICE_NAME + " HA SIDO ENCONTRADO!!");
            clearInterval(this["intervalHandle"]);
            this.TargetDevice = data;
            this["ComandoTXT"] = this.constants.CMD_TOGGLE_LED;
            this.ejecutandoComando = false;
          }
          this.appRef.tick();
        });
      },2100);//FIN DE LA DEFINICIÓN DEL TIMER
      this.ejecutandoComando = false;
    }

  /**
   * Transmitir datos al dispositivo BLE
   */
  private txData(){
    this.SetMessage("txData(): INICIO! Llamando a BLE CONNECT...");

    let id = this.TargetDevice.id;
    this.SetMessage("ID DE DISPOSITIVO: " + id);

    this.ble.connect(id).subscribe(datos=>{
      this.SetMessage("BLE CONNECT CALLBACK: INICIO!. Llamando a BLE WRITE..." + this.Value);

      this.ble.write(this.TargetDevice.id, this['service_id'],this['characteristic_id'], this.StringToBytes(this.Value) ).then(()=>{
        this.SetMessage("BLE WRITE CALLBACK: INICIO! Cambiando valor... " + this.Value);
        if(this.Value==this.constants.ON){
          this.Value = this.constants.OFF;
        } else {
          this.Value = this.constants.ON;
        }
        this.SetMessage("Nuevo valor... " + this.Value);

        this.SetMessage("Llamando a BLE DISCONNECT...");
        this.ble.disconnect(id);
        this.ejecutandoComando = false;
        this.appRef.tick();
      },(error)=>{
        this.SetMessage("BLE Write ERROR!");
        this.SetMessage(error);
        this.SetMessage("Llamando a BLE DISCONNECT...");
        this.ble.disconnect(id);
        this.ejecutandoComando = false;
        this.appRef.tick();
      });
    },error=>{
      this.SetMessage("BLE Connect ERROR!");
      this.SetMessage(error.message);
      this.ejecutandoComando = false;
      this.appRef.tick();
    });
  }

  /**
   * Agrega mensajes de ejecución al histórico
   */
  public SetMessage(message){
    var count = this['messages'].length;
    message = count + ':' + message;
    this['messages'].unshift(message);

    /*
      ESTA LINEA ES IMPORTANTE PARA REFRESCAR LA PANTALLA CUANDO SE GENERAN EVENTOS
      FUERA DEL CONTROL DE ANGULAR. POR EJEMPLO CUANDO SE LLAMA A UN CALLBACK EN
      UN PROCESO DE BLE SCAN.
    */
    this.appRef.tick();
  }

  // ASCII only. Convierte el valor a escribir a un arreglo de BYTES
  public StringToBytes(string) {
     let array = new Uint8Array(string.length);
     for (let i = 0, l = string.length; i < l; i++) {
         array[i] = string.charCodeAt(i);
      }
      return array.buffer;
  }

  // ASCII only
  public BytesToString(buffer) {
      return String.fromCharCode.apply(null, new Uint8Array(buffer));
  }
}

Comandos por BLE – (Parte 1 de 2) – El Receptor

21 Jul , 2017,
Jose Nunez
, ,
No Comments

Para continuar la exploración de la tecnología BLE que comenzó nuestra compañera Rebeca Rodriguez Tencio acá, les presentamos este primer tutorial de dos relacionados. La idea es poder implementar una forma de enviar comandos a una tarjeta de prototipado via Bluetooth Low Energy (BLE) desde una App de un teléfono Móvil.

En esta primera parte implementaremos un servicio “Comando LED” en un microcontrolador compatible con Arduino 101 llamado TinyTILE (basado en el chip Curie de Intel)

En la segunda parte, implementaremos una App (Android y IOS) usando IONIC 3 que le envía comandos al micro-controlador mediante el sistema BLE del teléfono.

(!) Antes de seguir estas instrucciones asegúrese de entender las Condiciones de Uso de nuestro sitio.

Primero: Programemos el Curie

En resumen:

  1. Necesitaremos un protoboard, un LED, una resistencia de 150 Ohm, un TinyTILE y un cable USB a micro-USB y una PC
  2. El circuito es muy sencillo:


  3. En la PC instalamos los controladores de placa “Arduino/Genuino 101” en el IDE de ARDUINO (V.1.8.2)
    • Menu: Tools >  Board > Board Manager > Search “Curie” > Instalar V 2.0.2 o superior.
  4. Descargamos el programa (sketch) de ejemplo de mi repositorio de Github y lo abrimos con el IDE de ARDUINO.
  5. Instalamos el boceto de ejemplo en la placa
    • Menu: Sketch > Upload
  6. Usamos una app para pruebas BLE denominada “BLE Scanner” para enviar comandos “ON” y “OFF”
  7. Nótese que hemos implementado una función “parpadear” que nos permite ver si el sketch arrancó adecuadamente.

Las siguientes imágenes ilustran el uso de BLE Scanner para enviar los comandos.

Seguidamente mostramos el código original del programa con los comentarios detallados sobre su funcionamiento. Es realmente sencillo; podemos resumirlo en:

  1. Definir un servicio BLE “ServicioBLE_Comando” (línea 5)
  2. Deinir una característica BLE “CaracteristiciaBLE_Comando” de tipo genérica, de lectura y escritura con mensajes de 20 bytes (línea 8)
  3. Darle un nombre al dispositivo “COMANDO LED” e inicializarlo, agregando el servicio y la característica (línea 19)
  4. Publicitamos el servicio (línea 23)
  5. Leemos eventos BLE en la característica (nuevos comandos) que luego son interpretados y ejecutados (líneas 31,33,57,61)
  6. Para esto convertimos el valor recibido a un String (línea 63)

 


#include <CurieBLE.h>
#define ledPin 13

//Definimos un servicio BLE
BLEService servicioBLE_Comandos("db938b80-f010-44b6-8aa9-1835adf9419a"); // create service

//Definimos una característica que pueda ser leida o escrita desde una central BLE, con capacidad de 20 bytes por mensaje.
BLECharacteristic caracteristicaBLE_Comandos("9906064e-9bbe-4eba-b415-bbd223f7d3d9", BLERead | BLEWrite, 20);

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT); 
  delay(500); //Esperamos un poco de tiempo (500ms) por si se puede habilitar la terminal serial.
  parpadear(5,200);//Señalizamos con el LED que estamos iniciando el sketch
  
  BLE.begin(); //Inicializamos el sistema Bluetooth Low Energy (BLE) del Curie
  parpadear(2 ,100);//Señal de aviso de que la operación anterior fue exitosa
  
  BLE.setLocalName("COMANDO LED"); //Definimos un nombre para publicitar nuestro dispositivo
  BLE.setAdvertisedService(servicioBLE_Comandos);//Definimos el servicio que se va a publicitar
  servicioBLE_Comandos.addCharacteristic(caracteristicaBLE_Comandos); //Agregamos la característica al servicio
  BLE.addService(servicioBLE_Comandos); //Agregamos el servicio al dispositivo  
  BLE.advertise(); // Publicitamos el dispositivo
  parpadear(3 ,100);//Señal de aviso de que la operación anterior fue exitosa

  Serial.println("En este punto el dispositivo queda listo, publicitado y esperando conexiones...");
  parpadear(10,50);//Señal de aviso de que SETUP se concluyó satisfactoriamente
}

void loop() {
  BLE.poll(); // Obtenemos cualquier evento BLE que haya sido enviado al dispositivo

  if (caracteristicaBLE_Comandos.written()) { //Si hay datos, ejecutamos el comando
    leerYEjecutarComado();
  } // ... caso contrario simplemente se termina el flujo de loop()
}

/**
 * Este método lee el comando registrado en la característica BLE y lo ejecuta.
 */
void leerYEjecutarComado(){
    String valorDelComando = obtenerValorDelComando();

    if (valorDelComando.startsWith("ON")) {
      Serial.println("LED on");
      digitalWrite(ledPin, HIGH);
    } else {
      Serial.println("LED off");
      digitalWrite(ledPin, LOW);
    }
}

/**
 * Extraer el valor del comando en formato String
 */
String obtenerValorDelComando(){
    int longitudDelComando = caracteristicaBLE_Comandos.valueLength();
    Serial.print("Longitud: ");
    Serial.println(longitudDelComando);
      
    const byte* val = caracteristicaBLE_Comandos.value();
    
    String strValor = String((const char *)val).substring(0, longitudDelComando);
    Serial.println("|" + strValor + "|");

    return strValor;
}

void parpadear(int times, int milliseconds){
  for(int i=0; i<times; i++){
    digitalWrite(ledPin, HIGH);
    delay(milliseconds);
    digitalWrite(ledPin, LOW);
    delay(milliseconds);
  }
}

 

 

Fundamentos y Experimentación con Bluetooth Low Energy

1 Jul , 2017,
Rebeca Rodriguez Tencio
, , , , ,
No Comments

Resumen: En esta publicación, Rebeca Rodiguez nos da una importante lección sobre la importancia de profundizar un poco en los fundamentos de las tecnologías que usamos, y a su vez nos propone un experimento muy interesante para aplicar estos conocimientos en una aplicación que permite controlar una luz (LED) de manera remota desde un teléfono celular.

(!) Antes de seguir estas instrucciones asegúrese de entender las Condiciones de Uso de nuestro sitio.

¿Conocen lo que es el Bluetooth de Baja Energía?

Saber de una tecnología va más allá de solo leer artículos informativos acerca de ella, antes de empezar a experimentar con BLE pensé que se me facilitaría desarrollar con está herramienta, no obstante descubrí que los conocimientos con los que contaba eran mínimos, y necesitaba aprender más para poder trabajar en uno de los proyectos actuales del Centro de Innovación, por lo que con el apoyo de Jose Núñez, uno de los ingenieros y colaboradores del centro, empecé la aventura de investigar y experimentar el mundo del Bluetooth de Baja Energía.

En muchos casos es muy fácil poder hacer aplicaciones funcionales e interesantes porque ya alguien más se tomó la molestia de hacer frameworks, librerías y tutoriales que nos facilitan la complejidad que conlleva realizar algo desde cero; probablemente si te gusta el mundo maker o estudias algo relacionado a la tecnología te has encontrado con proyectos que incluyan bluetooth como parte de las aplicaciones, sin embargo ¿te has preguntado la historia o cómo funciona toda la comunicación que hay detrás de esa tecnología o solamente has seguido los pasos de un tutorial e instalado las librerías respectivas copiando y pegando código y nos conformamos con que funcione a la primera?

PD: no importa si agarramos código de internet o nos basamos en algo ya existente para realizar un proyecto o aprender, existe mucha información y hay que sacarle el mayor provecho, pero es importante entender cómo funciona lo que estamos programando, la historia que hay detrás de  la comunicación entre los dispositivos y los términos empleados.

Resultado de imagen para BLUETOOTH low energy

El BLE es la versión ligera y mejorada del Bluetooth 4.0 clásico, está diseñado para abordar las necesidades de eficiencia energética y la simplicidad en el diseño de los productos, convirtiendose en una solución inalámbrica ULP (Ultra Low Power, Ultra Bajo Consumo); esta tecnología opera en la banda mundial de 2.4GHz, cuenta con una banda de bits de capa física de 1Mbps en un rango de 15metros.

El Bluetooth de Baja Energía fue desarrollado por Nordic Semiconductor, fue uno de los primeros miembros de “Wibree Alliance” la organización que inicio el desarrollo estándar de la ULP (Ultra Low Power), sin embargo después fue adoptado por el SIG (Special Interest Group, Grupo con Especial Interés), que fue conformado por cinco compañías (Ericsson, Nokia, Toshiba, IBM e INTEL). Nordic ha jugado un papel importante en el desarrollo de BLE, y continua desempeñando un papel clave a través del trabajo realizado como miembro asociado de Bluetooth SIG.

Lo interesante al usar BLE es que ha sido implementado en la gran mayoría de plataformas móviles modernas, sea iOS, Android, móviles con Windows, entre otros.

Hay conceptos indispensables con los que se van a encontrar siempre que empiecen a investigar acerca del BLE, por lo que conocer el significado o familiarizarse con los términos es importante.

Comenzamos hablando de perfiles y protocolos: el primer concepto es la subcategoría GAP (Generic Access Profile, Perfil de Acceso Genérico). El GAP es el encargado de permitir que el dispositivo sea público al exterior y por lo tanto define la forma de interacción entre los dispositivos. El GAP tiene dos roles importantes de conexión:  (1) los dispositivos centrales – de ahí el término BLE Central – (que corresponde a los móviles, tablet o dispositivos con capacidad de procesamiento mayor que inician la conexión con los periféricos) y (2) los periféricos (dispositivos pequeños de baja potencia y consumo) a los que se pueden conectar los dispositivos centrales.

Una vez que se establece la conexión entre los dispositivos centrales y los dispositivos periféricos entra al juego el GATT (Generic Attribute Profile, Perfil Genérico de Atributos) permitiendo la comunicación en ambas direcciones, a través del protocolo ATT que se usa para almacenar los servicios, los datos y las características propias de cada dispositivo utilizado; es importante destacar que un periférico BLE solo puede ser conectado a un dispositivo central a la vez, ya que tan pronto como el periférico es conectado al dispositivo central dejara de ser visible para otros dispositivos, sin embargo un dispositivo central (celulares, tablets…) si puede ser conectado a varios periféricos.

Al igual que en el GAP, el GATT también tiene roles de interacción que es importante conocer, como por ejemplo: el servidor que contiene las características de la búsqueda ATT asi como las definiciones del servicio y las características, el otro concepto es el cliente GATT que es el encargado de enviar las solicitudes. Todas las transacciones de comunicación entre los dispositivos son iniciadas por el GATT cliente (central) que recibe la respuesta del dispositivo esclavo, el GATT servidor (periférico).

Existen muchas aplicaciones para poder escanear periféricos BLE desde un dispositivo móvil, sin embargo hay una de ellas que me gustó mucho al momento de utilizarla. Se trata de nRF Connect for Mobile (Que antes se llamaba nRF Master Control Panel) es un app muy útil para experimentar y entender los conceptos de comunicación BLE.

Hay un ejemplo que encontré y quiero compartir porque está interesante ya que permite controlar un LED desde el celular, es decir podemos controlar un TinyTILE de Intel o una placa de Arduino 101 a través de un dispositivo central.

NOTA: Antes de iniciar el ejercicio es importante repasar qué es Intel Curie, esto para tener más claro el funcionamiento de los dispositvos perifericos utilizados, pueden guiarse con el siguiente enlace: https://costaricamakers.com/?s=curie

EJERCICIO PROPUESTO

Materiales:

  • 1LED
  • 1 Protoboard
  • Cable para prototipar
  • 1 tiny tile o placa arduino 101
  • 1 resistencia de 220Ω
  • Instalar el app de nRF Master Control Panel

Pasos a seguir:


PASO 1: Prototipar según la imagen del diagrama, que se obtuvo de: https://cdn.sparkfun.com/assets/learn_tutorials/4/9/2/Exp_1_Blink_bb.png

 

 

 

 

 

 

 


PASO 2: Conectar el periférico utilizado (Arduino 101 o TinyTILE), abrir el Arduino IDE y cargarle el código de ejemplo:

#include 
BLEPeripheral blePeripheral;
BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED servicio app

//BLE caracteristicas asigandas
BLEUnsignedCharCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = 13; // pin asignado al LED

void setup() {
    pinMode(ledPin, OUTPUT);

    blePeripheral.setLocalName("TINYTILE BLE"); //Nombre que se le asigna al periferico para ser encontrado
    blePeripheral.setAdvertisedServiceUuid(ledService.uuid());

    blePeripheral.addAttribute(ledService); //caracteristicas del servicio
    blePeripheral.addAttribute(switchCharacteristic);

    switchCharacteristic.setValue(0);

    blePeripheral.begin();
}

void loop() {
    // Escucha los perifericos BLE para conectarse:
    BLECentral central = blePeripheral.central();

    // Si el central es conectado al periferico:
    if (central) {
        // Mientras la central siga conectada al periferico:
        while (central.connected()) {
            // Si el dispositivo remoto escribió a la característica,
            // usar un valor para encender el LED
            if (switchCharacteristic.written()) {
                // Cualquier valor a diferencia de 0 encendera el LED
                if (switchCharacteristic.value()) {
                    digitalWrite(ledPin, HIGH);
                }
                else {
                    digitalWrite(ledPin, LOW);
                }
            }
        }
    }
}

PASO 3: Abrir el app y hacer escaner de los dispositivos periféricos, conectar en este caso con el “TINYTILE BLE” como se muestra en la siguiente imagen. Una vez que se selecciona la opción de “CONNECT”, hay que hacer click en “Unknown Service” van aparecer unas flechas, haga click en la  flecha que tiene direción hacia abajo.

 


PASO 4: Se abrirá una pantalla o cuadro de dialogo, donde debemos seleccionar la opción de “UNIT 8” e introducir un número distinto de 0 para encencer el LED y haga click en enviar o “SEND”.

¡El LED debe encenderse! para volver apagarlo, debe abrir el mismo cuadro de diálogo e ingresar el número 0 y hacer nuevamente click en enviar y el LED debe apagarse.

Gracias por leer este artículo. Nos será de mucho valor que nos digas en comentarios si te fue de utilidad, si trataste de hacer el experimento y si realizaste cambios al mismo.

IoT para Hogares Inteligentes

26 Jun , 2017,
Luis Diego Jimenez Sanchez

No Comments

Que significa Iot para Hogares Inteligentes?:

Para ir tomando los primeros pasos en la tecnología de IoT (Internet de las cosas) enfocado hacia el tema de los hogares inteligentes, es necesario primero investigar sobre cuales tecnologías hay disponibles.  Hogares inteligentes y el Internet de las cosas, que de ahora en adelante solo lo mencionare como IoT, se refiere a varios conceptos como inteligencia, automatización, comunicación, seguridad y eficiencia energética todo enfocado a intentar mejorar la calidad de vida de la persona y su hogar.  Algunos de los objetivos de lo que se intenta con IoT para hogares inteligentes es:

  • Control y automatización de luces.
  • Dispositivos de entretenimiento como equipos de sonido, televisores, etc.
  • Sistemas de alarma y sensores de seguridad.
  • Sistemas de control de temperatura.

Arquitectura del sistema

La arquitectura de un sistema de IoT para hogares inteligentes se reduce a los siguientes componentes:

  • Sensores y actuadores: reciben las señales y ejecutan comandos en el hogar tan sencillo como apagar una luz.
  • Cliente de control remoto: Puede ser desde un navegador web o una aplicación celular, pero desde este punto el usuario envía el comando a ejecutar por el actuador o en el caso del sensor, es aquí donde se recibe la información.
  • Servicio de nube o base de datos: Es el intermediario entre el usuario (cliente de control remoto) y los sensores y actuadores.

A continuación se explica de manera sencilla el funcionamiento de un sistema de IoT Smart Homes:

Figura 1: Diagrama de un sistema IoT para hogares

El hogar primero que todo debe tener los dispositivos en el hogar con el hardware necesario para el hardware en estudio.  Ejemplo básico, un switch o apagador de luces, debe tener el hardware que le permita la comunicación con el dispositivo que le vaya a mandar los comandos.  El HUB o la computadora que permita la comunicación con los dispositivos, aunque esto se puede reemplazar por un protocolo que permita la conexión directa.  Ahora para enviar los comandos desde una aplicación de celular hacia mi computadora o HUB en la casa para activar los dispositivos, esta información debe pasar por una nube de almacenamiento para la conexión.  A la vez, nos permite almacenar información de eficiencia energética para optimización de recursos.   Esto en cuanto a los protocolos de comunicación, se listan algunos a continuación.

  1. Wifi.
  2. Bluetooth.
  3. Radiofrecuencia.
    1. Z-Wave.
    2. Zigbee.
    3. BidCos.

Seguridad: 

Ahora, sabiendo el hardware existente para una posible construccion de un smart home, algo muy importante que no se puede olvidar es la seguridad.  Sin tener un protocolo con la debida incriptacion de datos, cualquier persona con un conocimiento tecnico en el area, podria eventualmente hackear las senales y manipular el hardware.  Para evitar esto es necesario siempre revisar la encriptacion que pueda tener los dispositivos que se utilicen.  En el caso de los dispositivos de radiofecuencia tales como Z-Wave, estos protocolos ya venden productos con certificados de seguridad.  En el caso de usar un dispositivo para comunicacion por WiFi, es necesario encriptar los datos.

Ahora, ya teniendo esta introduccion la idea es montar un prototipo usando los protocolos anteriores, estableciendo una conexion segura entre el usuario y los actuadores.

Se despide,

Luis Diego Jimenez Sanchez

 

 

 

Prototipos de Software con Computadoras Virtuales c9.io

11 Jun , 2017,
Jose Nunez
, , , ,
No Comments

Este es un post realmente corto.

Cuando uno está experimentando o desarrollando con tecnologías de software para cosas como desarrollo web y de aplicaciones móviles, sistemas como NodeJS o Python, visión computarizada, etc… usualmente requerimos instalar en nuestros computadores una cantidad importante de bibliotecas y paquetes para realizar pruebas con dichas tecnologías.

C9.io es un servicio comercial de máquinas virtuales en la web.

La verdad me ha parecido muy sencillo y completo.

https://c9.io

Todo es cuestión de crear una cuenta de usuario, ojalá enlazada con nuestra cuenta de usuario de github.com (si la tuvieramos) y vualá, podemos crear nuevas máquinas virtuales, clonar las existentes, y operarlas para instalar y desinstalar cosas a nuestro antojo casi ilimitado.

Una cuenta gratuita nos permitirá generar nuevas máquinas virtuales con ciertas limitaciones de capacidad de procesador, memoria RAM (512MB) y almacenamiento (2GB) que por lo general son suficientes para realizar pruebas de concepto o experimentación.

En próximas entregas estaré discutiendo un poco cómo realizar pruebas en C9.io para desarrollo de apps en ionic, nodejs, python-opencv entre otros.

Ya Contamos Personas… Ahora hagamos algo con Python

20 Abr , 2017,
Jose Nunez
, , , , ,
2 comments

Muchas personas piensan que la visión computarizada es un área de la tecnología reservada para genios matemáticos japoneses.

Nada más lejos de la realidad.

Mientras que en efecto se hace uso intensivo de matemática muy avanzada, y de sistemas computacionales de última generación; la realidad es que, gracias al código abierto, existen bibliotecas y frameworks  que hace accesible estas tecnologías a todas las personas que, con una dosis adecuada de interés quieran adentrarse en este mundo tan fascinante y a la vez de vital importancia para nuestra sociedad moderna.

En esta entrega les mostramos una extensión de nuestro artículo anterior sobre “Visión Computarizada: Contando Gente con OpenCV, ROS,..” donde exploramos la creación un programa básico en lenguaje Python que haga uso modesto de los datos generados por el contador de personas.

Recordemos que ROS (Robot Operating System) es un meta-sistema operativo de tipo publicador/suscriptor que facilita la comunicacion entre diversos nodos computacionales; y que está orientado a sistemas robóticos.

Como dijimos, en el artículo anterior exploramos cómo configurar un sistema Up-Board con Ubuntu Linux, para utilizar los datos provenientes de una cámara para analizar las imagenes en tiempo real y detectar personas. Fascinante.

Ahora, basados en el tutorial básico de ROS para creación de programas Python de publicación y escucha, acá listamos los pasos básicos para la creación de publicadores y escuchadores que funcionen con ROS.

(!) Antes, tengamos en cuenta que la detección de personas que viene con opencv_apps de ROS lo que hace es buscar en las imágenes patrones que coincidan con cierta geometría rectangular alta. Por eso en la imagen destacada de este artículo vemos marcas de rectángulos donde no hay personas. Al final de este artículo hablamos del comando rosrun rqt_reconfigure rqt_reconfigure que permite ajustar parámetros “en caliente” para mejorar la precisión.

También, antes de ejecutar estos procedimientos, es probable que necesite ejecutar las instrucciones de algunos artículos anteriores que se listan en esta página: http://costaricamakers.com/?p=914 a partir del punto 4.

En caso de duda o si algo no funciona, les agradezco nos lo hagan saber en los comentarios.


PASO 1 – Primeramente creamos un espacio de trabajo de tipo catkin. Es decir la estructura básica de archivos y herramientas de un espacio de trabajo para ROS usando el sistema de construcción Catkin.

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
cd ~/catkin_ws/
catkin_make
source devel/setup.bash

PASO 2 – Seguidamente crearemos un paquete de ROS al que llamaremos “beginner_tutorials”que no es otra cosa que un conjunto de programas que se pueden manipular mediante ROS.

cd ~/catkin_ws/src
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
cd ~/catkin_ws
catkin_make
. ~/catkin_ws/devel/setup.bash

De nuevo, para más información sobre la creación de paquetes puede visitar el tutorial oficial en http://wiki.ros.org/ROS/Tutorials/CreatingPackage


PASO 3 – Ahora escribiremos los programas básicos de publicación y escucha.

roscd beginner_tutorials
mkdir scripts
cd scripts
wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py
chmod +x talker.py

El comando wget de la linea 4 arriba se encargará de descargar nuestro programa de python llamado “talker.py” que se encarga de publicar mensajes en un nodo denominado “chatter” que luego serán leidos desde el programa de escucha o suscriptor.

Para crear el programa de escucha usamos los siguientes comandos:

roscd beginner_tutorials/scripts/
wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/listener.py
chmod +x listener.py

Con esto se descarga el programa “listener.py” en nuestra carpeta scripts para programas de python.

Este programa escuchará datos publicados al nodo “chatter” y los mostrará en la pantalla.


PASO 4 – Pongamos a prueba estos programas.

Para esto primero compilaremos el paquete usando los siguientes comandos

cd ~/catkin_ws
catkin_make

y luego ejecutaremos ambos scripts en terminales diferentes:

rosrun beginner_tutorials listener.py
rosrun beginner_tutorials talker.py

Al ejecutarse se puede apreciar como, el listener.py no hace nada, hasta que el talker.py es ejecutado. El programa talker.py envia mensajes con un numero al tópico chatter; estos mensajes son entonces escuchados por el programa listener.py el cual los muestra en la pantalla al recibirlos. Es una dinámica muy simple.


PASO 5 – Modifiquemos el listener.py

Ahora modificaremos el programa listener.py para que en lugar de escuchar el tópico ‘chatter’ publicado por talker.py, escuche un tópico un tanto más avanzado: la cuenta de personas de nuestra cámara.

Usando el siguiente comando abrimos listener.py usando el editor gedit que viene con Ubuntu.

cd ~/catkin_ws
sudo gedit src/beginner_tutorials/scripts/listener.py

Luego reemplazamos el contenido del script con el siguiente:

#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following
#    disclaimer in the documentation and/or other materials provided
#    with the distribution.
#  * Neither the name of Willow Garage, Inc. nor the names of its
#    contributors may be used to endorse or promote products derived
#    from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Revision $Id$

## Simple talker demo that listens to std_msgs/Strings published 
## to the 'chatter' topic

import rospy
from std_msgs.msg import String
from opencv_apps.msg import RectArrayStamped

def callback(data):
    rospy.loginfo(rospy.get_caller_id() + 'I AAAA  heard %s', data)

def listener():

    # In ROS, nodes are uniquely named. If two nodes with the same
    # name are launched, the previous one is kicked off. The
    # anonymous=True flag means that rospy will choose a unique
    # name for our 'listener' node so that multiple listeners can
    # run simultaneously.
    rospy.init_node('listener', anonymous=True)

    rospy.Subscriber('people_detect/found', RectArrayStamped, callback)

    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

if __name__ == '__main__':
    listener()

Podemos observar las partes clave del programa:

  1. Linea 41: Importamos de la librería opencv_apps.msg el tipo de datos RectArrayStamped, que es el tipo de datos con que se publican las personas encontradas .
  2. Linea 44: Se muestra en consola los datos recibidos por el suscriptor. Nótese que donde dice data, podríamos poner data.rects para obtener unicamente el arreglo de rectángulos que representa a cada persona.
  3. Linea 55: Se define un suscriptor para el tópico peopledetect/found con un tipo de dato RectArrayStamped que al escuchar datos llamatrá la función callback. Esta función se define en la línea 43 y 44.

Para ejecutar este script usariamos el siguiente comando que nos mostrará los datos escuchados.

rosrun beginner_tutorials listener.py

Otros comandos que suelen ser útiles:
Para listar todos los tópicos que están manejando en la instancia de ROS: rostopic list

Para ver la información de un tópico particular: rostopic echo people_detect/found

Para configurar los tópicos activos mediante un utilitario GUI: rosrun rqt_reconfigure rqt_reconfigure


Read More…

Una Introducción a la tecnología de Realidad Aumentada (AR)

9 Mar , 2017,
Luis Diego Jimenez Sanchez
, ,
No Comments

El 6 de Julio del 2016 salió Pokemon GO, uno de los actuales juegos pioneros en el mundo de la realidad aumentada y un despertar al mundo del interés sobre AR.  Quizás hayan escuchado sobre realidad virtual y realidad aumentada, así que, que las diferencia?  Realidad virtual, o conocido por sus siglas en inglés como VR, es la aplicación de un entorno o ambiente digital o virtual, que detecta diferentes caracteristicas de tiempo real del usuario y reacciona de manera que este siente que es real.  Realidad aumentada, es la ampliación de imágenes reales mediante el uso de algún dispositivo, de manera que agrega imágenes virtuales a lo que el usuario está observando.

Para empezar la investigación y aprendizaje de la realidad aumentada, un área totalmente desconocida para mí, el plan era iniciar con los Google Glass debido a su fama como empresa, esto antes de darme cuenta que el proyecto había sido descontinuado desde el 2015.  A partir de aquí, lo único que quedaba era iniciar búsqueda de  los productos que hay en el mercado.  Son 5 los que más me llamaron la atención, esto según los siguientes parámetros; precio, quien los produce y a que mercado se dirige el producto y como empezar a usarlos.   Después de investigar en internet por dispositivos de la naturaleza de AR, construí una lista de los dispositivos que mejor se acomodan a mi necesidad de entender el funcionamiento y alcance de estos.  Los dispositivos son los siguientes:

VUZIX M3000 Smart Glasses:

               Producido por la empresa VUZIX, la cual se dedica a la fabricación de lentes de VR y AR, los lentes M3000 tienen fecha de lanzamiento este verano de 2017, con precio que ronda los 900$.  Este producto tiene las capacidades de un teléfono inteligente con capacidad de conectarse a redes WIFI, basada en Android y se puede considerar una mini computadora.  Los M3000 se pueden personalizar, son más dirigidas a empresas de manera que se usen para entrenamientos, registros de procedimiento y data, y otros aspectos de la industria.  A continuación un link con demo de estos Smart glasses, https://www.youtube.com/watch?v=y6SGlOLVpg8.

VUZIX M3000

Imagen 1. VIZUX M3000 Smart Glasses

Microsoft HoloLens:

               El kit de desarrollo de HoloLens se puede encontrar por unos $3000 en la página,  https://www.microsoft.com/microsoft-hololens/en-us/buy.  Producido por los gigantes en la industria, Microsoft, tiene versiones comerciales desarrolladas para casos específicas.  Un ejemplo es para Case Western Reserve University tiene un programa de Anatomía Humana con el uso de hologramas.  Otras empresas que utilizan HoloLens para mejorar aspectos en su performance son Lowes, Volkswagen y Airbus.  Para el interés de desarrollar, el kit viene con su SDK respectivo, hay versión de SDK en Unity Engine donde se pueden crear objetos, escenas y usar comandos para reconocimientos de gestos.

hololens

Imagen 2. Microsoft HoloLens

Sony SmartEye Glass:

               Sony SmartEye Glass, no se puede comprar directamente en Costa Rica ni America Central, sino que es por pedido especial en Estados Unidos y algunos otros países en Europa.  El precio en la siguiente página es de $900.  Al igual que los otros lentes de realidad aumentada, estos también son Developer Kits por lo cual se permite al usuario darle el uso según las capacidades de lo que podas desarrollar.  Sony es la empresa que las produce y una diferencia de las demás es que esta trae un control cableado a los lentes, es pequeño por lo cual no produce incomodidad en el usuario.

sony smarteye glass

Imagen 3. Sony SmartEye Glass

Lenovo Phab Pro 2:

               Este teléfono, Lenovo Phab Pro 2 vale alrededor de $499.99 si se compra directamente de la página de Lenovo.  A mi opinión, no es un kit de desarrollo ni nada por el estilo.  Está destinado más hacia el uso de apps que incluyan AR, juegos por ejemplo ya se encuentran en el mercado.  La aplicación más interesante que encontré es roOomy Reality, esta permite mostrarle al usuario como se vería una nueva pieza de mueblería en algún determinado cuarto de su hogar.  Parece arropar la idea de la realidad aumentada al facilitar una tarea de la vida real mediante el uso de imágenes digitales.

lenovo phab pro 2

Imagen 4. Lenovo Phab Pro 2 celular

Intel RealSense:

              Aunque Real Sense no es una tecnología directamente relacionada con realidad aumentada en lo referente a proyeccion de elementos visuales a la vista del usuario, si permiten un acercamiento a esta mediante la comprensión experimental de las librerías y tecnologías adyacentes tales como captura, análisis y manipulación de imágenes y video.  Real Sense es un producto de un concepto tecnológico denominado “Perceptual Computing” que tiene que ver como los dispositivos computacionales pueden percibir mensajes del usuario diferentes al teclado/mouse tales como los gestos que vas a experimentar. Augmented Reality tiene que ver más con anteponer contenido a las imágenes que se le presentan al usuario; sin embargo en efecto las tecnologías y conceptos se traslapan.

La tecnología Intel RealSense, ofrece varios dispositivos y kits de desarollo, en precios que van desde los $99 para una cámara R200 hasta los $349 para un kit de desarrollo con cámara R200 y sistema computacional UP Board.

real sense

Imagen 5. Intel RealSense camera F200

Las cámaras, cuentan con la capacidad para hacer escaneos en 3D, reconocimiento facial y puede generar imágenes basándose en distancias de cuerpos u objetos de las cámaras.  Los SDK, kits de desarrollo de software, de Intel, en mi opinión es la mejor opción para empezar a trabajar con realidad aumentada y en siguiente mis razones:

  • Precio: es el producto más accesible, siendo el de $349 el kit más costoso. A pesar de que no se pueden comparar estos productos directamente debido a que sus objetivos y alcances son muy distintos, si los puedo comparar al tratarse de un primer acercamiento a esta tecnología.
  • Aplicación del hardware:  Para efectos de aprendizaje, tales como los mios, en el cual es necesario entender el alcance de registrar data a partir de entradas por camara, me parece mejor opcion usar el RealSense debido a las librerias que trae como reconocimiento facial o de gestos.

Mi primer experimento será con Intel RealSense, probablemente algún carro o robot al que pueda darle direcciones con gestos de mis manos.

EL ARTE TEXTIL EN FUSIÓN CON LA TECNOLOGÍA

7 Mar , 2017,
Rebeca Rodriguez Tencio
,
No Comments

Electrotextil es el nombre que se le da a la idea “mágica” de combinar la industria textil con la electrónica, creando un nuevo concepto de diseño que no solo es “fashion”, sino un impulso a la innovación.

Las prendas o accesorios que normalmente se utilizan no contienen elementos electrónicos, sin embargo dentro de 10 años es factible que cada tipo de ropa o accesorio tenga incorporado distintos componentes con funciones tecnológicas que contribuyan a la comodidad, salud y bienestar de los usuarios.

Actualmente los e-textiles presentan varios retos fundamentales para el progreso en el uso de esta tecnología, ya que un textil electrónico debe ser flexible, discreto, lavable y estéticamente aceptable, lo que provoca un desafío en la construcción del diseño y conectividad confiable.

Acá les comparto unos enlaces muy interesantes donde pueden sacar ideas para empezar a involucrase en el mundo wearable:

Espero sus comentarios acerca del tema :o). En el próximo artículo vamos a empezar a experimentar y crear un proyecto con diferentes componentes wearables paso a paso.

SimpleCV Hello World ++ en otros 5 minutos (Linux MINT 18)

4 Mar , 2017,
Jose Nunez
, , , , , ,
No Comments

Siguiendo nuestra serie sobre SimpleCV y como una motivación personal para aprender Python. Acá les presento un par de scripts basados en el ejemplo “Hello World” de SimpleCV.

El primero toma constantemente  una foto de una cámara y la “binariza”; es decir, la convierte cada pixel de la foto en negro o blanco dependiendo de su “posición estadística” respecto de los demás pixeles y muestra el resultado en pantalla.

El segundo toma la fotografía original, sin ser “binarizada” y la muestra en pantalla.

Al correr los scripts de manera simultánea podemos apreciar de mejor manera este filtro de binarización de la imagen.


PASO 1 – simplecv_helloworld.py

Usando un editor de texto como “xed” copiamos el siguiente programa y guardamos el archivo como “simplecv_helloworld.py”

from SimpleCV import Camera
# Initialize the camera
cam = Camera()
# Loop to continuously get images
while True:
    # Get Image from camera
    img = cam.getImage()
    img.save('/home/toruk-makto/imageport.jpg')
    # Make image black and white
    img = img.binarize()
    # Draw the text "Hello World" on image
    img.drawText("Hello World!")
    # Show the image
    img.show()

PASO 2 – simplecv_helloworld2.py

De nuevo, mediante el editor de texto copiamos el siguiente programa y guardamos el archivo como “simplecv_helloworld2.py”

from SimpleCV import Image

# Loop to continuously get images
while True:
    # Get Image from camera
    try:
        img = Image('/home/toruk-makto/imageport.jpg')
        # Draw the text "Hello World" on image
        img.drawText("Hello World!")
        # Show the image
        img.show()
    except:
        print "skip!"

PASO 3 – Ejecutar ambos scripts

En una terminal ejecutemos los siguientes dos commandos:



python simplecv_helloworld.py &

python simplecv_helloworld2.py &


Vemos como se muestran ambas imágenes “en tiempo real”

Para detener los scripts podemos digitar el comando fg(que trae el comando al “foreground de ejecución”) y luego usar las teclas CTRL C; o ejecutamos el comando sudo kill #### donde “####” corresponde al número del proceso que queremos detener; o simplemente cerramos la terminal.