Bosch XDK: Comande-o por voz com IBM Bluemix Speech to Text

Speech to Text
Este post faz parte da série Bosch XDK. Leia também os outros posts da série:

Olá caro leitor! Continuo com a minha saga explorando o Bosch XDK, que se à primeira vista pode parecer caro, ele entrega valor onde precisa no momento de implementar soluções completas para coleta de dados distribuída ou atuação remota. Neste artigo vamos continuar na linha de integração entre Bosch e IBM, onde vamos apresentar um projeto mostrado no último Meetup na IBM Hortolândia que rolou no mês passado. Nele comandamos o XDK por voz!

 

Comandando um sensor node por voz?

 

Isso, você não leu errado, com o uso do serviço Speech to Text da IBM podemos capturar o áudio de uma fonte como, por exemplo, a placa de áudio de um computador, enviar esses dados para o serviço de transcrição, que nos devolve o texto equivalente onde poderemos mapear os caracteres e verificar se a sentença falada é ou contém um comando. A arquitetura dessa ideia de projeto é apresentada abaixo:

 

Comande o Bosch XDK por voz com IBM Bluemix Speech to Text

Sobre o XDK não temos muito o que adicionar, mas se por um acaso o leitor quiser conhecer mais sobre esse poderoso sensor node, pode verificar neste meu artigo onde foi dada uma introdução e falamos um pouco sobre as características chave desse dispositivo (e não esqueça de voltar aqui depois hein).

 

Uma coisa interessante é que integraremos duas ferramentas do IBM Bluemix, o Watson IoT Platform, e o já citado Speech to Text. Sobre o primeiro, temos um guia completo para integrar o XDK no gerenciador de dispositivos IoT da IBM, então antes de continuar, dê uma passadinha neste artigo aqui.

 

Para esse projeto, desenvolveremos duas aplicações, uma no firmware do XDK, e outra aplicação Desktop em Java. Mas não se engane, a aplicação desenvolvida poderia ser voltada para um dispositivo móvel baseado em Android.

 

Mas então o que essa demonstração vai fazer? Bom, no artigo guia de integração do XDK com o Watson IoT nosso firmware iniciava e parava de fazer uma coleta de dados dos sensores da placa ao pressionar um dos botões, certo? Pois bem, o XDK agora vai receber comandos vindos da plataforma IoT da IBM utilizando o protocolo de mensagem padrão MQTT, que vai substituir o pressionamento dos botões e iniciar ou pausar a aquisição de dados.

 

Ok, mas quem é que envia esses comandos ao XDK? Sim, a aplicação em Java que, pasmem, pode estar rodando num computador em qualquer lugar do mundo! Bastando ter as credenciais do serviço Speech to Text e o Device-id do dispositivo XDK integrado previamente no Watson IoT.

 

Para disparar o envio do comando via MQTT, a aplicação fica constantemente observando o áudio que chega à placa de som do computador, e envia para o Speech to Text fazer a transcrição. Quando o texto contém o comando desejado, ele então dispara um comando pelo MQTT para o Device-id apontado, que é o XDK, e reinicia o ciclo.

 

 

Gostei, o que preciso para rodar esse projeto?

 

Vamos preparar o ambiente para rodar essa demonstração. Para isso vamos listar os requisitos necessários:

  • Bosch XDK Cross Domain kit;
  • Bosch XDK Workbench versão 2.x;
  • Notebook com conexão à internet;
  • SO Windows ou Linux (utilizaremos o Ubuntu nesse exemplo);
  • Apache Maven, para build da aplicação Java;
  • Conta IBM Bluemix com Watson IoT e Speech to Text configurados;
  • Repositório com o código fonte para XDK e Aplicação Java, aqui.

 

Com essa listinha em mãos podemos preparar todo ambiente para rodar nosso projeto. Para o XDK Workbench, citamos a versão 2.x pois a atual 3.x sofreu grandes modificações no SDK e o projeto ainda não foi testado nela.

 

Na sua máquina de desenvolvimento importe o projeto de firmware encontrado no repositório (não mexa em nada ainda, falaremos sobre o código mais adiante). Ainda na sua máquina de desenvolvimento, instale o Maven build system, utilize as instruções do fornecedor aqui, essa ferramenta é necessária para resolver as dependências da aplicação Java, em especial, as existentes da API do IBM Bluemix.

 

Não se preocupe com as URLs dos repositórios, o arquivo utilizado pelo Maven da nossa demonstração já está devidamente populado. Extraia o projeto da aplicação Java em um local conhecido, e também não mexa na aplicação ainda. Com esse passo feito teremos todo o necessário para construir nossa aplicação.

 

 

Credenciais: Preparando o Speeh to Text da IBM

 

Esse passo ja é conhecido para quem leu o guia de integração do XDK ao Watson. Teremos que refazer esse passo, mas dessa vez para o Speech to Text. A vantagem aqui é que a burocracia é menor, para ter acesso ao serviço pela aplicação Java, primeiramente logue em sua conta IBM Bluemix e selecione um novo serviço, em seguida Speech to Text.

 

 

Ao criar o serviço, agora precisamos gerar as credenciais, para isso observe as imagens abaixo, e ao final do processo guarde a autenticação com você, iremos inserir esses dados em um local conveniente da aplicação Java:

 

 

Pondo as mãos no código fonte!

 

Agora, efetivamente, vamos mexer nas coisas, o lado do firmware do XDK não precisa de grandes modificações, mas um item que constantemente me é perguntado é onde inserir os dados de WiFi e credenciais para acessar o IoT Watson. Para isso abra o arquivo mqttConfig.h localizado na pasta source, você deve ver algo assim:

/******************************************************************************
**	COPYRIGHT (c) 2016		Bosch Connected Devices and Solutions GmbH
**
**	The use of this software is subject to the XDK SDK EULA
**
*******************************************************************************
**
**	OBJECT NAME:	mqttConfig.h
**
**	DESCRIPTION:	Configuration header for the MQTT Paho Client
**
**	PURPOSE:        Contains the common macro, typedef, variables and function
**	                definitions for the entire project
**
**	AUTHOR(S):      Bosch Connected Devices and Solutions GmbH (BCDS)
**
**	Revision History:
**
**	Date			 Name		Company      Description
**  2016.Apr         crk        BCDS         Initial Release
**
*******************************************************************************/

/* header definition ******************************************************** */
#ifndef _MQTT_CONFIG_H_
#define _MQTT_CONFIG_H_

/* Config interface declaration ********************************************** */

/* Config type and macro definitions */
#define XDK_PAHO_DEMO_REVISION       "0.2.0"

#define NUMBER_UINT8_ZERO		     UINT8_C(0)     /**< Zero value */
#define NUMBER_UINT32_ZERO 		     UINT32_C(0)    /**< Zero value */
#define NUMBER_UINT16_ZERO 		     UINT16_C(0)    /**< Zero value */
#define NUMBER_INT16_ZERO 		     INT16_C(0)     /**< Zero value */

#define POINTER_NULL 			     NULL          /**< ZERO value for pointers */

#define TIMER_AUTORELOAD_ON          1             /**< Auto reload timer */
#define TIMER_AUTORELOAD_OFF         0             /**< One Shot Timer */

#define ENABLED         1
#define DISABLED        0

#warning Provide Default WLAN and MQTT Configuration Here
// Default Network Configuration Settings
#define	WLAN_SSID	  		"Desktop_F9A84202"      	  					  	  /**< WLAN SSID Name */
#define	WLAN_PWD	  		"1919xxxx"          							  /**< WLAN PWD */
#define	MQTT_CLIENT_ID	    "d:bq0xxx:bosch_xdk_huehue_brbr:ulipe_bosch_xdk"  /**< MQTT Client ID */
//#define	MQTT_CLIENT_ID	    "bosch_xdk_huehue_brbr"             	  		/**< MQTT Client ID */

#define MQTT_BROKER_NAME    "bq0tr8.messaging.internetofthings.ibmcloud.com"  /**< MQTT Broker */
#define MQTT_PORT           1883                          					  /**< MQTT Port Number */

#define IBM_BLUEMIX_DEVICE_TOKEN "10gRBU-*[email protected]"
#define IBM_BLUEMIX_USERNAME     "use-token-auth"

// Default Data Configuration Settings
#define STREAM_RATE         2000/portTICK_RATE_MS /**< Stream Data Rate in MS */
#define ACCEL_EN            ENABLED               /**< Accelerometer Data Enable */
#define GYRO_EN             ENABLED               /**< Gyroscope Data Enable */
#define MAG_EN              ENABLED               /**< Magnetometer Data Enable */
#define ENV_EN              ENABLED               /**< Environmental Data Enable */
#define LIGHT_EN            ENABLED               /**< Ambient Light Data Enable */

#define WDG_FREQ            1000
#define WDG_TIMEOUT         5000

/* global function prototype declarations */

/* global variable declarations */

/* global inline function definitions */

#endif /* _MQTT_CONFIG_H_ */

/** ************************************************************************* */

 

Vá direto à linha 48, as constantes definidas nessa linha basicamente representam o ID e Senha da sua WiFi, basta adicionar a string correspondente a esses valores. Com isso o XDK conseguirá se conectar à rede.

 

Para conectar o XDK no Watson IoT, você deve fornecer seu MQTT_ID, que é a string padrão pro serviço da IBM. A estrutura dessa string pode ser encontrada no guia de integração XDK e Watson IoT. E por último, você precisa passar a URL do broker MQTT desejado, no caso o da IBM, para isso edite a variável MQTT_BROKER_NAME. Feita essas alterações, compile o projeto e clique na opção Flash e pronto, seu XDK em alguns segundos estará conectado ao Watson IoT Platform aguardando comandos.

 

O passo mais chatinho nesse projeto reside na aplicação Java, para isso, agora volte ao projeto que você extraiu. Primeiramente precisamos configurar as credenciais e o Device-id que a aplicação deverá acessar, para isso dentro do diretório xdk_commander navegue para src/main/resources, você verá um arquivo chamado de application.properties, abra-o em um editor de texto e você deve ver algo parecido com o que está abaixo:

## Mandatory fields
id = 123456789
Organization-ID = bq0xxx
Authentication-Method = apikey
API-Key = a-bq0xxx-xxxxxxxxxx
Authentication-Token = [email protected])xxxxxx

## Device on behalf the application needs to subscribe to events or publish events
Device-Type = bosch_xdk_huehue_brbr
Device-ID = ulipe_bosch_xdk

## Speech To Text Credentials
stt-username = c025b81f-3e37-46b0-b035-f8dde5xxxxxx
stt-password = mzSBPRxxxxxx

 

Basicamente todos os campos deverão ser populados de acordo com o valor gerado. Em Organization-ID, por exemplo, você precisa do org-id da sua conta Bluemix; API-Key e Authentication token são obtidos ao criar um dispositivo no Watson IoT, e caso você não tenha anotado, volte no IoT Platform e gere o dispositivo novamente. Device-Type e ID basicamente são os mesmos valores passados no firmware do XDK.

 

Por fim, pegue as credenciais do Speech to Text que você gerou anteriormente e adicione em stt-username e password, respectivamente. Pronto, todas as credenciais estão populadas, agora a aplicação Java vai poder acessar o Bluemix para transcrever áudio e enviar comandos pelo MQTT.

 

Estamos prontos para fazer o build, sigam os passos, primeiro retorne à pasta xdk_commander e abra um terminal. Iremos resolver as dependências usando o Maven previamente instalado, para isso:

mvn clean package

 

Esse passo pode demorar alguns minutos pois basicamente o Maven vai fazer fetch de todos os fontes necessários para build da aplicação. Terminado esse passo, finalmente, faça o build da aplicação com:

 mvn exec:java -Dexec.mainClass="com.ibm.watsoniot.xdkVoiceController"

 

Lembrando que esse mesmo comando também irá rodar a aplicação. Se a conexão com internet estiver disponível, imediatamente ele irá conectar aos serviços do Bluemix e transmitir comandos que batam com as sentenças esperadas.

 

 

Fiquei curioso, como isso funciona?

 

Para entender o funcionamento principal dessa aplicação, vamos dar uma olhada nos fontes principais. Partindo da aplicação em java, vejam a classe principal abaixo:

/**
 *****************************************************************************
 * Copyright (c) 2016 IBM Corporation and other Contributors.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Sathiskumar Palaniappan - Initial Contribution
 * Prasanna Alur Mathada - Initial Contribution
 * Jose Paul - Initial Contribution
 *****************************************************************************
 */
package com.ibm.watsoniot;

import java.io.IOException;
import java.util.List;
import java.util.Properties;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;

import com.google.gson.JsonObject;
import com.ibm.iotf.client.app.ApplicationClient;
import com.ibm.watson.developer_cloud.http.HttpMediaType;
import com.ibm.watson.developer_cloud.speech_to_text.v1.SpeechToText;
import com.ibm.watson.developer_cloud.speech_to_text.v1.model.RecognizeOptions;
import com.ibm.watson.developer_cloud.speech_to_text.v1.model.SpeechAlternative;
import com.ibm.watson.developer_cloud.speech_to_text.v1.model.SpeechResults;
import com.ibm.watson.developer_cloud.speech_to_text.v1.model.Transcript;
import com.ibm.watson.developer_cloud.speech_to_text.v1.websocket.BaseRecognizeCallback;

/**
 * A Java application developed using the Watson Developer Cloud Java SDK, 
 * streams the voice from the user and invokes the Watson Speech to Text(STT) service 
 * to convert the voice to text. 
 * 
 * The returned text then parsed and mapped to one of the above commands. 
 * In this sample, we showcase a simple mapping wherein if a sentence contains a word �Red�, 
 * then it maps to the Red color command. The command is then sent to the Watson IoT Platform 
 * through MQTT. T
 * he Java application uses the Watson IoT java client library for sending the commands to the 
 * Watson IoT Platform.
 */
public class xdkVoiceController {
	
	private final static String PROPERTIES_FILE_NAME = "/application.properties";
	
	private ApplicationClient myClient;
	/**
	 * Get the Device Type and Device Id on behalf the application will publish the event
	 */
	private String deviceType;
	private String deviceId;
	private String sttUsername;
	private String sttPassword;
	
	/**
	 * Create and connect the application to Watson IoT Platform based on the credentials 
	 * specified in application.properties file.
	 */
	private void createApplication() {
		/**
	     * Load device properties
	     */
		Properties props = new Properties();
		try {
			props.load(xdkVoiceController.class.getResourceAsStream(PROPERTIES_FILE_NAME));
		} catch (IOException e1) {
			System.err.println("Not able to read the properties file, exiting..");
			System.exit(-1);
		}		
		
		//Instantiate and connect to IBM Watson IoT Platform
		
		try {
			myClient = new ApplicationClient(props);
			/**
			 * Get the Device Type and Device Id on behalf the application will publish the event
			 */
			deviceType = trimedValue(props.getProperty("Device-Type"));
			deviceId = trimedValue(props.getProperty("Device-ID"));
			this.sttUsername = trimedValue(props.getProperty("stt-username"));
			this.sttPassword = trimedValue(props.getProperty("stt-password"));
			myClient.connect();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) throws Exception {
		xdkVoiceController lt = new xdkVoiceController();
		lt.createApplication();
		lt.streamVoice();
		System.out.println("Wait for a second and start speaking");
		// Run for an hour
		Thread.sleep(1000);
	}
	
	/* run start or stopping acquisition */
	 private enum COMMAND {

		 /* maps to portuguese words */
		 START("start"),
		 STOP("stop");


		 private final String command;
		 
		@Override
		public String toString() {
			// TODO Auto-generated method stub
			return this.command;
		}

		 /**
		  * @param colour
		  */
		 private COMMAND(final String command) {
			 this.command = command;
		 }
		 
		 /**
		  * Form the payload based on the user transcript
		  * @param transcript
		  * @return
		  */
		 static JsonObject getPayload(String transcript) {
			 String capTranscript = transcript.toLowerCase();
			 JsonObject json = new JsonObject();
			 JsonObject values = new JsonObject();

			 // Map similar words to roll
			 if(capTranscript.contains(COMMAND.START.toString())) {
				 json.addProperty("action", START.toString());
				 return json;
			 } else if(capTranscript.contains(COMMAND.STOP.toString())) {
				 json.addProperty("action", STOP.toString());
				 return json;
			 } 
			 return null;
		 }
	}
	
	/**
	 * Core method that streams the voice and sends the command to Watson IoT Platform
	 * @throws LineUnavailableException
	 */
	private void streamVoice() throws LineUnavailableException {
	    SpeechToText service = new SpeechToText();
	    service.setUsernameAndPassword(this.sttUsername, this.sttPassword);

	    // Signed PCM AudioFormat with 16kHz, 16 bit sample size, mono
	    int sampleRate = 16000;
	    AudioFormat format = new AudioFormat(sampleRate, 16, 1, true, false);
	    DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
	
	    if (!AudioSystem.isLineSupported(info)) {
	      System.out.println("Line not supported");
	      System.exit(0);
	    }
	
	    TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
	    line.open(format);
	    line.start();
	
	    AudioInputStream audio = new AudioInputStream(line);
	
	    RecognizeOptions options = new RecognizeOptions.Builder()
	      .continuous(true)
	      .interimResults(true)
	      .contentType(HttpMediaType.AUDIO_RAW + "; rate=" + sampleRate)
	      .build();
	
	    service.recognizeUsingWebSocket(audio, options, new BaseRecognizeCallback() {
	      @Override
	      /**
	       * Called when the speech is converted to text.
	       */
	      public void onTranscription(final SpeechResults speechResults) {
	    	  List<Transcript> transcripts = speechResults.getResults();
	    	  for(int i = 0; i < transcripts.size(); i++) {
	    		  Transcript transcript = transcripts.get(i);
	    		  if(transcript.isFinal()) {
	    			  // Proceed only if its final
	    			  List<SpeechAlternative> alternatives = transcript.getAlternatives();
	    			  for(int j = 0; j < alternatives.size(); j++) {
	    				  System.out.println("Got tanscript: "+ alternatives.get(j).getTranscript());
	    				  //Map it to the available command
	    				  JsonObject payload = COMMAND.getPayload(alternatives.get(j).getTranscript());
	    				  if(payload != null) {
	    					  System.out.println("Publishing command: "+ payload.toString());
	    					  // Publish to Watson IoT Platform mentioning the device
	    					  myClient.publishCommand(deviceType, deviceId, "execute", payload);
	    				  }
		    		  }
		    	  }
		      }
	      }
	    });
	}
	
	
	private static String trimedValue(String value) {
		if(value != null) {
			return value.trim();
		}
		return value;
	}

}

 

Utilizei um exemplo fornecido pela IBM de como acessar o Speech to Text e fiz minhas modificações. A primeira é escanear a fonte de áudio a cada segundo, assim o método Main roda infinitamente e utiliza o método CreateApplication(), onde ele basicamente conecta-se aos serviços do Bluemix. Em seguida ele chama o método StreamVoice(), onde ele captura o áudio corrente, abre um WebSocket e envia a requisição ao serviço Speech to Text e instrui a chamada da callback onTranscription().

 

Essa chamada vai procurar na string recebida se existe um dos comandos válidos (Start ou Stop), caso positivo um Publish é enviado ao Device-ID (no caso o XDK), contendo o comando a ser processado e ciclo de scan se inicia.

 

No firmware o processo é baixo nível, mas nem tanto, vamos abrir o arquivo que contém a thread que cuida do MQTT:

/******************************************************************************
**	COPYRIGHT (c) 2016		Bosch Connected Devices and Solutions GmbH
**
**	The use of this software is subject to the XDK SDK EULA
**
*******************************************************************************
**
**	OBJECT NAME:	mqttClient.c
**
**	DESCRIPTION:	Source Code for the MQTT Paho Client
**
**	PURPOSE:        Initializes the Paho Client and sets up subscriptions,
**	                starts the task to pubish and receive data,
**	                initializes the timer to stream data,
**	                defines the callback function for subscibed topics
**
**	AUTHOR(S):		Bosch Connected Devices and Solutions GmbH (BCDS)
**
**	Revision History:
**
**	Date			 Name		Company      Description
**  2016.Apr         crk        BCDS         Initial Release
**
*******************************************************************************/

/* system header files */
#include <stdint.h>

/* own header files */
#include "mqttPahoClient.h"
#include "mqttConfig.h"
#include "mqttSensor.h"

/* additional interface header files */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "PTD_portDriver_ph.h"
#include "PTD_portDriver_ih.h"
#include "WDG_watchdog_ih.h"

/* paho header files */
#include "MQTTConnect.h"
#include "cJSON.h"

/* constant definitions ***************************************************** */
#define MQTT_JSON_OFFSET


/* local variables ********************************************************** */
// Buffers
static unsigned char buf[CLIENT_BUFF_SIZE];
static unsigned char readbuf[CLIENT_BUFF_SIZE];


// Client Task/Timer Variables
static xTimerHandle     clientStreamTimerHandle      = POINTER_NULL;  // timer handle for data stream
static xTaskHandle      clientTaskHandler            = POINTER_NULL;  // task handle for MQTT Client
static uint8_t clientDataGetFlag = NUMBER_UINT8_ZERO;
static uint32_t clientMessageId = 0;

// Subscribe topics variables
char clientTopicRed[CLIENT_BUFF_SIZE];
char clientTopicOrange[CLIENT_BUFF_SIZE];
char clientTopicYellow[CLIENT_BUFF_SIZE];
char clientTopicDataGet[CLIENT_BUFF_SIZE];
char clientTopicVoice[CLIENT_BUFF_SIZE];

char clientTopicDataStream[CLIENT_BUFF_SIZE];
const char *clientTopicRed_ptr = TOPIC_LED_RED;
const char *clientTopicOrange_ptr = TOPIC_LED_ORANGE;
const char *clientTopicYellow_ptr = TOPIC_LED_YELLOW;
const char *clientTopicDataGet_ptr = TOPIC_DATA_GET;
const char *clientTopicVoice_ptr = COMMAND_VOICE;


const char *clientTopicDataStream_ptr = TOPIC_DATA_STREAM;


/* global variables ********************************************************* */
// Network and Client Configuration
Network n;
Client c;

/* inline functions ********************************************************* */

/* local functions ********************************************************** */
static void clientRecv(MessageData* md);
static void clientTask(void *pvParameters);

/**
 * @brief callback function for subriptions
 *        toggles LEDS or sets read data flag
 *
 * @param[in] md - received message from the MQTT Broker
 *
 * @return NONE
 */
static void clientRecv(MessageData* md)
{
	/* Initialize Variables */
	MQTTMessage* message = md->message;

	if((strncmp(md->topicName->lenstring.data, clientTopicVoice_ptr, md->topicName->lenstring.len) == 0)) {

		printf("Subscribed Topic, %.*s, Message Received: %.*s\r\n", md->topicName->lenstring.len, md->topicName->lenstring.data,
				                                                   (int)message->payloadlen, (char*)message->payload);

		/* find the action desired in JSON file */
		cJSON * root = cJSON_Parse((char *)message->payload);
		cJSON * data = cJSON_GetObjectItemCaseSensitive(root, "d");
		cJSON * action = cJSON_GetObjectItemCaseSensitive(data, "action");


		if(!strcmp(action->valuestring, "start")) {
			clientStartTimer();
		} else if (!strcmp(action->valuestring, "stop")) {
			clientStopTimer();
		} else {
			printf("Spurious event, discarding! \n\r");
		}
	}

}

/**
 * @brief publish sensor data, get sensor data, or
 *        yield mqtt client to check subscriptions
 *
 * @param[in] pvParameters UNUSED/PASSED THROUGH
 *
 * @return NONE
 */
static void clientTask(void *pvParameters)
{
	/* Initialize Variables */
	MQTTMessage msg;

	/* Forever Loop Necessary for freeRTOS Task */
    for(;;)
    {
    	WDG_feedingWatchdog();
    	/* Publish Live Data Stream */
        if(sensorStreamBuffer.length > NUMBER_UINT32_ZERO)
        {

        	printf("clientTask(): publishing sensor stream! \n\r");
            msg.id = clientMessageId++;
            msg.qos = 0;
            msg.payload = sensorStreamBuffer.data;
            msg.payloadlen = sensorStreamBuffer.length;
            MQTTPublish(&c, clientTopicDataStream_ptr, &msg);

        	memset(sensorStreamBuffer.data, 0x00, SENSOR_DATA_BUF_SIZE);
        	sensorStreamBuffer.length = NUMBER_UINT32_ZERO;
        }
        else if(clientDataGetFlag) {
        	printf("clientTask(): preparing stream! \n\r");
        	sensorStreamData(pvParameters);
        	clientDataGetFlag = DISABLED;
        }
        else {
            MQTTYield(&c, CLIENT_YIELD_TIMEOUT);
        }
    }
}

/* global functions ********************************************************* */

/**
 * @brief starts the data streaming timer
 *
 * @return NONE
 */
void clientStartTimer(void)
{
	/* Start the timers */
	xTimerStart(clientStreamTimerHandle, UINT32_MAX);
	return;
}
/**
 * @brief stops the data streaming timer
 *
 * @return NONE
 */
void clientStopTimer(void)
{
	/* Stop the timers */
	xTimerStop(clientStreamTimerHandle, UINT32_MAX);
	return;
}

/**
 * @brief Initializes the MQTT Paho Client, set up subscriptions and initializes the timers and tasks
 *
 * @return NONE
 */
void clientInit(void)
{
	/* Initialize Variables */
    int rc = 0;
	WDG_feedingWatchdog();

    NewNetwork(&n);
    ConnectNetwork(&n, MQTT_BROKER_NAME, MQTT_PORT);
    MQTTClient(&c, &n, 1000, buf, CLIENT_BUFF_SIZE, readbuf, CLIENT_BUFF_SIZE);

    /* Configure the MQTT Connection Data */
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.willFlag = 0;
    data.MQTTVersion = 3;
    data.clientID.cstring = MQTT_CLIENT_ID;
    data.keepAliveInterval = 100;
    data.cleansession = 1;
    data.password.cstring = IBM_BLUEMIX_DEVICE_TOKEN;
    data.username.cstring = IBM_BLUEMIX_USERNAME;

    printf("Connecting to %s %d\r\n", MQTT_BROKER_NAME, MQTT_PORT);

    /* Connect to the MQTT Broker */
	WDG_feedingWatchdog();
    rc = MQTTConnect(&c, &data);


	memset(clientTopicVoice, 0x00, CLIENT_BUFF_SIZE);
	sprintf((char*) clientTopicVoice, COMMAND_VOICE, (const char*) MQTT_CLIENT_ID);
	clientTopicVoice_ptr = (char*) clientTopicVoice;


	memset(clientTopicDataStream, 0x00, CLIENT_BUFF_SIZE);
	sprintf((char*) clientTopicDataStream, TOPIC_DATA_STREAM, (const char*) MQTT_CLIENT_ID);
	clientTopicDataStream_ptr = (char*) clientTopicDataStream;


	/* Subscribe to receive voice commands */
	rc = MQTTSubscribe(&c, clientTopicVoice_ptr, QOS0, clientRecv);


	/* Create Live Data Stream Timer */
    clientStreamTimerHandle = xTimerCreate(
			(const char * const) "Data Stream",
			STREAM_RATE,
			TIMER_AUTORELOAD_ON,
			NULL,
			sensorStreamData);

	/* Create MQTT Client Task */
    rc = xTaskCreate(clientTask, (const char * const) "Mqtt Client App",
                    		CLIENT_TASK_STACK_SIZE, NULL, CLIENT_TASK_PRIORITY, &clientTaskHandler);

    /* Error Occured Exit App */
    if(rc < 0)
    {
    	clientDeinit();
    }

    return;
}

/**
 * @brief Disconnect from the MQTT Client
 *
 * @return NONE
 */
void clientDeinit(void)
{
    MQTTDisconnect(&c);
    n.disconnect(&n);
}

 

A thread ClientTask() basicamente cuida do processo de transmissão e recepção de dados, ela fica em repouso até que a variável clientDataGetFlag sejá colocada em true. Isso ocorre quando um comando é publicado pela aplicação Java, o payload vem por MQTT em formato JSON e invoca a callback ClientRecv(). Essa função pesquisa no JSON se é o comando Start ou Stop, baseado nesses comandos clientDataGetFlag é colocado em true e o XDK passa a fazer a aquisição de dados dos sensores on board. Os dados são formatados em JSON e enviados ao IoT Platform onde o usuário do Bluemix poderá ver os dados que chegam, ou criar gráficos para ver sua evolução ao longo do tempo.

 

Lembrando que é possível adicionar comandos em português e disparar o sensor com frases inteiras se desejado. Legal não?

 

 

Conclusão

 

O objetivo desse artigo foi demonstrar mais um caso de aplicação de Internet das coisas na sua forma mais real, para isso contamos com um dispositivo de borda conectado, o Bosch XDK, seu arsenal de sensores, um serviço de nuvem poderoso como IBM Bluemix fornecendo ferramentas fantásticas como gerenciador de dispositivos IoT e Speech to text. Com essas ferramentas e em algumas horas de código pudemos escrever um caso de comando remoto envolvendo voz. E você leitor, acha que esse projeto clareou tanto para uso do XDK quanto do IBM Watson? Postem seus comentários e fiquem ligados, que postaremos mais projetos legais com a dobradinha XDK e IBM Watson, até a próxima!

 

 

Referências

 

Outros artigos da série

<< Apresentando o Bosch XDK Sensor X-perience
Este post faz da série Bosch XDK. Leia também os outros posts da série:
NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Felipe Neves
Desenvolvedor de sistemas embarcados apaixonado pelo que faz, divide seu tempo entre trabalhar no Venturus desenvolvendo firmware de tudo quanto é coisa, na Aeolus Robotics se envolvendo com o que há de mais legal em robótica e na Overlay Tech desenvolvendo algumas coisas bem legais para o campo de motion control. Possui mestrado em engenharia elétrica pela Poli-USP e possui interesse em tópicos como: Software embarcado, sistemas de tempo real, controle, robótica móvel e manipuladores, Linux embedded e quase qualquer coisa por onde passe um elétron.

1
Deixe um comentário

avatar
 
1 Comment threads
0 Thread replies
1 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Bruno Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Bruno
Visitante
Bruno

opa legal, cai de paraquedas no seu site.. estou procurando o que a industria 4.0 irá trazer.. voce tem mais aplicações do xdk ?