Este artículo es una traducción de Day 6: Motion, puedes encontrar aquí la versión original en inglés.

dia6

Hoy, vamos a tomar toda la información que hemos aprendido de los últimos dos días y vamos a hacerla mucho mas sencilla de manejar utilizando la clase Motion. La clase Motion es una combinación de la información que recibimos del acelerómetro, la brújula y el giroscopio en un Windows Phone.

Si tu quisieras, descargar esta aplicación para ti Windows Phone, esta disponible en Windows Phone Marketplace de manera gratuita.

 

Inclinación, desplazamiento y rotación

 

200px-Aptch200px-Ayaw200px-Aileron_roll

          Inclinación                                               Desplazamiento                                               Rotación

Como puedes ver de las imágenes animadas arriba, la inclinación, desplazamiento y rotación (o giro), son tres piezas importantes de información en la aviación, pero ellas pueden aplicar en nuestro Windows Phone también. Cuando nosotros miramos al acelerómetro y giroscopio, éramos capaces de obtener información acerca del dispositivo en ejes específicos: X, Y y Z. La inclinación, desplazamiento y giro representan la rotación sobre esos ejes. Esto es hecho utilizando un puñado de matemáticas que la clase Motion de hecho ejecuta para nosotros automáticamente. (Para mas información en los ejes principales de la aviación, checa en Wikipedia).

Utilizando la clase Motion

En nuestros ejemplos previos de el giroscopio y la brújula, nosotros hemos detectado a los sensores en el dispositivo antes de comenzar. No necesitamos hacer un chequeo individual cuando usamos la clase Motion, lo que necesitamos es verificar que la clase Motion, por si sola es soportada.

Antes de que nos metamos en el código específico para la clase Motion, vamor a checar la interfaz. Para nuestro ejemplo, vamos a colocar una estrella XAML en nuestra pantalla, como en la imagen de abajo.

image22

 

Al utilizar el valor de desplazamiento de la clase Motion, nosotros seremos capaces de manipular la orientación de la estrella. Mientras que el usuario rote su teléfono, la estrella parecerá permanecer estacionaria en relación al usuario. Aquí puedes ver un video breve para ilustrar este efecto de forma práctica.

Puedes ver el video aquí.

Aquí está el XAML que necesitamos para completar la interfaz.

<phone:PhoneApplicationPage
    x:Class=”Dia_6_Motion.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:es=”clr-namespace:Microsoft.Expression.Shapes;assembly=Microsoft.Expression.Drawing”
    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”>

    <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=”motion” Margin=”9,-7,0,0″ Style=”{StaticResource PhoneTextTitle1Style}”/>
        </StackPanel>

        <Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
            <es:RegularPolygon x:Name=”estrella” InnerRadius=”0.47211″ Margin=”100,175,100,175″ PointCount=”5″ Stretch=”Fill” Stroke=”White” UseLayoutRounding=”False” StrokeThickness=”6″>
                <es:RegularPolygon.Fill>
                    <SolidColorBrush Color=”{StaticResource PhoneAccentColor}”/>
                </es:RegularPolygon.Fill>
                <es:RegularPolygon.RenderTransform>
                    <RotateTransform CenterX=”100″ CenterY=”128″></RotateTransform>
                </es:RegularPolygon.RenderTransform>
            </es:RegularPolygon>

            <TextBlock x:Name=”txtValor” Text=”YAW = 34.567″ FontSize=”40″ Width=”400″ Height=”100″ TextAlignment=”Center” Margin=”28,503,28,4″ />     
        </Grid>
    </Grid>
</phone:PhoneApplicationPage>

Deberás notar que nuestra estrella esta creada utilizando la referencia a un nuevo ensamblado específico de Expression Blend. Sin embargo, no necesitamos usar Blend para usar los controles que contiene. Necesitarás hacer una referencia al ensamblado Microsoft.Expression.Drawing y nombrar adecuadamente un nombre de espacio en la parte superior de tu XAML. Si tu no has jugado con esto antes, trata de cambiar la propiedad PointCount del polígono. Puedes crear estrellas con tantos picos como tu quieras (aunque después de 60 puntos no notes mucha diferencia).

Podrás ver igual, los otros dos cambios que le he hecho a la estrella. El primero es el color del Fill, he definido un SolidColorBrush que utilizará el color del tema seleccionado. Esto fue cubierto en el Día 5 de los 31 días de Windows Phone, así que asegúrate de leerlo si lo quieres usar en tu aplicación.

Para comenzar a hacer que esta estrella se comience a mover, vamos a estar usando conceptos muy similares a aquellos que usamos en los sensores individuales. Primero vamos a hacer la detección de la clase Motion.

 

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

namespace Dia_6_Motion
{
    public partial class MainPage : PhoneApplicationPage
    {
        Motion motion;

        public MainPage()
        {
            InitializeComponent();
            if (Motion.IsSupported)
            {
                //HACER ALGO
            }
        }

       
    }
}

En nuestro espació de “HACER ALGO”, necesitamos inicializar nuestro objeto Motion, y crear un manejador de eventos para escuchar la información que será creada.

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

namespace Dia_6_Motion
{
    public partial class MainPage : PhoneApplicationPage
    {
        Motion motion;

        public MainPage()
        {
            InitializeComponent();
            if (Motion.IsSupported)
            {
                motion = new Motion();
                motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
                motion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(motion_CurrentValueChanged);
                motion.Start();
            }
        }

        void motion_CurrentValueChanged(object sender, SensorReadingEventArgs<MotionReading> e)
        {
            //OBTENER LA INFORMACION
        }

    }
}

Finalmente necesitamos asegurarnos que practiquemos un poco de seguridad en el manejo de hilos. No podemos leer la información a través del hilo de la UI, así que necesitamos enviar ese proceso a un hilo separado usando el método Dispatcher.BeginInvoke(). Tu verás eso agregado abajo, junto con nuestras matemáticas para manipular la estrella. El código abajo debería ser la única versión de la aplicación que tu de hecho necesitas copiar y pegar para hacer el tuyo propio.

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

namespace Dia_6_Motion
{
    public partial class MainPage : PhoneApplicationPage
    {
        Motion motion;

        public MainPage()
        {
            InitializeComponent();
            if (Motion.IsSupported)
            {
                motion = new Motion();
                motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
                motion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(motion_CurrentValueChanged);
                motion.Start();
            }
        }

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

        private void UpdateUI(MotionReading e)
        {
            ((RotateTransform)estrella.RenderTransform).Angle = MathHelper.ToDegrees(e.Attitude.Yaw);
            txtValor.Text = “Desplazamiento = ” + e.Attitude.Yaw.ToString();

            float pitch = e.Attitude.Pitch;
            float yaw = e.Attitude.Yaw;
            float roll = e.Attitude.Roll;

            float accelerometerX = e.DeviceAcceleration.X;
            float accelerometerY = e.DeviceAcceleration.Y;
            float accelerometerZ = e.DeviceAcceleration.Z;

            float gyroscopeX = e.DeviceRotationRate.X;
            float gyroscopeY = e.DeviceRotationRate.Y;
            float gyroscopeZ = e.DeviceRotationRate.Z;

            float gravityX = e.Gravity.X;
            float gravityY = e.Gravity.Y;
            float gravityZ = e.Gravity.Z;

            DateTimeOffset timestamp = e.Timestamp;
        }
    }
}

Puedes ver que nosotros aplicamos nuestro valor de desplazamiento al ángulo de nuestra estrella, forzándola a rotar mientras los sensores detectan el movimiento del teléfono. Dale una prueba al dispositivo (asumiendo que tienes uno disponible) y probablemente notarás una diferencia significativa en la conducta entre un teléfono que tiene un giroscopio y uno que no. Como mencioné ayer, un giroscopio da mucha mayor precisión de información, y como tal, la estrella se mueve con gracia cuando el giroscopio esta presente.

¿Qué quieres decir? ¿No tienes un teléfono?

No estoy sugiriendo que salgas ahora mismo a comprar uno (aunque obviamente eres mas que bienvenido para hacerlo). Si tu vives en la parte central-oeste de Estados Unidos, puedes enviarle a Jeff Blankenburg un tweet, o un correo, el puede prestarte un dispositivo por 10 días. Si tu no vives ahí, contáctalo de todas formas, el podrá conectarte con la persona a cargo en el área por la que vivas. Todos tienen teléfonos disponibles para prestar.

Un poco mas de información interesante…

En mi código de ejemplo aquí, realmente solo utilizé la información de movimiento de la clase Motion. En la solución descargable de Windows Phone mas abajo, también incluí variables para obtener toda la información disponiblede la clase Motion. Aquí es como ve ve.

 

float pitch = e.Attitude.Pitch;
float yaw = e.Attitude.Yaw;
float roll = e.Attitude.Roll;

float accelerometerX = e.DeviceAcceleration.X;
float accelerometerY = e.DeviceAcceleration.Y;
float accelerometerZ = e.DeviceAcceleration.Z;

float gyroscopeX = e.DeviceRotationRate.X;
float gyroscopeY = e.DeviceRotationRate.Y;
float gyroscopeZ = e.DeviceRotationRate.Z;

float gravityX = e.Gravity.X;
float gravityY = e.Gravity.Y;
float gravityZ = e.Gravity.Z;

DateTimeOffset timestamp = e.Timestamp;

Puedes ver que aún tenemos acceso a la información de los sensores individuales, así como a un valor de tipo TimeStamp para saber exactamente cuando ocurrió nuestra información.

En Resumen

Así que esta es la clase Motion. Debería ser una manera primaria en la que tu interactúas con el giroscopio, brújula y acelerómetro, y debería haber mucho mas fáciles las matemáticas y procesamientos para tí. Para aquellos preguntándose alguna forma interesante de como utilizar esta información, aquí está un gran ejemplo.

Un gran uso que vi del acelerómetro que he visto, fue en una aplicación de ciclismo. El punto principal de la aplicación era registrar por donde estaba el usuario usando su bicicleta. Como un elemento de seguridad, podrías ingresar un teléfono de emergencias. Si la aplicación reconoce una parada brusca, seguida por un movimiento muy pequeño, podría automáticamente escribir a emergencias un mensaje de texto con las coordenadas del GPS del dispositivo. Además de eso, haría al teléfono marcar al número local de emergencias. Este es un uso sorprendente de manejo de información entre el GPS y el acelerómetro que ayudaría al ciclista a sentirse mucho mas seguro. Tu aplicación puede hacer eso igual.

Si quieres descargar la solución de este artículo puedes hacerlo con el siguiente enlace.

Descarga aquí el código.

Mañana, vamos a hablar de otra gran API, la de la cámara. Ahora podemos tener la habilidad de obtener la información de las imágenes que la cámara capture, y hablaremos acerca de como hacerlo y para que podríamos usarla. ¡Nos vemos!