Projeto WakeUP

O funcionamento do sistema Wakeup consiste basicamente em aproveitar a capacidade do sensor (Kinect) em reconhecer alguns movimentos faciais e usando essas informações como dados de entrada para a unidade de processamento (Galileo) onde cada movimento facial reconhecido será tratado e tendo como saída do sistema uma indicação sonora orientando o condutor na melhor forma de condução do veículo.

Projeto desenvolvido como auxílio no processo de aprendizagem da disciplina de Infraestrutura de Hardware, ministrada pelo professor Victor Medeiros.
Formado pelo Grupo: Gabriele Pessoa, José Fernando, José Rodrigues e Clarissa Cordeiro.

Projeto que visa aumentar a segurança no trânsito
Os acidentes de trânsito no Brasil atualmente fazem com que uma grande quantidade de vidas sejam perdidas anualmente. Normalmente as pessoas perguntam quem é o culpado onde à pergunta correta é quem poderia ter evitado o acidente. Uma das maiores causas dos acidentes chama-se condutor de veículos.
Estatisticamente, 75% dos acidentes são causados por falha humana (condutor) e 25% por causas diversas, ou seja, podemos dizer que o homem, no mínimo, é responsável direta e indiretamente por 93% dos acidentes.
Entre as diversas causas de acidentes podemos citar algumas:

  1. Ingestão de bebidas alcoólicas;
  2. Falta de atenção;
  3. Distração interna do condutor (rádio, passageiro, celular, objetos soltos no interior do veículo);
  4. Sonolência falta de descanso, drogas (remédios, psicotrópicos, tranquilizantes, etc.) e fadiga;

Portanto, nesses casos, o condutor deve retirar o veículo da via para não causar um acidente ou qualquer outra situação que ponha em risco à segurança do trânsito.
Com o objetivo de auxiliar o condutor na melhor forma de conduzir seu veículo, evitando assim acidentes, o sistema Wakeup monitora os movimentos da cabeça do condutor verificando se o foco de sua atenção está na via pública ou em outra direção. O Wakeup também monitora a fadiga do condutor através da observação seus olhos verificando se estão abertos ou fechados assim como seu tempo de abertura e fechamento.

COMPONENTES

  • Sensor Kinect 2

Apresentando pela Microsoft em 2009 com o nome de Projeto Natal, o Kinect foi desenvolvido para rivalizar diretamente com o Nintendo Wii, porém foi muito mais além eliminando completamente a necessidade de controles, usando o próprio corpo do jogador para realizar os movimentos. Com sensores de movimento aliados a uma câmera de detecção 3D, o aparelho reconhece as movimentações do corpo com uma ótima precisão.

O módulo Kinect tem cerca de 30 cm de comprimento e têm 5 recursos principais:

Câmera de vídeo em HD (1920 x 1080 – 30fps) que permite o reconhecimento facial perfeito da pessoa que está em frente do console (0,5 até 4,5 metros).

Sensor de profundidade Infra Vermelho (512 x 424 – 30fps) que permite que o acessório escaneie o ambiente a sua volta em três dimensões.

Microfone embutido, que além de captar as vozes mais próximas, consegue diferenciar os ruídos externos. Dessa forma, barulhos ao fundo não atrapalham o andamento do Kinect. O microfone também é capaz de detectar várias pessoas diferentes em uma sala (só não se sabe se a precisão é perfeita, já que é comum, por exemplo, irmãos com vozes parecidas).

Próprio processador e software.

Detecta 25 pontos de articulação do nosso corpo, ou seja, possui uma precisão sem precedentes.
kinect

  • Placa Galileo 2

A board de desenvolvimento Intel® Galileo Gen 2 é uma board microcontroladora com base no processador de aplicações Intel® Quark SoC X1000, um sistema de 32 bits Intel® Pentium® em um chip (SoC). Ela é a primeira board baseada na arquitetura Intel® desenvolvida para ter compatibilidade de pinos de hardware and software com proteção desenvolvida para o Arduino Uno* R3.

Esta plataforma oferece a facilidade do desenvolvimento em arquitetura Intel através do suporte a sistemas operacionais Microsoft Windows*, Mac OS* e Linux* do host. Ela também oferece a simplicidade do software do ambiente de desenvolvimento integrado Arduino (IDE).

A board Intel® Galileo Gen 2 também possui compatibilidade de software com o ambiente de desenvolvimento de software Arduino, que agiliza a usabilidade e introdução. Além da compatibilidade de hardware e software com o Arduino, a board Intel® Galileo Gen 2 possui inúmeras portas E/S padrão para PC e recursos para expandir o uso e capacidades nativas além do ecossistema protegido do Arduino. Um slot mini-PCI Express*, porta Ethernet de 100 Mb, slot para cartão Micro-SD, cabeçote UART TTL USB 3,3V de 6 pinos, porta de host USB, porta de cliente USB e Flash* NOR de 8 megabytes vêm como padrão na board.
galileo

  • Módulo de Áudio

O MP3 Arduino WTV020-SD é um módulo de gravação de voz com capacidade de armazenamento de 1GB com Cartão SD. É possível carregar arquivos no formato WAV e AD4 que estejam de acordo com a formatação FAT. Suporta 6KHz a 32KHz, sendo 36KHz para arquivos AD4 e 6-16KHz para taxa de amostragem de voz (áudio sampling).
Este Módulo MP3 Arduino pode ser usado em automóveis para alarmes, comando de voz, leitor de música, sensor de estacionamento, navegação GPS, casa inteligente e instrumentos médicos.
O chip WTV020-SD possui modos de controle como o modo MP3, one-to-one (3 vozes com voz de 2), power-loop e second-line, vejam as especificações abaixo.

Modo de Controle MP3:
Funções Play/Stop, Próximo, Volume+, Volume-;
Modo de Controle One-To-One:
A chave correspondente aciona a voz que dispara as 3 vozes e ajusta a subtração do volume. Todos os botões aqui são os padrões.
b1

  • Módulo Bluetooth

Este módulo bluetooth HC-05 oferece uma forma fácil e barata de comunicação com seu projeto arduino. Diferente de outros modelos este suporta tanto o modo mestre como escravo, elém de ter uma fácil configuração.

Em sua placa existe um regulador de tensão e você poderá alimentar com 3.3 a 5V, onde a corrente de consumo é de 35mA quando do dispositivo está pareado e de 8mA quando está conectado. Também temos na placa um led que se o módulo está pareado com outro dispositivo.

O protocolo de comunicação utilizado pelo módulo é o v2.0+EDR utilizando a frequência de 2,4 GHz Banda ISM com modulação GFSK. A velocidade de comunicação Assíncrona é de 2,1Mbps(Max)/160Kbps já a velocidade Síncrona é de 1Mbps/1Mbps ambas com segurança de autenticação e encriptação.
bluetooth

PROGRAMANDO O KINECT
Com o kinect conectado a placa, temos que configurar na propria sdk do kinect o que ele deve fazer, no caso vamos com essa codificação:

//------------------------------------------------------------------------------
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//------------------------------------------------------------------------------

namespace Microsoft.Samples.Kinect.FaceBasics
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Media.Media3D;
    using Microsoft.Kinect;
    using Microsoft.Kinect.Face;
    using System.Timers;
    using System.Threading;
    using System.IO.Ports;
    using System.Windows.Controls;

    ///

    /// Interaction logic for MainWindow
    ///
public partial class MainWindow : Window, INotifyPropertyChanged { ///
/// Espessura das bordas do retângulo e pontos de face /// Thickness of face bounding box and face points ///

private const double DrawFaceShapeThickness = 8; ///
/// Tamanho da fonte do texto da propriedade da face /// Font size of face property text ///

private const double DrawTextFontSize = 30; ///
/// Raio do círculo dos pontos da face /// Radius of face point circle ///

private const double FacePointRadius = 1.0; ///
/// O offset do layout do texto no eixo X. /// Text layout offset in X axis ///

private const float TextLayoutOffsetX = -0.1f; ///
/// O offset do layout do texto no eixo Y. /// Text layout offset in Y axis ///

private const float TextLayoutOffsetY = -0.15f; ///
/// Exibição da rotação da face com incremento do ângulo em graus. /// Face rotation display angle increment in degrees ///

private const double FaceRotationIncrementInDegrees = 5.0; ///
/// Texto formatado para indicar que o corpo/face não foram rastreados. /// Formatted text to indicate that there are no bodies/faces tracked in the FOV ///

private FormattedText textFaceNotTracked = new FormattedText( "No bodies or faces are tracked ...", CultureInfo.GetCultureInfo("en-us"), FlowDirection.LeftToRight, new Typeface("Georgia"), DrawTextFontSize, Brushes.White); ///
/// Layout do texto para a mensagem de face rastreada. /// Text layout for the no face tracked message ///

private Point textLayoutFaceNotTracked = new Point(10.0, 10.0); ///
/// Desenho de parte do corpo para redenrização de saída. /// Drawing group for body rendering output ///

private DrawingGroup drawingGroup; ///
/// Desenho de imagem que nós vamos mostrar /// Drawing image that we will display ///

private DrawingImage imageSource; ///
/// Sensor Kinect ativo /// Active Kinect sensor ///

private KinectSensor kinectSensor = null; ///
/// Coordinate mapper mapeia um tipo de ponto para outro /// Coordinate mapper to map one type of point to another ///

private CoordinateMapper coordinateMapper = null; ///
/// Leitor dos frames do corpo capturados. /// Reader for body frames ///

private BodyFrameReader bodyFrameReader = null; ///
/// Array para armazenar os corpos capturados. /// Array to store bodies ///

private Body[] bodies = null; ///
/// Número de corpos rastreados /// Number of bodies tracked ///

private int bodyCount; ///
/// Face frame sources ///

private FaceFrameSource[] faceFrameSources = null; ///
/// Face frame readers ///

private FaceFrameReader[] faceFrameReaders = null; ///
/// Armazenamento dos resultados do face frame /// Storage for face frame results ///

private FaceFrameResult[] faceFrameResults = null; ///
/// Largura da exibição /// Width of display (color space) ///

private int displayWidth; ///
/// Altura da exibição /// Height of display (color space) ///

private int displayHeight; ///
/// Exibição do retângulo /// Display rectangle ///

private Rect displayRect; ///
/// Lista de brushes para cada face rastreada. /// List of brushes for each face tracked ///

private List faceBrush; ///
/// Exibição do statustext atual. /// Current status text to display ///

private string statusText = null; // Criamos a variável delay´s private static System.Timers.Timer delayHappy; private static System.Timers.Timer delayEngaged; private static System.Timers.Timer delayWearingGlasses; private static System.Timers.Timer delayLeftRightClosed; private static System.Timers.Timer delayMouthOpen; private static System.Timers.Timer delayMouthMoved; private static System.Timers.Timer delayLookingAway; int Happy = 0; int Engaged = 0; int WearingGlasses = 0; int LeftEyeClosed = 0; int RightEyeClosed = 0; int MouthOpen = 0; int MouthMoved = 0; int LookingAway = 0; int FaceYaw = 0; int FacePitch = 0; int FacenRoll = 0; int Resultado; // Aqui inicializamos a porta serial. SerialPort serial = new SerialPort(); ///
/// Inicializa uma nova instância da classe MainWindow. /// Initializes a new instance of the MainWindow class. ///

public MainWindow() { // Criamos os timer´s com um intervalo de 5 segundos. delayHappy = new System.Timers.Timer(5000); delayEngaged = new System.Timers.Timer(5000); delayWearingGlasses = new System.Timers.Timer(5000); delayLeftRightClosed = new System.Timers.Timer(5000); delayMouthOpen = new System.Timers.Timer(5000); delayMouthMoved = new System.Timers.Timer(5000); delayLookingAway = new System.Timers.Timer(5000); // Criamos aqui os manipuladores de evento do timer´s delayHappy.Elapsed += new ElapsedEventHandler(OntimeEvent); delayEngaged.Elapsed += new ElapsedEventHandler(OntimeEngaged); delayWearingGlasses.Elapsed += new ElapsedEventHandler(OntimeWearingGlasses); delayLeftRightClosed.Elapsed += new ElapsedEventHandler(OntimeLeftRightClosed); delayMouthOpen.Elapsed += new ElapsedEventHandler(OntimeMouthOpen); delayMouthMoved.Elapsed += new ElapsedEventHandler(OntimeMouthMoved); delayLookingAway.Elapsed += new ElapsedEventHandler(OntimeLookingAway); // Definimos o intervalo de 2 segundos para os Timer´s(2000 milliseconds). delayHappy.Interval = 2000; delayEngaged.Interval = 3000; delayWearingGlasses.Interval = 2000; delayLeftRightClosed.Interval = 2000; delayMouthOpen.Interval = 2000; delayMouthMoved.Interval = 2000; delayLookingAway.Interval = 2000; // detecção do sensor atual. // one sensor is currently supported this.kinectSensor = KinectSensor.GetDefault(); // Capturar o coordinate mapper // get the coordinate mapper this.coordinateMapper = this.kinectSensor.CoordinateMapper; // Capturar os detalhes do color frame // get the color frame details FrameDescription frameDescription = this.kinectSensor.ColorFrameSource.FrameDescription; // define as características de exibição. // set the display specifics this.displayWidth = frameDescription.Width; this.displayHeight = frameDescription.Height; this.displayRect = new Rect(0.0, 0.0, this.displayWidth, this.displayHeight); // Abre o leitor de frames do corpo. // open the reader for the body frames this.bodyFrameReader = this.kinectSensor.BodyFrameSource.OpenReader(); // O manipulador de eventos de frames do corpo. // wire handler for body frame arrival this.bodyFrameReader.FrameArrived += this.Reader_BodyFrameArrived; // Define o número máximo de corpos que pode ser rastreado pelo kinect. // set the maximum number of bodies that would be tracked by Kinect this.bodyCount = this.kinectSensor.BodyFrameSource.BodyCount; // Alocar espaço para armazenar objectos corporais. // allocate storage to store body objects this.bodies = new Body[this.bodyCount]; // especificar os resultados requiridos dos frames da face // specify the required face frame results FaceFrameFeatures faceFrameFeatures = FaceFrameFeatures.BoundingBoxInColorSpace | FaceFrameFeatures.PointsInColorSpace | FaceFrameFeatures.RotationOrientation | FaceFrameFeatures.FaceEngagement | FaceFrameFeatures.Glasses | FaceFrameFeatures.Happy | FaceFrameFeatures.LeftEyeClosed | FaceFrameFeatures.RightEyeClosed | FaceFrameFeatures.LookingAway | FaceFrameFeatures.MouthMoved | FaceFrameFeatures.MouthOpen; // Cria a fonte do face frame e reader para rastrear cada face no FOV // create a face frame source + reader to track each face in the FOV this.faceFrameSources = new FaceFrameSource[this.bodyCount]; this.faceFrameReaders = new FaceFrameReader[this.bodyCount]; for (int i = 0; i < this.bodyCount; i++) { // Cria a fonte do face frame com as caracterísiticas requiridas do face frame e valor inicial do Id=0 // create the face frame source with the required face frame features and an initial tracking Id of 0 this.faceFrameSources[i] = new FaceFrameSource(this.kinectSensor, 0, faceFrameFeatures); // Abre o reader correspondente // open the corresponding reader this.faceFrameReaders[i] = this.faceFrameSources[i].OpenReader(); } // Aloca espaço para armazenar os resultados do face frame de cada face no FOV. // allocate storage to store face frame results for each face in the FOV this.faceFrameResults = new FaceFrameResult[this.bodyCount]; // Popularizar o resultado da cor da face - uma cor para cada face. // populate face result colors - one for each face index this.faceBrush = new List() { Brushes.White, Brushes.Orange, Brushes.Green, Brushes.Red, Brushes.LightBlue, Brushes.Yellow }; // Define o evento notificador IsAvailableChanged // set IsAvailableChanged event notifier this.kinectSensor.IsAvailableChanged += this.Sensor_IsAvailableChanged; // Abre o sensor // open the sensor this.kinectSensor.Open(); // Define o status text // set the status text this.StatusText = this.kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText : Properties.Resources.NoSensorStatusText; // Cria o desenho de grupo onde iremos desenhar // Create the drawing group we'll use for drawing this.drawingGroup = new DrawingGroup(); // Cria uma fonte de imagem que podemos usar em nosso controle de imagem. // Create an image source that we can use in our image control this.imageSource = new DrawingImage(this.drawingGroup); // usar o objeto janela como o modelo de exibição neste exemplo simples // use the window object as the view model in this simple example this.DataContext = this; // Inicializa os componentes (controles) da janela. // initialize the components (controls) of the window this.InitializeComponent(); chamaPorta(); } private void OntimeLookingAway(object sender, ElapsedEventArgs e) { LookingAway = 0; // Verificamos se a porta está aberta if (serial.IsOpen == true) // Envia o texto presente no textbox serial.Write("l"); } private void OntimeMouthMoved(object sender, ElapsedEventArgs e) { MouthMoved = 0; // Verificamos se a porta está aberta if (serial.IsOpen == true) // Envia o texto presente no textbox serial.Write("m"); } private void OntimeMouthOpen(object sender, ElapsedEventArgs e) { MouthOpen = 0; // Verificamos se a porta está aberta if (serial.IsOpen == true) // Envia o texto presente no textbox serial.Write("M"); } private void OntimeLeftRightClosed(object sender, ElapsedEventArgs e) { LeftEyeClosed = 0; // Verificamos se a porta está aberta if (serial.IsOpen == true) // Envia o texto presente no textbox serial.Write("O\n"); } private void OntimeWearingGlasses(object sender, ElapsedEventArgs e) { WearingGlasses = 0; // Verificamos se a porta está aberta if (serial.IsOpen == true) // Envia o texto presente no textbox serial.Write("W\n"); } private void OntimeEngaged(object sender, ElapsedEventArgs e) { delayEngaged.Enabled = false; Thread.Sleep(1000); Debug.WriteLine(Thread.CurrentThread.ManagedThreadId); // Verificamos se a porta está aberta if (serial.IsOpen == true) // Envia o texto presente no textbox serial.Write("E\n"); } private void OntimeEvent(object sender, ElapsedEventArgs e) { delayHappy.Enabled = false; Thread.Sleep(1000); Debug.WriteLine(Thread.CurrentThread.ManagedThreadId); Happy = 0; // Verificamos se a porta está aberta if (serial.IsOpen == true) // Envia o texto presente no textbox serial.Write("H\n"); } ///
/// O evento INotifyPropertyChangedPropertyChanged permite que controles da janela se ligue a dados mutáveis /// INotifyPropertyChangedPropertyChanged event to allow window controls to bind to changeable data ///

public event PropertyChangedEventHandler PropertyChanged; ///
/// Obtém o bitmap para exibição /// Gets the bitmap to display ///

public ImageSource ImageSource { get { return this.imageSource; } } ///
/// Obtém ou define o status text corrente para exibição. /// Gets or sets the current status text to display ///

public string StatusText { get { return this.statusText; } set { if (this.statusText != value) { this.statusText = value; // Notificar quaisquer elementos que o texto foi alterado // notify any bound elements that the text has changed if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs("StatusText")); } } } } ///
/// Converte a rotação dos 4 elementos para ângulos de Euler /// em seguida os mapeia para um range específico de valores para controlar a taxa de atualização. /// Converts rotation quaternion to Euler angles /// And then maps them to a specified range of values to control the refresh rate ///

/// face rotation quaternion /// rotation about the X-axis /// rotation about the Y-axis /// rotation about the Z-axis private static void ExtractFaceRotationInDegrees(Vector4 rotQuaternion, out int pitch, out int yaw, out int roll) { double x = rotQuaternion.X; double y = rotQuaternion.Y; double z = rotQuaternion.Z; double w = rotQuaternion.W; // Converte a rotação dos 4 elementos para ângulos de Euler em graus. // convert face rotation quaternion to Euler angles in degrees double yawD, pitchD, rollD; pitchD = Math.Atan2(2 * ((y * z) + (w * x)), (w * w) - (x * x) - (y * y) + (z * z)) / Math.PI * 180.0; yawD = Math.Asin(2 * ((w * y) - (x * z))) / Math.PI * 180.0; rollD = Math.Atan2(2 * ((x * y) + (w * z)), (w * w) + (x * x) - (y * y) - (z * z)) / Math.PI * 180.0; // fixar os valores para um múltiplo do incremento especificado para controlar a taxa de atualização // clamp the values to a multiple of the specified increment to control the refresh rate double increment = FaceRotationIncrementInDegrees; pitch = (int)(Math.Floor((pitchD + ((increment / 2.0) * (pitchD > 0 ? 1.0 : -1.0))) / increment) * increment); yaw = (int)(Math.Floor((yawD + ((increment / 2.0) * (yawD > 0 ? 1.0 : -1.0))) / increment) * increment); roll = (int)(Math.Floor((rollD + ((increment / 2.0) * (rollD > 0 ? 1.0 : -1.0))) / increment) * increment); } ///
/// Executa as tarefas start up /// Execute start up tasks ///

/// object sending the event /// event arguments private void MainWindow_Loaded(object sender, RoutedEventArgs e) { for (int i = 0; i < this.bodyCount; i++) { if (this.faceFrameReaders[i] != null) { // Manipulador de evento do face frame. // wire handler for face frame arrival this.faceFrameReaders[i].FrameArrived += this.Reader_FaceFrameArrived; } } if (this.bodyFrameReader != null) { // Manipulador de evento do body frame. // wire handler for body frame arrival this.bodyFrameReader.FrameArrived += this.Reader_BodyFrameArrived; } } ///
/// Executa as tarefas shutdown /// Execute shutdown tasks ///

/// object sending the event /// event arguments private void MainWindow_Closing(object sender, CancelEventArgs e) { for (int i = 0; i < this.bodyCount; i++) { if (this.faceFrameReaders[i] != null) { // FaceFrameReader é descartado // FaceFrameReader is IDisposable this.faceFrameReaders[i].Dispose(); this.faceFrameReaders[i] = null; } if (this.faceFrameSources[i] != null) { // FaceFrameSource é descartado // FaceFrameSource is IDisposable this.faceFrameSources[i].Dispose(); this.faceFrameSources[i] = null; } } if (this.bodyFrameReader != null) { // BodyFrameReader é descartado // BodyFrameReader is IDisposable this.bodyFrameReader.Dispose(); this.bodyFrameReader = null; } if (this.kinectSensor != null) { this.kinectSensor.Close(); this.kinectSensor = null; } } ///
/// Manipulador dos dados do face frame que chegam a partir do sensor /// Handles the face frame data arriving from the sensor ///

/// object sending the event /// event arguments private void Reader_FaceFrameArrived(object sender, FaceFrameArrivedEventArgs e) { using (FaceFrame faceFrame = e.FrameReference.AcquireFrame()) { if (faceFrame != null) { // Obtém o índice do face source do array face source. // get the index of the face source from the face source array int index = this.GetFaceSourceIndex(faceFrame.FaceFrameSource); // Checa se este face frame tem resultados válidos // check if this face frame has valid face frame results if (this.ValidateFaceBoxAndPoints(faceFrame.FaceFrameResult)) { // Armazena o resultado do face frame para usar depois. // store this face frame result to draw later this.faceFrameResults[index] = faceFrame.FaceFrameResult; } else { // indica que o resultado mais recente do face frame a partir deste leitor é inválido // indicates that the latest face frame result from this reader is invalid this.faceFrameResults[index] = null; } } } } ///
/// Retorna o índice do face frame source. /// Returns the index of the face frame source ///

/// the face frame source /// the index of the face source in the face source array private int GetFaceSourceIndex(FaceFrameSource faceFrameSource) { int index = -1; for (int i = 0; i < this.bodyCount; i++) { if (this.faceFrameSources[i] == faceFrameSource) { index = i; break; } } return index; } ///
/// Manipulador dos dados do body frame que chega a partir do sensor /// Handles the body frame data arriving from the sensor ///

/// object sending the event /// event arguments private void Reader_BodyFrameArrived(object sender, BodyFrameArrivedEventArgs e) { using (var bodyFrame = e.FrameReference.AcquireFrame()) { if (bodyFrame != null) { // Atualiza os dados do corpo // update body data bodyFrame.GetAndRefreshBodyData(this.bodies); using (DrawingContext dc = this.drawingGroup.Open()) { // Define o background dark // draw the dark background dc.DrawRectangle(Brushes.Black, null, this.displayRect); bool drawFaceResult = false; // Interação através de cada face source. // iterate through each face source for (int i = 0; i < this.bodyCount; i++) { // checa se o face rastreado no face source é válido // check if a valid face is tracked in this face source if (this.faceFrameSources[i].IsTrackingIdValid) { // Checa se temos resultados válidos do face frame // check if we have valid face frame results if (this.faceFrameResults[i] != null) { // extrair o resultado do face frame // draw face frame results this.DrawFaceFrameResults(i, this.faceFrameResults[i], dc); if (!drawFaceResult) { drawFaceResult = true; } } } else { // Checa se o body correspondente foi rastreado // check if the corresponding body is tracked if (this.bodies[i].IsTracked) { // Atualizar a fonte do face frame para acompanhar este corpo // update the face frame source to track this body this.faceFrameSources[i].TrackingId = this.bodies[i].TrackingId; } } } if (!drawFaceResult) { // Se não foi detectado nenhum rosto então isso indica uma das seguintes opções: // if no faces were drawn then this indicates one of the following: // // Nenhum corpo foi rastreado // a body was not tracked // // Um corpo foi rastreado mas o rosto correspondente não foi rastreado // a body was tracked but the corresponding face was not tracked // // Um corpo e um rosto correspondente foram rastreados embora a caixa ou os pontos da face não eram válidos // a body and the corresponding face was tracked though the face box or the face points were not valid dc.DrawText( this.textFaceNotTracked, this.textLayoutFaceNotTracked); } this.drawingGroup.ClipGeometry = new RectangleGeometry(this.displayRect); } } } } ///
/// Extrair os resultados do face frame /// Draws face frame results ///

/// the index of the face frame corresponding to a specific body in the FOV /// container of all face frame results /// drawing context to render to private void DrawFaceFrameResults(int faceIndex, FaceFrameResult faceResult, DrawingContext drawingContext) { // Escolha o brush baseado no índice da face. // choose the brush based on the face index Brush drawingBrush = this.faceBrush[0]; if (faceIndex < this.bodyCount) { drawingBrush = this.faceBrush[faceIndex]; } Pen drawingPen = new Pen(drawingBrush, DrawFaceShapeThickness); // desenha o retângulo da face // draw the face bounding box var faceBoxSource = faceResult.FaceBoundingBoxInColorSpace; Rect faceBox = new Rect(faceBoxSource.Left, faceBoxSource.Top, faceBoxSource.Right - faceBoxSource.Left, faceBoxSource.Bottom - faceBoxSource.Top); drawingContext.DrawRectangle(null, drawingPen, faceBox); if (faceResult.FacePointsInColorSpace != null) { // desenha cada ponto da face. // draw each face point foreach (PointF pointF in faceResult.FacePointsInColorSpace.Values) { drawingContext.DrawEllipse(null, drawingPen, new Point(pointF.X, pointF.Y), FacePointRadius, FacePointRadius); } } string faceText = string.Empty; // extrair as informações de cada propriedade da face e armazená-las em faceText // extract each face property information and store it in faceText if (faceResult.FaceProperties != null) { foreach (var item in faceResult.FaceProperties) { faceText += item.Key.ToString() + " : "; // Considerar um "talvez" como um "não" para restringir // a taxa de atualização do resultado de detecção // consider a "maybe" as a "no" to restrict // the detection result refresh rate if (item.Value == DetectionResult.Maybe) { faceText += DetectionResult.No + "\n"; } else { faceText += item.Value.ToString() + "\n"; // Aqui recuperamos cada valor das expressões faciais switch(item.Key.ToString()){ case "Happy": txtFeliz.Text = item.Value.ToString(); if (txtFeliz.Text == "Yes") { delayHappy.Enabled = true; Happy = 1; } else { delayHappy.Enabled = false; } break; case "Engaged": txtFocado.Text = item.Value.ToString(); if (txtFocado.Text == "No") { delayEngaged.Enabled = true; delayHappy.Enabled = false; } else { delayEngaged.Enabled = false; } break; case "WearingGlasses": txtOculos.Text = item.Value.ToString(); if (txtOculos.Text == "No") { delayWearingGlasses.Enabled = true; WearingGlasses = 1; } else { delayWearingGlasses.Enabled = false; WearingGlasses = 0; } break; case "LeftEyeClosed": txtOlhoEsquerdo.Text = item.Value.ToString(); if (txtOlhoEsquerdo.Text == "Yes") { delayLeftRightClosed.Enabled = true; LeftEyeClosed = 1; } else { delayLeftRightClosed.Enabled = false; LeftEyeClosed = 0; } break; case "RightEyeClosed": txtOlhoDireito.Text = item.Value.ToString(); if (txtOlhoDireito.Text == "Yes") { delayLeftRightClosed.Enabled = true; RightEyeClosed = 1; } else { delayLeftRightClosed.Enabled = false; RightEyeClosed = 0; } break; //case "MouthOpen": // txtBocaAberta.Text = item.Value.ToString(); // if (txtBocaAberta.Text == "Yes" && Happy==0) // { // delayMouthOpen.Enabled = true; // delayHappy.Enabled = false; // MouthOpen = 1; // } // else // { // delayMouthOpen.Enabled = false; // Happy = 0; // } // break; //case "MouthMoved": // txtBocaMov.Text = item.Value.ToString(); // if (txtBocaMov.Text == "Yes") // { // delayMouthMoved.Enabled = true; // delayHappy.Enabled = false; // delayMouthOpen.Enabled = false; // MouthMoved = 1; // } // else // { // delayMouthMoved.Enabled = false; // delayHappy.Enabled = true; // delayMouthOpen.Enabled = true; // MouthMoved = 0; // } // break; //case "LookingAway": // txtOlhoHoz.Text = item.Value.ToString(); // if (txtOlhoHoz.Text == "Yes") // { // delayLookingAway.Enabled = true; // LookingAway = 1; // } // else // { // delayLookingAway.Enabled = false; // LookingAway = 0; // } // break; } //Resultado = Happy + Engaged + WearingGlasses + LeftEyeClosed + RightEyeClosed + MouthOpen + MouthMoved + LookingAway; //if (Resultado == 1 || Resultado == 2 || Resultado == 3 || Resultado == 4 || Resultado == 5 || Resultado == 6 || Resultado == 7 || Resultado == 8) //{ // delay.Enabled = true; //} //else //{ // delay.Enabled = false; // Resultado = 0; //} } } } // Extrair a rotação da face em graus como ângulos de Euler // extract face rotation in degrees as Euler angles if (faceResult.FaceRotationQuaternion != null) { int pitch, yaw, roll; ExtractFaceRotationInDegrees(faceResult.FaceRotationQuaternion, out pitch, out yaw, out roll); faceText += "FaceYaw : " + yaw + "\n" + "FacePitch : " + pitch + "\n" + "FacenRoll : " + roll + "\n"; //int FaceYaw = 0; //int FacePitch = 0; //int FacenRoll = 0; // Aqui recuperamos cada valor do movimento da cabeça txtForaVia.Text = yaw.ToString(); txtPitch.Text = pitch.ToString(); txtRoll.Text = roll.ToString(); } // processar a propriedade e a informação da rotação da face // render the face property and face rotation information Point faceTextLayout; if (this.GetFaceTextPositionInColorSpace(faceIndex, out faceTextLayout)) { drawingContext.DrawText( new FormattedText( faceText, CultureInfo.GetCultureInfo("en-us"), FlowDirection.LeftToRight, new Typeface("Georgia"), DrawTextFontSize, drawingBrush), faceTextLayout); } } ///
/// Computa o resultado textual da posição da face e adiciona um offset para o correspondente /// body´s head joint no espaço da câmera e em seguida projeta no espaço da tela. /// /// Computes the face result text position by adding an offset to the corresponding /// body's head joint in camera space and then by projecting it to screen space ///

/// the index of the face frame corresponding to a specific body in the FOV /// the text layout position in screen space /// success or failure private bool GetFaceTextPositionInColorSpace(int faceIndex, out Point faceTextLayout) { faceTextLayout = new Point(); bool isLayoutValid = false; Body body = this.bodies[faceIndex]; if (body.IsTracked) { var headJoint = body.Joints[JointType.Head].Position; CameraSpacePoint textPoint = new CameraSpacePoint() { X = headJoint.X + TextLayoutOffsetX, Y = headJoint.Y + TextLayoutOffsetY, Z = headJoint.Z }; ColorSpacePoint textPointInColor = this.coordinateMapper.MapCameraPointToColorSpace(textPoint); faceTextLayout.X = textPointInColor.X; faceTextLayout.Y = textPointInColor.Y; isLayoutValid = true; } return isLayoutValid; } ///
/// Valida a face dentro do retângulo delimitador e os pontos da face para estar dentro do espaço da tela /// Validates face bounding box and face points to be within screen space ///

/// the face frame result containing face box and points /// success or failure private bool ValidateFaceBoxAndPoints(FaceFrameResult faceResult) { bool isFaceValid = faceResult != null; if (isFaceValid) { var faceBox = faceResult.FaceBoundingBoxInColorSpace; if (faceBox != null) { // Checa se temos um retângulo válido dentro dos limites do espaço da tela // check if we have a valid rectangle within the bounds of the screen space isFaceValid = (faceBox.Right - faceBox.Left) > 0 && (faceBox.Bottom - faceBox.Top) > 0 && faceBox.Right <= this.displayWidth && faceBox.Bottom 0.0f && pointF.Y > 0.0f && pointF.X < this.displayWidth && pointF.Y < this.displayHeight; if (!isFacePointValid) { isFaceValid = false; break; } } } } } } return isFaceValid; } ///
/// Manipulador de eventos quando o sensor fica indisponível (Ex fez uma pausa, fechado, desligado). /// Handles the event which the sensor becomes unavailable (E.g. paused, closed, unplugged). ///

/// object sending the event /// event arguments private void Sensor_IsAvailableChanged(object sender, IsAvailableChangedEventArgs e) { if (this.kinectSensor != null) { // on failure, set the status text this.StatusText = this.kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText : Properties.Resources.SensorNotAvailableStatusText; } } // Aqui neste método chamamos a porta serial private void chamaPorta() { foreach (string s in SerialPort.GetPortNames()) { ComboSerial.Items.Add(s); } Botoes botao = new Botoes("Conectar"); Conecta.DataContext = botao; Conecta.IsEnabled = false; } private void ComboSerial_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (ComboSerial.SelectedIndex != -1) { // Aqui definimos a porta que será usada para a comunicação serial com o arduino. // recuperamos a informação de qual porta será utilizada do comboBox através do // item selecionado. serial.PortName = ComboSerial.SelectedItem.ToString(); Conecta.IsEnabled = true; } } private void Conectar_Click(object sender, RoutedEventArgs e) { if (serial.IsOpen == false) { try { serial.Open(); } catch { return; } if (serial.IsOpen) { // Aqui desabilitamos o combo e escrevemos "Desconectar" no Content do botão ComboSerial.IsEnabled = false; Botoes botao = new Botoes("Desconectar"); Conecta.DataContext = botao; } } else { try { // Aqui fechamos a conexão com a serial, habilitamos o combo e escrevemos "Conectar" no Content do botão. serial.Close(); ComboSerial.IsEnabled = true; Botoes botao = new Botoes("Conectar"); Conecta.DataContext = botao; } catch { return; } } } // Através desta classe definimos o texto que irá aparecer no botão conectar, usando um binding // para o exibir o texto do botão no XAML. public class Botoes { public Botoes(string status) { this.statusBotao = status; } public string statusBotao { get; set; } } } }

PROGRAMANDO O ARDUINO
Com o código acima, temos o kinect configurado para monitorar as expressoes faciais do condutor. Agora temos q configurar o arduino para fazer a emissao sonora quando o kinect estiver em funcionamento. Assim segue:

/*
 
 O código abaixo refere-se ao projeto WakeUp que tem como objetivo monitorar as expressões faciais de um indivíduo através de um sensor
 de captura movimento. Aqui apresentamos a implementação do código que cuida da parte do projeto em que todas as vezes que um determinado
 movimento for capturado pelo sensor o arduino será notificado através da porta serial e emitirá uma mensagem de alerta ou uma orientação
 para o indivíduo. Neste projeto também utilizaremos o módulo WTV020-SD-16P para reprodução de mensagens através do Arduino.
   
 */

// Carrega a biblioteca SoftwareSerial
#include 

// Carrega a biblioteca Wtv020sd16p para interação com a placa de aúdio. 
#include 

int resetPin = 2;  // Pino de reset.
int clockPin = 3;  // Pino de clock.
int dataPin = 4;   // Pino data.
int busyPin = 5;   // Pino busy.

/*
Cria uma instância de classe do Wtv020sd16p.
 1st parâmetro: pino do Reset.
 2nd parâmetro: pino do Clock.
 3rd parâmetro: pino Data.
 4th parâmetro: pino Busy.
 */
 
//Define os pinos para a serial   
SoftwareSerial mySerial(10, 11);  // RX, TX  

Wtv020sd16p wtv020sd16p(resetPin,clockPin,dataPin,busyPin);

String inputString = "";          // Uma seqüência de caracteres para armazenar dados de entrada
char buf;                         //Armazena o caracter recebido
boolean stringComplete = false;   // Verifica se a cadeia está completa
int qtEntrada=0;

void setup() {
  
 // Inicia a porta serial para comunicação pela porta USB 
 Serial.begin(9600);             // inicializa a porta serial:
 inputString.reserve(200);       // reserva 200 bytes para a variável inputString:
 
  // Inicia a serial configurada nas portas 10 e 11 para comunicações com a placa do BlueTooth
  mySerial.begin(9600);
  
 wtv020sd16p.reset();            // Aqui inicializamos a placa de áudio
 wtv020sd16p.unmute();           //
  
  // inicializa o pino digital 13 como output.
  pinMode(13, OUTPUT);
}

void loop() {
  
   // Neste loop monitoramos a porta de comunicação com o bluetooth
   while(mySerial.available()>0)
   {
      buf = mySerial.read();
      
      // Caso seja recebido o caracter L, acende o led
      // Com o flag "buf" carregado com o valor "L" o sistema reconhecerá o 
      // veículo automotivo está em movimento, caso o valor seja "D" o
      // sistema reconhecerá que o veículo está parado. 
      digitalWrite(13, HIGH);
      //Caso seja recebido o caracter L, acende o led
      if (buf == 'L')
      {
         Serial.println(buf);
         digitalWrite(13, HIGH);
      }
        //Caso seja recebido o caracter D, apaga o led
      if (buf == 'D')
      {
         Serial.println(buf);
         digitalWrite(13, LOW);
      }
   }
   
 
  // Aqui verificamos se o valor de stringComplete é igual true, em caso positivo
  // as instruções dentro do if serão executadas.
  if (stringComplete) {
    
    // imprimir a seqüência de caracteres quando uma nova linha chega:
    Serial.println(inputString);
    
    // Aqui verificamos o valor da variável inputString e dependendo do seu valor
    // determinado junto de instruções dentro dos if's serão executadas. 
    if(inputString=="H\n"){
       
          // Este bloco de instruções será executado caso o valor de inputString seja igual a "H"
          // valor este que será enviado pelo software de interação com o kinect e que a 
          // corresponde a detecção da expressão facial "Feliz" capturada pelo kinect.
          
          digitalWrite(13, HIGH);       // acende o LED 
          delay(1000);                  // aguarda 1s
          digitalWrite(13, LOW);        // apaga o LED
          delay(1000);                  // aguarda 1s
          
          wtv020sd16p.playVoice(1);     // Aciona a reproduçãodo áudio com uma mensagem de alerta 
          wtv020sd16p.stopVoice();      // Encerra a reprodução do áudio.
          
    }else if(inputString=="E\n"){
          
          // Este bloco de instruções será executado caso o valor de inputString seja igual a "E"
          // valor este que será enviado pelo software de interação com o kinect e que a 
          // corresponde a detecção da expressão facial "Focado" capturada pelo kinect.
          
          digitalWrite(13, HIGH);       // acende o LED 
          delay(1000);                  // aguarda 1s
          digitalWrite(13, LOW);        // apaga o LED
          delay(1000);                  // aguarda 1s
          
          wtv020sd16p.playVoice(2);     // Aciona a reproduçãodo áudio com uma mensagem de alerta 
          wtv020sd16p.stopVoice();      // Encerra a reprodução do áudio.
          
    }else if(inputString=="W\n"){
          
          // Este bloco de instruções será executado caso o valor de inputString seja igual a "W"
          // valor este que será enviado pelo software de interação com o kinect e que a 
          // corresponde a detecção da expressão facial "Sem Óculos" capturada pelo kinect.
          
          digitalWrite(13, HIGH);       // acende o LED 
          delay(1000);                  // aguarda 1s
          digitalWrite(13, LOW);        // apaga o LED
          delay(1000);                  // aguarda 1s
          
          wtv020sd16p.playVoice(3);     // Aciona a reproduçãodo áudio com uma mensagem de alerta 
          wtv020sd16p.stopVoice();      // Encerra a reprodução do áudio.
          
    }else if(inputString=="O\n"){
          
          // Este bloco de instruções será executado caso o valor de inputString seja igual a "O"
          // valor este que será enviado pelo software de interação com o kinect e que a 
          // corresponde a detecção da expressão facial "Olhos Fechados" capturada pelo kinect.
          
          digitalWrite(13, HIGH);       // acende o LED 
          delay(1000);                  // aguarda 1s
          digitalWrite(13, LOW);        // apaga o LED
          delay(1000);                  // aguarda 1s
          
          wtv020sd16p.playVoice(6);     // Aciona a reproduçãodo áudio com uma mensagem de alerta 
          wtv020sd16p.stopVoice();      // Encerra a reprodução do áudio.
    }
    
    inputString = "";
    stringComplete = false;
  }
}

/*
  SerialEvent ocorre sempre que novos dados chegam da
  porta serial. Esta rotina é executada cada vez que o
  loop() é executado, portanto, usando um atraso dentro 
  do loop pode atrasar a resposta. Vários bytes de dados 
  podem estar disponíveis.
  
 */
void serialEvent() {
  while (Serial.available()) {
    
        char inChar = (char)Serial.read();        // Captura um novo byte:
        inputString += inChar;                    // adiciona a inputString:
    
        // Se na entrada tiver o caracter de nova linha, o flag é setado para "true"
        // então as instruções dentro do loop principal poderam ser executadas
        if (inChar == '\n') {
            stringComplete = true;
        }
  }
}

PROGRAMANDO O ARDROID
Com o código abaixo, temos um aplicativo android que se conecta ao arduino para enviar a informação se o veículo está em movimento ou parado habilitando ou desabilitando a função do arduino de emitir os avisos sonoros ao condutor no momento em que o veículo está parado. Assim segue:

 import java.io.IOException;
        import java.io.InputStream;
        import java.io.OutputStream;
        import java.util.UUID;
        import java.lang.Math;
        import java.text.DecimalFormat;
        import android.app.Activity;
        import android.bluetooth.BluetoothAdapter;
        import android.bluetooth.BluetoothDevice;
        import android.bluetooth.BluetoothSocket;
        import android.content.Context;
        import android.content.Intent;
        import android.os.Bundle;
        import android.os.Handler;
        import android.util.Log;
        import android.view.View;
        import android.widget.Button;
        import android.widget.TextView;
        import android.widget.Toast;
        import android.location.Location;
        import android.location.LocationListener;
        import android.location.LocationManager;

        public class MainActivity extends Activity  implements LocationListener{

 private static final int REQUEST_ENABLE_BT = 1;
 private static final int REQUEST_PAIRED_DEVICE = 2;
 private static final double PI = 3.1415926535;
 private static double D2 = 0.0;   // latitude inicial
 private static double D3;   // latitude final
 private static double E2 = 0.0;   // longitude inicial
 private static double E3;   // longitude final
 private static double distancia;  // Distância atingida pelo dispositivo
 
 Button btnListPairedDevices;
 Button Conectar;
 Button Clear;
 TextView stateBluetooth;
 BluetoothAdapter bluetoothAdapter;
 
 private static final String TAG = "JFernando";           //Tag para o log d do android     
 private BluetoothSocket btSocket = null;      
 private OutputStream outStream = null;         
 private static String address = "";  //endereco de conexao BT a ser pareado do arduino            
 private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
 private InputStream inStream = null;     //inputStream para armazenar as entradas           
 Handler handler = new Handler();         //Thread do Android       
 byte delimiter = 10;                     //delimitador fr Bits a serem enviados 
 boolean stopWorker = false;              //ponteiro para leitura do Buffer      
 int readBufferPosition = 0;            
 byte[] readBuffer = new byte[1024];      //Buffer de Bits                    
 
 boolean conetado =false;                 //boolean para conexão 
 String dadoEnviarSintetizador = "";      //Variavel que armazena o dado a ser enviado                   
 String dadoSintetizado = "";             //variavel que armazena o dado apos o tratamento (validação)
 
 private LocationManager locationManager;
 private Location localizacao;
 private boolean allowNetwork;
 private DecimalFormat lat;
 private DecimalFormat log;
 private DecimalFormat dis;
 private String latitude;
 private String longitude;
 private String enviaDado = "";           
 private boolean ModoTeste = false;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 btnListPairedDevices = (Button)findViewById(R.id.listpaireddevices);
 Conectar = (Button)findViewById(R.id.btnConectar);
 Clear = (Button)findViewById(R.id.btnClear);
 
 stateBluetooth = (TextView)findViewById(R.id.bluetoothstate);
 bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
 
 CheckBluetoothState();
 Conectar.setEnabled(false);
 
 btnListPairedDevices.setOnClickListener(btnListPairedDevicesOnClickListener);
 Conectar.setOnClickListener(btnConectarOnClickListener);
 Clear.setOnClickListener(btnClearOnClickListener);
 }
 
 @Override
 protected void onResume(){
 super.onResume();
 allowNetwork=true;
 
 locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
 // Aqui verificamos se o Gps está ativo, caso não esteja será solicitado ao
         // usuário que o ative.
 if(!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
 Intent it = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
 startActivity(it);
 }else{
 // Aqui recuperamos a informação das coordenadas geográficas do NETWORK.
     localizacao =   locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
     // Aqui recuperamos a informação das coordenadas geográficas do GPS.
     localizacao =   locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
 }
 
 if (localizacao != null)
        {
    lat = new DecimalFormat("#,#####0.00000");  
    log = new DecimalFormat("#,#####0.00000");  
    dis = new DecimalFormat("#,#####0.00000");  
    
    latitude = lat.format(localizacao.getLatitude());
    longitude = log.format(localizacao.getLongitude());
    latitude = latitude.replace(",", ".");
    longitude = longitude.replace(",", ".");
    
            Toast.makeText(getBaseContext(),"lat: " + latitude + " Lon: " + longitude, Toast.LENGTH_SHORT).show();
        
            Log.d("latitude inicial",String.valueOf(D2));
            Log.d("longitude inicial",String.valueOf(E2));
      }
 locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 0, this);
 }
 
 @Override
 protected void onPause(){
 super.onPause();
 locationManager.removeUpdates(this);
 }
 
 // Aqui neste método verificamos se o bluetooth está ativado
 // caso não esteja será exibida uma mensagem solicitando que o bluetooth seja ligado.
 private void CheckBluetoothState(){
 
 if (bluetoothAdapter == null){
       stateBluetooth.setText("Bluetooth NOT support");
 }
 else {
   if (bluetoothAdapter.isEnabled()){
       if(bluetoothAdapter.isDiscovering()){
           stateBluetooth.setText("Bluetooth is currently in device discovery process.");
      }
      else {
           stateBluetooth.setText("Bluetooth is Enabled.");
           btnListPairedDevices.setEnabled(true);
      }
   }
   else {
       stateBluetooth.setText("Bluetooth is NOT Enabled!");
       Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
       startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
   }
 }
 }
 private Button.OnClickListener btnListPairedDevicesOnClickListener
   = new Button.OnClickListener(){
          @Override
          public void onClick(View arg0) {
          Intent intent = new Intent();
          intent.setClass(MainActivity.this, DeviceActivity.class);
          startActivityForResult(intent, REQUEST_PAIRED_DEVICE);
 }};

 private Button.OnClickListener btnConectarOnClickListener
   = new Button.OnClickListener(){
 @Override
 public void onClick(View v) {
 conetado = Connect();
 if(conetado){
 Toast.makeText(getBaseContext(),"Dispositivo Conectado", Toast.LENGTH_SHORT).show();
 }
 }
 };
 
 private Button.OnClickListener btnClearOnClickListener
   = new Button.OnClickListener(){
 @Override
 public void onClick(View v) { 
 if(ModoTeste==false){
 validaDados("Ligar");                //envia para o metodo de validação antes de enviar para o proximo dispositivo                    
 writeData(dadoEnviarSintetizador);      //envia o dado para o dispositivo Client  
 ModoTeste=true;
 Toast.makeText(getBaseContext(),"Veículo em Movimento",Toast.LENGTH_SHORT).show();
 }else{
 validaDados("Desligar");                //envia para o metodo de validação antes de enviar para o proximo dispositivo                    
 writeData(dadoEnviarSintetizador);      //envia o dado para o dispositivo Client  
 ModoTeste=false;
 Toast.makeText(getBaseContext(),"Veículo parado",Toast.LENGTH_SHORT).show();
 } 
 }
 };

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
     if(requestCode == REQUEST_ENABLE_BT){
         CheckBluetoothState();
     }
     if (requestCode == REQUEST_PAIRED_DEVICE){
         if(resultCode == RESULT_OK){ 
                // aqui recuperamos o valor do MAC do dispositivo que queremos parear 
       address = data.getExtras().getString(DeviceActivity.EXTRA_DEVICE_ADDRESS);
      // Aqui habilitamos o botão conectar
      Conectar.setEnabled(true);
      }
   }
 } 
 
 //Aqui conectamos o smartphone com o dispositivo
        public boolean Connect() {
              try{  
                     Log.d(TAG, address);
                     //cancela a busca apos armazenar no BluetoothDevice
                     bluetoothAdapter.cancelDiscovery();
            
            //pega o adress do bluetooth para iniciar a pariedade
            BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
            Log.d(TAG, "Connecting to … " + device);
            try{
                //envia para o Socket a ID do dispositivo local
                btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
                //requisita a conexão
                btSocket.connect();
                Log.d(TAG, "Conexão Realizada!.");
                    
                //chama o metodo que inicia a transferencia dos dados
                beginListenForData();
            
            }catch (IOException e) {
                try{
                   //fecha o socket caso ocorra algum erro
                   btSocket.close();
                   Log.d(TAG, "Conexão Não Realizada!.");
                   return false;
                } catch (IOException e2) {
                   Log.d(TAG, "Unable to end the connection");
                   return false;
                }
            }
            return true;
            
         }catch (Exception e){
          Toast.makeText(getBaseContext(),"Erro na Conexão", Toast.LENGTH_SHORT).show();
             return false;
         }
    }
    
       // inicia a transferencia dos dados
  public void beginListenForData(){
          try{
              inStream = btSocket.getInputStream();
          }catch (IOException e){
          }

          Thread workerThread = new Thread(new Runnable()
          {
             public void run()
             {                
                while(!Thread.currentThread().isInterrupted() && !stopWorker)
                {
                   try{
                      int bytesAvailable = inStream.available();                        
                      if(bytesAvailable > 0)
                      {
                          byte[] packetBytes = new byte[bytesAvailable];
                          inStream.read(packetBytes);
                          
                          for(int i=0;i<bytesAvailable;i++)
                          {
                              byte b = packetBytes[i];
                              if(b == delimiter)
                              {
                                 byte[] encodedBytes = new byte[readBufferPosition];
                                 System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
                                 final String data = new String(encodedBytes, "US-ASCII");
                                 readBufferPosition = 0;
                                 handler.post(new Runnable()
                                 {
                                     public void run(){
      
                                     }
                                 });
                              }
                              else
                              {
                                 readBuffer[readBufferPosition++] = b;
                              }
                          }
                      }
                   }
                   catch (IOException ex)
                   {
                      stopWorker = true;
                   }
                }
             }
          });
    }
  
  
  //Aqui tratamos os dados para posteriormente enviar para o dispositivo (arduino)
        public void validaDados(String dadoBruto){
        
                  if(dadoBruto.equalsIgnoreCase("Ligar")){
                            dadoEnviarSintetizador ="L";
                  }else if(dadoBruto.equalsIgnoreCase("Desligar")){ 
                           dadoEnviarSintetizador ="D";
                  }        
       }
  
       //Aqui enviamos os dados para o Blutooth 
       private void writeData(String data) {
              try{
                     outStream = btSocket.getOutputStream();
             }catch (IOException e){
                     Log.d(TAG, "Bug BEFORE Sending stuff", e);
            }
            try{         
                    String message = data;
                    byte[] msgBuffer = message.getBytes();
                    outStream.write(msgBuffer);
                    Log.d("jfERNANDO","Dado Enviado");
            }catch (IOException e) {
                    Log.d(TAG, "Bug while sending stuff", e);
            }
       }

 @Override
 public void onLocationChanged(Location location) { 
 if(location.getProvider().equals(LocationManager.GPS_PROVIDER)){
 allowNetwork=false;
 }
 if(location.getProvider().equals(LocationManager.GPS_PROVIDER)){
 if(ModoTeste==true){
 locationManager.removeUpdates(this);
 }
 latitude = lat.format(location.getLatitude());
 longitude = log.format(location.getLongitude());
 latitude = latitude.replace(",", ".");
 longitude = longitude.replace(",", ".");
    
 D3 = Double.parseDouble(latitude);
 E3 = Double.parseDouble(longitude);
     
 Log.d("latitude final",String.valueOf(D3));
 Log.d("longitude final",String.valueOf(E3));
        
 distancia = 6371*Math.acos(Math.cos(PI*(90-D3)/180)*Math.cos((90-D2)*PI/180)+Math.sin((90-D3)*PI/180)*Math.sin((90-                                                                D2)*PI/180)*Math.cos((E2-E3)*PI/180)); 
 double velocidade = distancia/2000;
 Toast.makeText(getBaseContext(),dis.format(velocidade),Toast.LENGTH_SHORT).show();
          D2 = D3;
 E2 = E3;
 if(velocidade==0){
 validaDados("Desligar");                   //envia para o metodo de validação antes de enviar para o proximo dispositivo                    
 writeData(dadoEnviarSintetizador);      //envia o dado para o dispositivo Client                                        
 }else{
 validaDados("Ligar");                //envia para o metodo de validação antes de enviar para o proximo dispositivo                    
 writeData(dadoEnviarSintetizador);      //envia o dado para o dispositivo Client                                        
 }
		}
 }

 @Override
 public void onStatusChanged(String provider, int status, Bundle extras) {
 // TODO Auto-generated method stub
 }

 @Override
 public void onProviderEnabled(String provider) {
 // TODO Auto-generated method stub
 }

 @Override
 public void onProviderDisabled(String provider) {
 // TODO Auto-generated method stub
 }
}

MONTAGEM
Segue abaixo o circuito montado e fotos do projeto
wakeupImagem

imagen1

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s