Este artículo es una traducción de Día 4: Compass , puedes encontrar aquí la versión en inglés.

dia4

Hoy voy a hablar acerca de un sensor que se encuentra dentro de cada dispositivo Windows Phone actualmente, la brújula. En los teléfono originales, cada dispositivo tenía una brújula, pero los desarrolladores no tenían una API para poder acceder a ella. Con el lanzamiento de Windows Phone 7.5, se volvió una pieza opcional del equipo, pero con una API muy rica similar  a la del acelerómetro.

En adición, si tu quisieras probar esta aplicación en tu dispositivo justo ahora, ¡esta disponible en el Marketplace de Windows Phone!

DownloadIcon1

Antes de que nos vayamos al “como” de la API de la brújula, sin embargo, vamos a hablar acerca de lo que la brújula verdaderamente es.

¿Qué es una brújula?

En términos tradicionales, una brújula es usada para determinar la dirección del norte magnético de la tierra. Cuando escuchas la palabra brújula, probablemente imagines algo como esto.

image18

Ciertamente no es una de estas la que llevas en tu dispositivo, En su lugar, los teléfonos móviles optaron por utilizar algo mas acertado referido como un magnetómetro. En nuestro caso, un magnetómetro puede aún determinar la rotación de el dispositivo relativo a un norte magnético, pero también puede determinar la rotación del dispositivo relativo al norte magnético. Además, puede ser capaz de detectar campos magnéticos alrededor del dispositivo (los cuales comunmente interfieren con los otros cálculos). Para demostrar eso de la mejor forma, he creado un video rápido donde uso un imán con mi Windows Phone.

Puedes ver aquí el video

Los valores X, Y y Z que tu ves en la pantalla son de hecho medidos en microteslas, las cuales miden la fuerza de un campo magnético. Los valores en blanco que están mostrados sobre la X, Y y Z, son los valores magnéticos y verdaderos medidos en grados. El MagneticHeading usa el polo norte magnético como su referencia, mientras que el TrueHeading usa el polo norte geográfico. Así que ahora que nos hemos metido dentro de la ciencia del sensor de brújula, vamos a darle un vistazo a como podemos construir la aplicación mostrada en el video.

Usando la brújula del Windows Phone

Primero, vamos a crear la interfaz del usuario. En caso de que no hayas visto el video arriba, vamos a estar creando algo como esto.

image19

 

Una vez que hayas creado esta aplicación de ejemplo, estoy seguro de que también tomarás un imán y le darás la posibilidad de la duda a mi video. Aquí está el XAML para comenzar con tu interfaz.

<Grid x:Name=”LayoutRoot” Background=”Transparent”>
<Grid.RowDefinitions>
<RowDefinition Height=”Auto”/>
<RowDefinition Height=”*”/>
</Grid.RowDefinitions>

<StackPanel x:Name=”TitlePanel” Grid.Row=”0″ Margin=”12,17,0,28″>
<TextBlock x:Name=”ApplicationTitle” Text=”LA LIGA SILVERLIGHT” Style=”{StaticResource PhoneTextNormalStyle}”/>
<TextBlock x:Name=”PageTitle” Text=”brújula” Margin=”9,-7,0,0″ Style=”{StaticResource PhoneTextTitle1Style}”/>
</StackPanel>

<Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
<TextBlock Height=”30″ HorizontalAlignment=”Left”  Margin=”20,73,0,0″ Text=”MAGNETICO” VerticalAlignment=”Top” FontSize=”28″ FontWeight=”Bold”/>
<TextBlock Height=”30″ HorizontalAlignment=”Right”  Margin=”0,74,47,0″ Text=”REAL” VerticalAlignment=”Top” Foreground=”Gray” FontSize=”28″ FontWeight=”Bold”/>
<TextBlock Height=”30″ HorizontalAlignment=”Left”  Margin=”20,100,0,0″ x:Name=”txtMagnetico” Text=”1.0″ VerticalAlignment=”Top” FontSize=”28″ FontWeight=”Bold” Width=”147″ TextAlignment=”Center” />
<TextBlock Height=”30″ HorizontalAlignment=”Right”  Margin=”0,100,20,0″ x:Name=”txtReal” Text=”1.0″ VerticalAlignment=”Top” Foreground=”Gray” FontSize=”28″ FontWeight=”Bold” Width=”123″ TextAlignment=”Center” />
<TextBlock Height=”30″ HorizontalAlignment=”Left”  Margin=”20,140,0,0″ x:Name=”txtX” Text=”X: 1.0″ VerticalAlignment=”Top” Foreground=”Red” FontSize=”28″ FontWeight=”Bold”/>
<TextBlock Height=”30″ HorizontalAlignment=”Center”  Margin=”0,140,0,0″ x:Name=”txtY” Text=”Y: 1.0″ VerticalAlignment=”Top” Foreground=”Green” FontSize=”28″ FontWeight=”Bold”/>
<TextBlock Height=”30″ HorizontalAlignment=”Right”  Margin=”0,140,20,0″ x:Name=”txtZ” Text=”Z: 1.0″ VerticalAlignment=”Top”  Foreground=”Blue” FontSize=”28″ FontWeight=”Bold”/>
<Line x:Name=”lineaMagnetica” X1=”240″ Y1=”350″ X2=”240″ Y2=”270″ Stroke=”{StaticResource PhoneForegroundBrush}” StrokeThickness=”4″></Line>
</Grid>
</Grid>

 

Podrás ver que nosotros realmente tenemos solo un montón de TextBlock y una línea. Esta línea será utilizada para actuar como una brújula tradicional, apuntando al norte. Sin embargo, de hecho estará apuntando hacia el campo magnético mas fuerte, esta es la razón por la que se mueve tanto cuando acercamos un imán.

La mayor parte de nuestro esfuerzo será en el archivo del code behind, incluyendo un poco de matemáticas avanzadas para hacer que nuestra línea se mueva apropiadamente. Vamos a comenzar inicializando y detectando nuestra brújula en el dispositivo.

using System;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;

namespace Dia_4_Brujula
{
public partial class MainPage : PhoneApplicationPage
{
Compass brujula;

public MainPage()
{
InitializeComponent();

if (Compass.IsSupported)
{

}

Puedes ver que tenemos que agregar una referencia al ensamblado Microsoft.Devices.Sensors (también una referencia a Microsoft.Xna.Framework, pero eso será para después). Esto la habilidad de comunicarnos con el sensor, y también checar para ver si el dispositivo soporta o no la brújula.  Donde dejé el espacio en blanco es donde nosotros inicializaremos nuestra brújula y crearemos un manejador de eventos para manejar que produce.

using System;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;

namespace Dia_4_Brujula
{
public partial class MainPage : PhoneApplicationPage
{
Compass brujula;

public MainPage()
{
InitializeComponent();

if (Compass.IsSupported)
{
brujula = new Compass();
brujula.TimeBetweenUpdates = TimeSpan.FromMilliseconds(1);
brujula.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<CompassReading>>(brujula_CurrentValueChanged);
brujula.Start();
}

}

void brujula_CurrentValueChanged(object sender, SensorReadingEventArgs<CompassReading> e)
{

}

En el código de ejemplo de arriba, nosotros agregamos una propiedad TimeBetweenUpdates, el cual limita que tan seguido obtenemos nueva información del sensor. Lo he ajustado para darme actualizaciones tan pronto como sea posible, pero esto también es una consideración para la batería. No recomiendo la lectura de los sensores mas seguido de lo que realmente necesitas. Tomar lecturas mas lentas te dará la habilidad de dar un movimiento mas suave de “aguja”. Deberías ver que en mi video arriba, la aguja del compass brinca muy erraticamente. Este es el resultado de mis TimeBetweenUpdates frecuentes.

También he creado un manejador CurrentValueChanged, el cual nos dará los nuevos valores de la brújula cada vez que un cambio sea detectado. Para algo tan sensible como la brújula (o el tema de mañana, el giroscopio), comenzarás a sentirte cómodo con la información, así que manéjala de tal forma que tenga sentido para tu aplicación.

Finalmente, llamamos el método Start(), el cual le dice a la brújula que comienza a poner atención a la información. Esta información es pasada a nuestro manejador de evento con el nombre brujula_CurrentValueChanged como un objeto de tipo CompassReading. Para leer esta información, nosotros necesitamos moverla del hilo primario del procesador. Si tratamos de leer esta información directamente en este manejador de eventos, solo obtendremos una UnauthorizedAccessException, la cual nos previene de un acceso a través de hilos inválido. Así que donde ves el espacio en blanco, vamos a pasar nuestro objeto de tipo CompassReading a un método en un hilo separado, el cual nos dará el código final de abajo.

using System;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;

namespace Dia_4_Brujula
{
public partial class MainPage : PhoneApplicationPage
{
Compass brujula;

public MainPage()
{
InitializeComponent();

if (Compass.IsSupported)
{
brujula = new Compass();
brujula.TimeBetweenUpdates = TimeSpan.FromMilliseconds(1);
brujula.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<CompassReading>>(brujula_CurrentValueChanged);
brujula.Start();
}

}

void brujula_CurrentValueChanged(object sender, SensorReadingEventArgs<CompassReading> e)
{
Dispatcher.BeginInvoke(() => UpdateUI(e.SensorReading));
}

private void UpdateUI(CompassReading compassReading)
{
txtMagnetico.Text = compassReading.MagneticHeading.ToString(“0.00″);
txtReal.Text = compassReading.TrueHeading.ToString(“0.00″);

lineaMagnetica.X2 = lineaMagnetica.X1 – (200 * Math.Sin(MathHelper.ToRadians((float)compassReading.MagneticHeading)));
lineaMagnetica.Y2 = lineaMagnetica.Y1 – (200 * Math.Cos(MathHelper.ToRadians((float)compassReading.MagneticHeading)));

txtX.Text = “X: ” + compassReading.MagnetometerReading.X.ToString(“0.00″);
txtY.Text = “Y: ” + compassReading.MagnetometerReading.Y.ToString(“0.00″);
txtZ.Text = “Z: ” + compassReading.MagnetometerReading.Z.ToString(“0.00″);
}
}
}

 

Usando el método Dispatcher.BeginInvoke nos permitirá pasar nuestra información a un hilo separado, donde nosotros podremos trabajar con la información. Dentro de nuestro método UpdateUI, nosotros también asignamos los valores X, Y y Z a los elementos de nuestra UI. Para determinar la dirección de nuestra línea, sin embargo, necesitamos un poco de matemáticas avanzadas, y de hecho jalar la clase MathHelper del ensamblado Microsoft.Xna.Framework.

Lo que estoy haciendo en esos dos valores para la línea magnética es determinar las coordenadas X e Y de el final de la línea del control que estamos usando. Porque estará siempre anclada al centro de nuestra pantalla, podremos calcular nuestras matemáticas basados en esa posición. Esto es la razón por la que comencé con los valores de lineaMagnetica.X1 y lineaMagnetica.Y1. Para explicar el resto de las matemáticas, el valor 200 es solo la longitud de la línea. La línea es siempre de 200 píxeles de largo. El resto de los cálculos usa una conversión de radianes de el valor MagneticHeading para determinar donde en la curva (usando las funciones de Seno y Coseno) el final de la línea debería residir.

Para usar el XAML arriba y el C# que recién hemos terminado, puedes fácilmente construir un lector de brújula.

En resumen

La brújula es un sensor poderoso en nuestro Windows Phone que nos da la habilidad para determinar hacia que dirección está apuntando el dispositivo, además para medir campos magnéticos cerca del dispositivo. En los próximos días, vamos a checar otro sensor, el giroscopio, y después checaremos a la nueva clase Motion que solo combina todos los sensores en una API que nos da una vista mucho mas rica a la orientación del dispositivo del usuario.

Si tu quieres descargar una solución que acceda a la brújula de Windows Phone, puedes hacerlo descargando el proyecto.

Descarga aquí el código.

Mañana, voy a escribir acerca de otro sensor genial, el giroscopio. Es una herramienta genial para entender la orientación del dispositivo, y uno de esos temas en los que definitivamente debes pasar algo de tiempo. ¡Nos vemos!