Utilizando o Giroscópio no Windows Phone

Veja neste artigo como utilizar o recurso de giroscópio no Windows Phone através de um exemplo prático em uma aplicação.

Em diversas situações o dispositivo é utilizado como entrada de dados para os aplicativos, como em jogos que utilizam movimentos como controles, e o Windows Phone suporta vários tipos de sensores que permitem que a aplicação capte a orientação e o movimento do aparelho.

A função do giroscópio é medir a velocidade nos eixos X, Y e Z, e possui uma sensibilidade a ponto de indicar a rotação até mesmo com o aparelho parado, porém o giroscópio é opcional nos aparelhos.

Figura 1. Smartphone da HTC com Windows Phone
Nota: Por ser opcional, é essencial que as aplicações verifiquem se o aparelho possui o giroscópio e caso não possua, adaptem o aplicativo para o uso sem o mesmo. No Windows Phone existem recursos para verificar e decidir a melhor maneira de utilizá-los.

Infelizmente para testar o exemplo a ser mostrado neste artigo você necessitará de um device real, portanto fique avisado que caso vá testar o aplicativo no emulador, será mostrado no estado da aplicação que o device não possui giroscópio.

Abra o Visual Studio e crie um projeto do tipo Windows Phone Application chamado GiroscopioApplication, conforme a Figura 2.

Figura 2. Criação do projeto GiroscopioApplication no Visual Studio

Ao criar o projeto é exibida uma caixa com a opção de escolha da versão do Windows Phone, escolha a 7.1, pois assim o seu aplicativo funcionará em todas as versões de Windows Phone disponíveis.

Agora você deve adicionar uma nova referência, para isso vá ao Solution Explorer e clique com o botão direito em Reference, e depois Add Reference. Será exibida uma janela com diversas opções e você deverá selecionar o Microsoft.XNA.Framework e o Microsoft.Devices.Sensors, conforme a Figura 3.

Figura 3. Adicionando referência ao projeto

Agora você deverá alterar o layout da página principal, para isso abra a MainPage.xaml e no ContentPanel adicione os controles necessários para a visualização dos dados. Você terá um label para informar o estado da aplicação, linhas que mostrarão os valores de X, Y e Z e etc. Veja como ficará a MainPage.xaml com os controles adicionados na Listagem 1.

<phone:PhoneApplicationPage x:Class="GiroscopioApplication.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" shell:SystemTray.IsVisible="True"> <!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="APLICATIVO SENSOR" /> <TextBlock x:Name="PageTitle" Text="giroscópio" Margin="9,-7,0,0" /> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical"> <TextBlock Height="30" Name="lblStatus" Text="Estado: " VerticalAlignment="Top" /> <TextBlock Height="30" Name="lblAtualizacoes" Text="Intervalo de atualizações: " VerticalAlignment="Top" /> </StackPanel> <TextBlock Text="Velocidade Rotacional:" /> <Grid> <TextBlock Height="30" HorizontalAlignment="Left" Name="lblXAtual" Text="X: 1.0" VerticalAlignment="Top" Foreground="Red" FontSize="28" FontWeight="Bold" /> <TextBlock Height="30" HorizontalAlignment="Center" Name="lblYAtual" Text="Y: 1.0" VerticalAlignment="Top" Foreground="LightGreen" FontSize="28" FontWeight="Bold" /> <TextBlock Height="30" HorizontalAlignment="Right" Name="lblZAtual" Text="Z: 1.0" VerticalAlignment="Top" Foreground="LightBlue" FontSize="28" FontWeight="Bold" /> </Grid> <Grid Height="140"> <Line x:Name="currentXLine" X1="240" Y1="40" X2="240" Y2="40" Stroke="Red" StrokeThickness="14" /> <Line x:Name="currentYLine" X1="240" Y1="40" X2="240" Y2="40" Stroke="LightGreen" StrokeThickness="14" /> <Line x:Name="currentZLine" X1="240" Y1="40" X2="240" Y2="40" Stroke="Blue" StrokeThickness="14" /> </Grid> <TextBlock Text="cumulative rotation (degrees)"/> <Grid> <TextBlock Height="30" HorizontalAlignment="Left" Name="lblXAcumulado" Text="X: 1.0" VerticalAlignment="Top" Foreground="Red" FontSize="28" FontWeight="Bold" /> <TextBlock Height="30" HorizontalAlignment="Center" Name="lblYAcumulado" Text="Y: 1.0" VerticalAlignment="Top" Foreground="LightGreen" FontSize="28" FontWeight="Bold" /> <TextBlock Height="30" HorizontalAlignment="Right" Name="lblZAcumulado" Text="Z: 1.0" VerticalAlignment="Top" Foreground="LightBlue" FontSize="28" FontWeight="Bold" /> </Grid> <Grid Height="200" Name="grdAcumulo"> <Line x:Name="lnX" X1="240" Y1="100" X2="240" Y2="0" Stroke="Red" StrokeThickness="14" /> <Line x:Name="lnY" X1="240" Y1="100" X2="240" Y2="0" Stroke="LightGreen" StrokeThickness="14" /> <Line x:Name="lnZ" X1="240" Y1="100" X2="240" Y2="0" Stroke="LightBlue" StrokeThickness="14" /> </Grid> <Button Content="Start" Height="72" Name="btnStart" Click="btnStart_Click" /> </StackPanel> </Grid> </Grid> </phone:PhoneApplicationPage>
Listagem 1. Arquivo MainPage.xaml

Sua aplicação deverá estar conforme a Figura 4.

Figura 4. Layout da página principal, após alteração da MainPage.xaml

Agora você deverá tratar o método do evento de click do botão Start e adicionar mais dois métodos na classe, um para ser chamado a certo intervalo de tempo e alterar as informações e um outro método para exibir as informações após a coleta. Verifique como ficará a classe MainPage.xaml.cs na Listagem 2.

Você também deve adicionar a referência no topo para System.Windows.Threading, Microsoft.XNA.Framework, e Microsoft.Devices.Sensors.

Lembrando que como alguns devices não possuem giroscópio, então no construtor é feita a verificação e caso não possua, impossibilita o teste pelo click do botão.

using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using System.Windows.Threading; using Microsoft.Xna.Framework; using Microsoft.Devices.Sensors; namespace GiroscopioApplication { public partial class MainPage : PhoneApplicationPage { Gyroscope giroscopio; DispatcherTimer timer; Vector3 taxaRotacao = Vector3.Zero; Vector3 rotacaoAcumulada = Vector3.Zero; DateTimeOffset ultimaAtualizacao = DateTimeOffset.MinValue; bool isDataValid; // Constructor public MainPage() { InitializeComponent(); if (!Gyroscope.IsSupported) { lblStatus.Text = "Não há suporte de giroscópio para o aparelho"; btnStart.IsEnabled = false; } else { timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromMilliseconds(60); timer.Tick += timer_Tick; } } void timer_Tick(object sender, EventArgs e) { if (isDataValid) { lblStatus.Text = "Recebendo informações...."; } lblXAtual.Text = taxaRotacao.X.ToString("0.000"); lblYAtual.Text = taxaRotacao.Y.ToString("0.000"); lblZAtual.Text = taxaRotacao.Z.ToString("0.000"); lblXAcumulado.Text = MathHelper.ToDegrees(rotacaoAcumulada.X).ToString("0.00"); lblYAcumulado.Text = MathHelper.ToDegrees(rotacaoAcumulada.Y).ToString("0.00"); lblZAcumulado.Text = MathHelper.ToDegrees(rotacaoAcumulada.Z).ToString("0.00"); double centerX = grdAcumulo.ActualWidth / 2.0; double centerY = grdAcumulo.ActualHeight / 2.0; currentXLine.X2 = centerX + taxaRotacao.X * 100; currentYLine.X2 = centerX + taxaRotacao.Y * 100; currentZLine.X2 = centerX + taxaRotacao.Z * 100; lnX.X2 = centerX - centerY * Math.Sin(rotacaoAcumulada.X); lnX.Y2 = centerY - centerY * Math.Cos(rotacaoAcumulada.X); lnY.X2 = centerX - centerY * Math.Sin(rotacaoAcumulada.Y); lnY.Y2 = centerY - centerY * Math.Sin(rotacaoAcumulada.X); lnZ.X2 = centerX - centerY * Math.Cos(rotacaoAcumulada.X); lnZ.Y2 = centerY - centerY * Math.Sin(rotacaoAcumulada.Y); } void giroscopio_CurrentValueChanged(object sender, SensorReadingEventArgs<GyroscopeReading> e) { isDataValid = giroscopio.IsDataValid; if (ultimaAtualizacao.Equals(DateTimeOffset.MinValue)) { ultimaAtualizacao = e.SensorReading.Timestamp; } else { taxaRotacao = e.SensorReading.RotationRate; TimeSpan timeSinceLastUpdate = e.SensorReading.Timestamp - ultimaAtualizacao; rotacaoAcumulada += taxaRotacao * (float)(timeSinceLastUpdate.TotalSeconds); ultimaAtualizacao = e.SensorReading.Timestamp; } } private void btnStart_Click(object sender, RoutedEventArgs e) { if (giroscopio != null && giroscopio.IsDataValid) { giroscopio.Stop(); timer.Stop(); lblStatus.Text = "Giroscópio parado"; } else { if (giroscopio == null) { giroscopio = new Gyroscope(); giroscopio.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20); lblAtualizacoes.Text = "Intervalo de atualizações: " + giroscopio.TimeBetweenUpdates.TotalMilliseconds + " ms"; giroscopio.CurrentValueChanged += giroscopio_CurrentValueChanged; } } try { lblStatus.Text = "Iniciando o giroscópio"; giroscopio.Start(); timer.Start(); } catch (Exception) { lblStatus.Text = "Não é possível iniciar o giroscópio"; } } } }
Listagem 2. Código da classe MainPage.xaml.cs

Basta agora conectar seu dispositivo, alterar o modo de debug para device, conforme a Figura 5, pressionar F5 e testar a aplicação.

Figura 5. Alterando o modo de debug para Device
Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados