Reto 2 - Bacheo con IoT

Requerimientos

  1. Apagar los 3 indicadores al inicio del programa.

  2. Obtener la posición objetivo (Latitud, Longitud) desde Blynk.Cloud.

  3. El usuario dispondrá de dos botones, cuando presione el botón azul, se deberá obtener la posición actual usando las funciones GNSS, el usuario deberá mantenerse al menos un minuto a menos de 20 metros de la posición objetivo, durante el proceso uno de los indicadores deberá encenderse en color azul y mantenerse encendido siempre y cuando se cumpla la condición de menos de 20 metros.

  4. Si el usuario se mantuvo a menos de 20 metros de la distancia objetivo y si el usuario presiona el botón verde, entonces el dispositivo se reconectará y deberá enviar la posición actual del dispositivo a Blynk.Cloud. El indicador deberá cambiar a color verde.

  5. El servidor comprobará que la posición obtenida por GNSS se encuentre a menos de 20 metros de la posición objetivo, de ser así enviará una nueva posición.

  6. Repetir el paso 2 al 5 hasta que los 3 indicadores sean color verde.

Materiales

Maqueta "Bacheo"
LED RGB de cátodo común
LED RGB

Un LED RGB de cátodo común, tiene 1 terminal para GND y 3 terminales para cada uno de los colores Rojo (R), Verde (G) y Azul (B), cada terminal requiere una resistencia limitadora de corriente.

Para el reto se te entregará un LED RGB con resistencias apropiadas y sin la terminal de color rojo.

Batería Li-Ion 18650 con porta batería

Batería recargable Li-Ion 18650 de 2200 mAh, incluye porta baterías y conector JST compatible con el módulo de carga del XC01 R5-I.

Botón pulsador (x2)

Botón pulsador de tipo normalmente abierto, modo de uso recomendado:

  • Conectar una terminal a GND.

  • Conectar una terminal a una de las terminales del XN01.

Condiciones

  • Contarás con un máximo de 30 MB de datos para conexión a internet.

2 datastreams para la posición del dispositivo
VPIN
Tipo
Min
Max
Descripción

V1

double

-180

180

Longitud

V2

double

-90

90

Latitud

2 datastreams para la posición del dispositivo
VPIN
Tipo
Min
Max
Descripción

V3

double

-180

180

Longitud objetivo

V4

double

-90

90

Latitud objetivo

  • Al enviar la posición del dispositivo el servidor validará que se cumpla con la condición de distancia de 20 mts (+/-0.0002), si se cumple el servidor actualizará una nueva dirección objetivo.

  • La aplicación móvil mostrará en el mapa la posición objetivo.

  • Durante el desarrollo estará habilitado una sección llamada: Depuración y Pruebas, donde podrás enviar libremente los valores de Latitud Objetivo y Longitud Objetivo, durante la validación está opción estará deshabilitada.

Consejos

Conexión a la nube + GNSS

El XC03 - Red celular LTE y GSS solo puede utilizar la antena LTE o la antena GNSS, pero no puede utilizar ambas al mismo tiempo. Por lo que deberás escribir el código considerando esta limitante. Apóyate de las funciones de TinyGSM y Blynk para interrumpir la conexión con la nube mientras se obtiene la posición GNSS y reanúdala una vez sea obtenida.

A continuación, se muestran las funciones que podrían serte útiles

// Inicia una sesión LTE, la antena GNSS debe estar deshabilitada
modem.gprsConnect( apn, user, pass );

// Terminar una sesión LTE
modem.gprsDisconnect();

// Inicia la configuración del modem de red celular,
// inicia una sesión LTE e inicia una sesión en la nube de Blynk,
// solo debe usarse una vez en el inicio del programa
Blynk.begin(auth, modem, apn, user, pass, domain);

// Reestablece la comunicación con el servidor en la nube de Blynk
Blynk.connect();

// Consulta el estado de la conexión con el servidor de Blynk,
// si hay una sesión activa entonces retornará true, false en
// cualquier otro caso
Blynk.connected()

// Termina la sesión de Blynk activa
Blynk.disconnect();

// Habilita la antena GNSS, no debe haber una sesión LTE activa
modem.enableGPS()

// Intenta obtener los datos de posición, la antena GNSS debe estar
// habilitada. Retornará true en caso de éxito, falso si la posición
// aún no está disponible
modem.getGPS( &latitude, &longitude, &speed, &alt, &vsat, &usat, &accuracy,
                            &year, &month, &day, &hour, &minute, &second );
                            
// Deshabilita la antenna GNSS         
modem.disableGPS();

Revisa el siguiente código de ejemplo sobre una posible implementación GNSS + LTE, recuerda que deberás modificarlo para cumplir con el reto:

// *************** TEMPLATE DE BLYNK **************************
#define BLYNK_TEMPLATE_ID "TMPxxxxxx"
#define BLYNK_TEMPLATE_NAME "Device"
#define BLYNK_AUTH_TOKEN "YourAuthToken"

#define BLYNK_PRINT Serial 

// ******************* MODEM SIM7080 **************************
#define TINY_GSM_MODEM_SIM7080

#include <Arduino.h>
#include <Wire.h>
#include <TinyGsmClient.h>
#include <BlynkSimpleTinyGSM.h>

// ********** CONFIGURACION DE COMUNICACIONES SERIALES ********
#define SerialMon Serial
#define SerialAT Serial2
#define TINY_GSM_DEBUG SerialMon

// ************ CONFIGURACION DE PINOUT MIKROBUS ***************
#define MIKROBUS_AN 4
#define MIKROBUS_RST 15
#define MIKROBUS_CS 6
#define MIKROBUS_SCK 8
#define MIKROBUS_MISO 18
#define MIKROBUS_MOSI 17
#define MIKROBUS_PWM 5
#define MIKROBUS_INT 7
#define MIKROBUS_RX 9
#define MIKROBUS_TX 10
#define MIKROBUS_SCL 13
#define MIKROBUS_SDA 12

#define BOARD_LED 16

// En éste ejemplo se usará el botón BOOT
// para actualizar la posición GNSS
#define UPDATE_BUTTON 0
#define PIN_MODEM_PK MIKROBUS_INT

// *************** CONFIGURACION OPERADORA LTE ******************
const char apn[]  = "";
const char user[] = "";
const char pass[] = "";

// ************** CONFIGURACION SERVIDOR BLYNK ******************
const char domain[] = "ny3.blynk.cloud";
const char auth[] = BLYNK_AUTH_TOKEN;


// ******************* VARIABLES GLOBALES ***********************
static BlynkTimer scheduler;
static TinyGsm modem(SerialAT);

// Para poder utilizar el valor de posición en todo el programa
// declaramos las variables de latitud y longitud como variables
// globales.
static float gps_latitude  = NAN;
static float gps_longitude = NAN;

// ********************* FUNCIONES GNSS *************************
void updatePosition();
bool getGNSS();

void setup() {

  // Configuración de comunicaciones seriales
  SerialMon.begin(115200);
  SerialAT.begin(115200, SERIAL_8N1, MIKROBUS_RX, MIKROBUS_TX );
  Wire.setPins( MIKROBUS_SDA, MIKROBUS_SCL );
  Wire.begin();

  // Inicialización de I/O
  pinMode( BOARD_LED, OUTPUT );
  digitalWrite( BOARD_LED, LOW );
  pinMode( UPDATE_BUTTON, INPUT_PULLUP );
  
  pinMode( PIN_MODEM_PK, OUTPUT );
  
  // Reinicio del modem LTE por hardware
  digitalWrite( PIN_MODEM_PK, HIGH );
  delay(3000);
  digitalWrite( PIN_MODEM_PK, LOW );

  // Configuración inicial del modem LTE
  SerialMon.println("Iniciando modem LTE...");
  modem.restart();
  String modemInfo = modem.getModemInfo();
  SerialMon.print("Modem: ");
  SerialMon.println(modemInfo);

  // Obtener posición en coldboot
  getGNSS();

  // Iniciar comunicación con Blynk.Cloud
  Blynk.begin(auth, modem, apn, user, pass, domain);
}

void loop() {

  Blynk.run();
  scheduler.run();

  // Si se presiona el botón
  if ( !digitalRead( UPDATE_BUTTON ) ){
    updatePosition();
  }
    
}

bool getGNSS() {
  // Colocamos un tiempo de espera máximo de 30 segundos y 90 para coldboot
  static bool coldboot = true;
  const unsigned long timeout_coldboot = 90000;
  const unsigned long timeout_run = 30000;

  float speed;
  float alt;
  int vsat;
  int usat;
  float accuracy;
  int year;
  int month;
  int day;
  int hour;
  int minute;
  int second;

  unsigned long timer = 0;
  unsigned long timeout = 0;
  bool success = false;

  if ( coldboot ){
    timeout = timeout_coldboot;
  } else {
    timeout = timeout_run;
  }

  // Finaliza las comunicaciones LTE e inicia
  // GNSS
  modem.gprsDisconnect();
  if ( !modem.enableGPS() ) {
    return false;
  }

  // Comenzamos el temporizador
  timer = millis();

  // Mientras no se agote el tiempo de espera intentar obtener la posición
  while ( ( millis() - timer ) < timeout ) {

    success = modem.getGPS( &gps_latitude, &gps_longitude, &speed, &alt, &vsat, &usat, &accuracy,
                            &year, &month, &day, &hour, &minute, &second );

    // Si se obtiene la posición exitosamente entonces finalizar el bucle
    if ( success ) {
      break;
    }
  }

  // Finaliza el GNSS y vuelva a iniciar las comunicaciones GNSS
  modem.disableGPS();
  modem.gprsConnect( apn, user, pass );

  // Retorna el resultado de la operación, si se obtuvo la posición
  // deshabilita el abanderamiento de Coldboot
  if ( !success ) {
    return false;
  }
  coldboot = false;
  return true;
}

void updatePosition(){
  bool success = false;

  // Si Blynk está conectado...
  if ( Blynk.connected() ) {
    Serial.println( "Desconectando de Blynk..." );
    Blynk.disconnect();
  }

  Serial.println( "Obteniendo posicion GNSS..." );

  success = getGNSS();

  Serial.println( "Reconectando a Blynk" );
  Blynk.connect();

  if ( !success ){
    Serial.println( "Error al obtener fix GNSS..." );
  }

  return;
}

BLYNK_CONNECTED() {
  digitalWrite( BOARD_LED, HIGH );
}

BLYNK_DISCONNECTED() { digitalWrite( BOARD_LED, LOW ); }
Reducir el tiempo para obtener la posición

En los dispositivos GNSS el tiempo para obtener la posición la primera vez (TTFF) demora significativamente más tiempo. Esto se debe a las condiciones de inicio:

  • Cold start: Ocurre cuando el dispositivo se apaga y enciende, en este estado es necesario obtener información de los satélites para estimar la posición. Este proceso es el más largo, puede demorar de 10 segundos hasta 10 minutos, dependiendo de la posición de la antena.

  • Warm start: Ocurre cuando el dispositivo deshabilita y habilita la antena GNSS, requiere descargar algunos datos de los satélites, pero conserva alguno. Este proceso demora algo de tiempo, pero es significativamente más corto que el "Cold start", aproximadamente de 10 a 30 segundos.

  • Hot start: Ocurre siempre y cuando la antena GNSS se mantenga habilitada. Este proceso es casi inmediato.

Para obtener una posición coloca la antena GNSS a cielo abierto durante el proceso de "Cold start", una vez se obtenga la primera posición el dispositivo deberá mantenerse encendido incluso aunque se deshabilite la antena GNSS y se use las funciones LTE.

Evitar el uso de la función delay mientras se encuentra una conexión activa con la nube

En Arduino delay es una función que bloquea la CPU, lo que impide que TinyGSM pueda mantener la conexión con la nube, lo que causará desconexiones frecuentes y pérdida de información enviada desde la nube hacia el dispositivo. En su lugar utiliza el objeto de BlynkTimer y sus funciones.

Recuerda que esto solo aplica si se encuentra una conexión activa con la nube, si se deshabilitó la conexión con el servidor entonces puedes usar delay.

// Objeto BlynkTimer, se encarga
// de crear temporizadores para
// llamar funciones en tiempos
// definidos
static BlynkTimer scheduler;

// Función que se llamará por el objeto scheduler
void fun(){
}

void main(){
    // El método setTimeout solo ejecutará 1 vez
    // la función "fun" cuando pasen 10s (10000ms)
    scheduler.setTimeout( 10000UL, fun);
    
    // El método setInterval ejecutará la función
    // "fun" cada 10s (10000ms)
    scheduler.setInterval( 20000UL, fun );
}

void loop(){
    // El método run deberá ejecutarse tan
    // frecuentemente como sea posible, pues
    // se encarga de revisar el estado de los
    // temporizadores
    scheduler.run();
}
Recibir información de Blynk mientras se utiliza el GNSS

Las funciones GNSS y LTE no se pueden utilizar al mismo tiempo, por lo que no se puede recibir información mientras se obtiene la posición. Sin embargo, el dispositivo puede consultar los valores de los datastream al volver a conectarse a la red con el siguiente fragmento de código.

// BLYNK_CONNECTED está función se ejecutará
// cada vez que el dispositivo se conecte a la
// red de Blynk.
BLYNK_CONNECTED() {
  // Coloque los datastream a consultar
  Blynk.syncVirtual( V1, V2, ...., Vn );
}

// Reemplaza Vx por el datastream del que se deasea
// recibir información.
BLYNK_WRITE( Vx ){
  // Código para procesar el datastream
  // Recuerda que debes usar el tipo de dato
  // correcto.
  int var_int = param.asInt();
  float var_float = param.asFloat();
  double var_double = param.asDouble();
  
}
Vigila el consumo de datos

Durante el desarrollo de la aplicación estructura la solución en módulos, escribe funciones que solucionen los requerimientos de manera modular. Evita desperdiciar datos celulares durante pruebas que no requieran conexión a internet. Escribe código eficiente, solo envía mensajes a la nube cuando sea necesario, recuerda que al inicio del reto contarás con un máximo de 30MB de datos.

El dispositivo no se conecta a la nube; Verificar que la SIM aún cuente con datos

El equipo de soporte puede ayudarte a verificar que la tarjeta SIM aún cuente con datos disponibles y que se encuentre correctamente configurada para utilizar una operadora.

Última actualización

¿Te fue útil?