Dieser Artikel ist Tag #5 der Serie 31 Tage Mango von Jeff Blankenburg.
Der Originalartikel befindet sich hier: Day #5: Gyroscope.
Heute reden wir über einen neuen Sensor, das Gyroskop. Dieser Sensor wird nur in Geräten verfügbar sein, die nach dem Mango Start erschienen sind und sogar dann wird er nicht in allen Geräten vorhanden sein. Da das Gyroskop aber ein mächtiger Sensor ist, sollten wir von ihm Gebrauch machen, wenn er zur Verfügung steht.
Was ist ein Gyroskop?
Laut Wikipedia werden Gyroskope „als Navigationsinstrumente sowie zur aktiven Lageregelung eingesetzt“. Viele von Ihnen werden ein Gyroskop (auch „Kreiselinstrument“) schon einmal gesehen haben. Hier ist trotzdem eine kleine Illustration eines physikalischen Kreiselinstruments (von der englischen Wikipedia-Seite):
Wie Sie sehen, kann es sich um alle drei Achsen X, Y, und Z drehen (ähnlich wie der Accelerometer, den wir in Day #11 of the 31 Days of Windows Phone behandelt haben). Während der Accelerometer Beschleunigung misst, dient das Gyroskop der Bestimmung der Drehgeschwindigkeit.
Ein Telefon enthält natürlich nicht einen physikalischen Kreisel wie er oben abgebildet ist. Telefone benutzen ein sogenanntes MEMS Gyroskop. Diese Sensoren nutzen in der Regel Vibrationen oder Resonanz zur Bestimmung der Drehgeschwindigkeit.
Das Gyroskop benutzen
Das Gyroskop ist prinzipiell so einfach zu benutzen wie der Accelerometer. Im Gegensatz zum Accelerometer haben wir allerdings den Nachteil, dass es kein Simulations-Werkzeug im Emulator gibt. Das Gyroskop misst Drehgeschwindigkeit und liefert diese Daten in Radian pro Sekunde.
Mit diesem Sensor lässt sich die aktuelle Ausrichtung des Telefons also präziser und „weicher“ bestimmen. Besonders nützlich kann das werden, wenn man Augmented Reality Anwendungen baut. Allerdings wird man in den meisten Fällen gar nicht direkt auf das Gyroskop zugreifen. Das hat folgende Gründe:
- Nicht alle Windows Phones haben ein Gyroskop. Nur Geräte, die nach Mango erschienen sind können ein Gyroskop verbaut haben und sogar nach Mango bleibt dieser Sensor eine optionale Hardwarekomponente.
- Microsoft hat eine Motion Klasse entwickelt, die die Daten des Accelerometers, des Kompasses und des eventuell vorhandenen Gyroskops in einer API vereint und die damit wesentlich praktischer in der Benutzung ist (diese Klasse werden wir morgen behandeln). Wenn Sie an der aktuellen Lage (also Neigung, Gierung und Drehung) des Geräts interessiert sind, ist es sinnvoller, sich auf die Motion Klasse zu konzentrieren.
Wenn man dennoch direkten Zugriff auf das Gyroskop unabhängig von der Motion Klasse braucht, sollte man immer überprüfen, ob das aktuelle Gerät diesen Sensor überhaupt unterstützt. Hierfür brauchen wir zwei Stückchen Code. Erstens fügen wir ein using Statement für den Microsoft.Phone.Sensors Namespace hinzu. Zweitens brauchen wir ein if Statement, welches den Wert von Gyroscope.IsSupported überprüft. Bisher sieht unsere Code-behind Datei also so aus:
using System; using Microsoft.Phone.Controls; using Microsoft.Devices.Sensors; using Microsoft.Xna.Framework; namespace Day5_Gyroscope { public partial class MainPage : PhoneApplicationPage { public MainPage() { InitializeComponent(); if (Gyroscope.IsSupported) { // DO SOMETHING } } } }
Jetzt müssen wir nur noch die Stelle mit dem Kommentar „DO SOMETHING“ mit Leben füllen. Dazu definieren wir uns zunächst eine Benutzerschnittstelle, die die Daten des Gyroskops darstellen wird.
In der obigen Benutzerschnittstelle haben wir drei TextBlock Elemente, welche uns die Rohdaten ausgeben werden und drei Linien, welche jeweils den Ausschlag eines der Werte repräsentieren werden. Um diese Oberfläche nachzubauen, nutzen Sie das folgende XAML in Ihrer Seite:
<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="31 DAYS OF MANGO" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="gyroscope" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock Height="30" HorizontalAlignment="Left" Margin="20,100,0,0" Name="xTextBlock" Text="X: 1.0" VerticalAlignment="Top" Foreground="Red" FontSize="28" FontWeight="Bold"/> <TextBlock Height="30" HorizontalAlignment="Center" Margin="0,100,0,0" Name="yTextBlock" Text="Y: 1.0" VerticalAlignment="Top" Foreground="Yellow" FontSize="28" FontWeight="Bold"/> <TextBlock Height="30" HorizontalAlignment="Right" Margin="0,100,20,0" Name="zTextBlock" Text="Z: 1.0" VerticalAlignment="Top" Foreground="Blue" FontSize="28" FontWeight="Bold"/> <Line x:Name="xLine" X1="240" Y1="350" X2="340" Y2="350" Stroke="Red" StrokeThickness="4"></Line> <Line x:Name="yLine" X1="240" Y1="350" X2="240" Y2="270" Stroke="Yellow" StrokeThickness="4"></Line> <Line x:Name="zLine" X1="240" Y1="350" X2="190" Y2="400" Stroke="Blue" StrokeThickness="4"></Line> <TextBlock Height="30" HorizontalAlignment="Center" Margin="6,571,6,0" Name="statusTextBlock" Text="" VerticalAlignment="Top" Width="444" /> </Grid> </Grid>
Im folgenden Codebeispiel überprüfen wir zunächst, ob das Gyroskop von der Hardware unterstüzt wird, indem wir Gyroscope.IsSupported abfragen. Danach erstellen wir ein neues Gyroscope Objekt und einen Event Handler für CurrentValueChanged.
using System; using Microsoft.Phone.Controls; using Microsoft.Devices.Sensors; using Microsoft.Xna.Framework; namespace Day5_Gyroscope { public partial class MainPage : PhoneApplicationPage { Gyroscope g; public MainPage() { InitializeComponent(); if (Gyroscope.IsSupported) { g = new Gyroscope(); g.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20); g.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<GyroscopeReading>>(g_CurrentValueChanged); g.Start(); } else statusTextBlock.Text = "gyroscope not supported"; } void g_CurrentValueChanged(object sender, SensorReadingEventArgs<GyroscopeReading> e) { Dispatcher.BeginInvoke(() => UpdateUI(e.SensorReading)); } private void UpdateUI(GyroscopeReading gyroscopeReading) { statusTextBlock.Text = "getting data"; Vector3 rotationReading = gyroscopeReading.RotationRate; xTextBlock.Text = "X " + rotationReading.X.ToString("0.00"); yTextBlock.Text = "Y " + rotationReading.Y.ToString("0.00"); zTextBlock.Text = "Z " + rotationReading.Z.ToString("0.00"); xLine.X2 = xLine.X1 + rotationReading.X * 200; yLine.Y2 = yLine.Y1 - rotationReading.Y * 200; zLine.X2 = zLine.X1 - rotationReading.Z * 100; zLine.Y2 = zLine.Y1 + rotationReading.Z * 100; } } }
Wie schon beim Kompass feuert der Event Handler des Gyroskops sobald nach der in TimeBetweenUpdates festgelegten Wartezeit ein neuer Wert festgestellt wurde. In unserem Beispiel werden wir also Aktualisierungen nicht öfter bekommen als alle 20 Millisekunden.
Sie werden möglicherweise über diese Zeile gestolpert sein:
Dispatcher.BeginInvoke(() => UpdateUI(e.SensorReading));
Der Grund für diese Zeile ist, dass der Event Handler nicht auf dem UI Thread aufgerufen wird um diesen nicht zu blockieren. Um also die Benutzeroberfläche zu aktualisieren, müssen wir erst wieder den UI Thread benachrichtigen (mit Hilfe der Methode Dispatcher.BeginInvoke) (Anm. leitning: dieser Absatz lautet im Orginalartikel anders. Ich habe hier geschrieben, warum meiner Meinung nach Dispatcher.BeginInvoke aufgerufen wird und lasse mich gerne eines Besseren belehren).
Wir übergeben das ganze GyroscopeReading Objekt an die Methode UpdateUI (Anm. leitning: welche auf dem UI Thread ausgeführt wird). Dieses Objekt erlaubt uns, die Werte von X, Y und Z aus dem Vector3 der RotationRate Eigenschaft auszulesen. Wir zeigen die Werte in den TextBlock Feldern an. Die eigentlich coole Visualisierung passiert allerdings über die Line Elemente, die wir zuvor im XAML erstellt haben.
Jede der Linien soll jeweils einen der Datenpunkte repräsentieren (die rote Linie ist für X, die gelbe vertikale Linie repräsentiert Y und die blaue diagonale Linie steht für Z). Die Länge einer Linie soll jeweils die Rotationsgeschwindigkeit des Geräts darstellen. Bei jedem Aufruf der Methode UpdateUI verlängern oder verkürzen wir die Linien entsprechend der Daten des Gyroskops. Damit erhalten wir einen Eindruck davon, welcher Rotation unser Gerät gerade ausgesetzt ist.
Bitte bedenken Sie, dass der Beispielcode dieses Artikels nur auf einem Gerät laufen wird, welches auch ein Gyroskop eingebaut hat. Der Emulator sowie alle Windows Phones der ersten Generation haben diesen Sensor nicht. Hier ist ein kleines Video von einem Gerät mit einem Gyroskop:
Zusammenfassung
Das Gyroskop ist ein praktischer kleiner Sensor. Er liefert uns ein sehr präzises Bild der Bewegung des Geräts im Raum. Das kann besonders für Augmented Reality Anwendungen nützlich sein. Wenn Sie die Beispielanwendung dieses Artikels herunterladen möchten, drücken Sie auf den Download Code Button unten:
Microsoft hat in Windows Phone 7.5 eine neue Klasse mit dem Namen Motion eingeführt. Diese vereint die Daten des Gyroskops, des Accelerometers und des Kompasses und liefert dadurch Daten mit erstaunlicher Genauigkeit. Die Motion Klasse wird Gegenstand des morgigen Artikels sein. Wir werden diese Klasse im Detail behandeln und uns beispielsweise anschauen, wie man die aktuelle Lage (also Neigung, Gierung und Drehung) des Geräts ermitteln kann.
Bis dahin!
4 Kommentare
Hallo,
welches Gerät ist das auf dem Video?
Das HTC Titan scheint mir leider das einzige WP7 Smartphone zu sein welches ein Gyroskop verbaut hat oder täusche ich mich da? Das auf dem video sieht nämich deutlich kleiner aus…
Ich weiß auch nicht, welches Gerät da im Video zu sehen ist. In den Kommentaren zum Originalartikel schreibt Jeff, dass das HTC Titan und das Samsung Focus S ein Gyroskop haben müssten.
Welche Genauigkeit ist mit dem Kompass auf einem OMNIA7 zu erreichen? Genauer als die Anzeige „10Grad“ habe ich noch nie geschafft. Ist das das Ende der Möglichkeiten?
Hi Uwe,
ich habe selber ein Omnia 7 und bei mir funktioniert der Kompass überhaupt nicht — auch wenn ich eine der Kompass Apps aus dem Marketplace ausprobiere. Vielleicht ist das ja ein generelles Problem beim Omnia 7.