Я недавно видел этот проект Android, и я подумал, что было бы неплохо реализовать что-то подобное для Windows Phone. Это потребовало некоторого понимания физики и общей обработки данных акселерометра, но это, безусловно, интересный проект для реализации. Я был готов к тому, что у Windows Phone будут некоторые ограничения (например, нет автоматического вызова без одобрения пользователя), но в целом он должен работать аналогичным образом.
Итак, давайте подумаем об общей концепции. Сначала мне нужно прочитать данные акселерометра, поэтому я создал тестовую консоль, которая отображает текущие значения акселерометра, а также график чистой силы, возвращаемой акселерометром. Вот окончательный результат (UI):
Процесс захвата данных настолько прост, насколько это возможно — я использую стандартный класс акселерометра в сочетании с диспетчером , который передает данные обратно в пользовательский интерфейс. Вот код:
Accelerometer acc; public MainPage() { InitializeComponent(); acc = new Accelerometer(); acc.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(acc_CurrentValueChanged); } void acc_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e) { double f = Math.Sqrt(e.SensorReading.Acceleration.X * e.SensorReading.Acceleration.X + e.SensorReading.Acceleration.Y * e.SensorReading.Acceleration.Y + e.SensorReading.Acceleration.Z * e.SensorReading.Acceleration.Z); Dispatcher.BeginInvoke(new Action(() => { accList.Items.Add(f); var rectangle = new System.Windows.Shapes.Rectangle(); rectangle.Width = 1.0; rectangle.Height = f * 25; rectangle.Fill = new SolidColorBrush(Colors.Blue); GraphGrid.Children.Add(rectangle); })); } private void btnStart_Click(object sender, RoutedEventArgs e) { acc.Start(); } private void btnStop_Click(object sender, RoutedEventArgs e) { acc.Stop(); }
Обратите внимание, как я вычисляю значение f , которое представляет чистую силу. Учитывая евклидову норму , я вычисляя одно значение из трех существующих векторов — X , Y и Z . Я не должен просто добавлять их вместе, потому что я не работаю со скалярными значениями. Статическое значение, когда телефон не находится в движении, должно быть равно единице (1G — гравитационная единица) с небольшими колебаниями.
XAML для главной страницы:
<phone:PhoneApplicationPage x:Class="MANGO_PIVOT.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d:DesignHeight="800" d:DesignWidth="480"> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="500"></RowDefinition> <RowDefinition Height="200"></RowDefinition> <RowDefinition Height="*"></RowDefinition> </Grid.RowDefinitions> <ListBox x:Name="accList" Grid.Row="0"></ListBox> <ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto"> <StackPanel Orientation="Horizontal" x:Name="GraphGrid"> </StackPanel> </ScrollViewer> <StackPanel Orientation="Horizontal" Grid.Row="2"> <Button x:Name="btnStart" Content="Start" Width="240" Click="btnStart_Click"></Button> <Button x:Name="btnStop" Content="Stop" Width="240" Click="btnStop_Click"></Button> </StackPanel> </Grid> </phone:PhoneApplicationPage>
Положение векторов на основе акселерометра можно легко увидеть на этом рисунке:
Та же самая сила гравитации применяется к телефону, если он неподвижен (лицевой стороной вверх или вниз), а отрицательные или положительные значения показывают ориентацию телефона — благодаря тому, как работает акселерометр , он может определять направление гравитации вытащить.
В целях абстракции вы можете игнорировать положительные и отрицательные индикаторы — направление гравитационного притяжения в данный момент нас не интересует.
В положении телефона на рисунке оси X и Y не имеют активных сил, связанных с ними. Сила G применяется к оси Z, и ее значение в настоящее время составляет 1G = 9,8 м / с.
Давайте предположим, что телефон упал и летит лицом вверх или вниз. Поскольку это свободное падение, полное ускорение достигнет точки нуля, потому что:
- В целях абстракции мы пока игнорируем небольшие значения, сгенерированные X и Y. Они нулевые.
- Сила сопротивления воздуха быстро станет такой же, как вес (масса * г), компенсируя друг друга. При этом чистое ускорение станет равным нулю (0).
Вот почему, если вы посмотрите на исходный график, вы увидите, что есть временной интервал, когда график спускается до тонкой линии — он приближается к нулю, но еще не там. Изучив значения AccelerometerReading.Z , вы заметите, что они довольно быстро приближаются к нулю.
Когда телефон сталкивается с землей, мы видим всплеск результирующей силы, так как телефон падает и движется совершенно случайно, почти все три оси испытывают внешнюю силу. Именно тогда мы узнаем, что на самом деле произошло столкновение — или мы предполагаем, что в идеальной ситуации. Того же результата можно добиться, если телефон активно встряхивать в руке.
После этого значения ускорения возвращаются к норме, чистая сила составляет около 1G без внешних воздействий.
В следующей (и последней) части этой статьи я покажу вам, как обнаружить коллизию и как предпринять соответствующие действия, чтобы у нас было приложение, похожее на упомянутое в начале, работающее только на Windows Phone.