Android センサーの TYPE_GRAVITY でもう少し遊ぶ

Android センサーの TYPE_GRAVITY でも少し遊ぶと何が違う? 「う」が違う。

正規重力やら重力異常なんか普通興味ないよね。重力加速度が測れてるなら「水準器もどき」でしょ、やっぱし。

ほれ:

android.txt
1 title=Gravity Sensor Demo
2 author=hhsprings
3 orientation=all

ほれ:

gravity_sensor.py (前回あった abs_value は消してある)
 1 # -*- coding: utf-8 -*-
 2 from copy import deepcopy
 3 from jnius import PythonJavaClass, java_method, autoclass, cast
 4 from plyer.platforms.android import activity
 5 from kivy.logger import Logger
 6 
 7 Context = autoclass('android.content.Context')
 8 Sensor = autoclass('android.hardware.Sensor')
 9 SensorManager = autoclass('android.hardware.SensorManager')
10 
11 class _SensorListener(PythonJavaClass):
12     __javainterfaces__ = ['android/hardware/SensorEventListener']
13 
14     def __init__(self, sensor_manager, sensor_type):
15         super(_SensorListener, self).__init__()
16         self.SensorManager = sensor_manager
17         self.sensor = self.SensorManager.getDefaultSensor(sensor_type)
18         self.values = None
19 
20     def enable(self):
21         self.SensorManager.registerListener(self, self.sensor,
22             SensorManager.SENSOR_DELAY_NORMAL)
23 
24     def disable(self):
25         self.SensorManager.unregisterListener(self, self.sensor)
26 
27     @java_method('(Landroid/hardware/SensorEvent;)V')
28     def onSensorChanged(self, event):
29         self.values = deepcopy(event.values)
30 
31     @java_method('(Landroid/hardware/Sensor;I)V')
32     def onAccuracyChanged(self, sensor, accuracy):
33         # Maybe, do something in future?
34         pass
35 
36 
37 class GravitySensor(object):
38     def __init__(self):
39         self.SensorManager = cast('android.hardware.SensorManager',
40             activity.getSystemService(Context.SENSOR_SERVICE))
41         self._bState = False
42 
43     def enable(self):
44         if not self._bState:
45             self._listener = _SensorListener(
46                 self.SensorManager, Sensor.TYPE_GRAVITY)
47             self._listener.enable()
48             #
49             self._bState = True
50 
51     def disable(self):
52         if self._bState:
53             self._bState = False
54             #
55             self._listener.disable()
56             del self._listener
57 
58     @property
59     def values(self):
60         if self._bState and self._listener.values:
61             return self._listener.values[:3]
62 
63     def __del__(self):
64         if self._bState:
65             self._disable()
66         super(self.__class__, self).__del__()

ほれ:

main.py (いつもどおり雑ですまんの)
  1 # -*- coding: utf-8 -*-
  2 import math
  3 from kivy.lang import Builder
  4 from kivy.app import App
  5 from kivy.clock import Clock, mainthread
  6 from kivy.properties import StringProperty
  7 from kivy.uix.boxlayout import BoxLayout
  8 from kivy.graphics import Color, Line, Ellipse
  9 from plyer import gps
 10 from gravity_sensor import GravitySensor
 11 grav_sensor = GravitySensor()
 12 
 13 kv = '''
 14 <GravityDemo>:
 15     orientation: 'vertical'
 16 
 17     face: face
 18     detail_doc: detail_doc
 19 
 20     Widget:
 21         id: face
 22         r: (min(root.size[0], root.size[1] - detail_doc.height)) / 2
 23         canvas.after:
 24             Color:
 25                 rgba: 1, 1, 1, 0.1
 26             Ellipse:
 27                 size: self.size     
 28                 pos: self.pos
 29 
 30     RstDocument:
 31         id: detail_doc
 32         text: root.result
 33         size_hint: 1, None
 34         height: 600
 35 '''
 36 Builder.load_string(kv)
 37 
 38 class GravityDemo(BoxLayout):
 39     result = StringProperty()
 40     lon = None
 41     lat = None
 42     alt = None
 43 
 44     def __init__(self):
 45         super(GravityDemo, self).__init__()
 46 
 47         grav_sensor.enable()
 48         gps.configure(on_location=self.on_location,
 49                            on_status=self.on_status)
 50         gps.start()
 51         Clock.schedule_interval(self.do_interval, 1./10)
 52 
 53     @mainthread
 54     def on_location(self, **kwargs):
 55         #self.lon = float(kwargs['lon'])
 56         self.lat = float(kwargs['lat'])
 57         #self.alt = float(kwargs['altitude'])
 58 
 59     @mainthread
 60     def on_status(self, stype, status):
 61         pass
 62 
 63     def do_interval(self, *args, **kwargs):
 64         if self.lat is None:
 65             return
 66 
 67         gv = grav_sensor.values
 68         g = math.sqrt(gv[0]**2 + gv[1]**2 + gv[2]**2)
 69 
 70         self.face.canvas.clear()
 71 
 72         with self.face.canvas:
 73             Color(0.7, 0.2, 0.2)
 74             pos = (
 75                 self.face.center_x - self.face.r * gv[0] / g,
 76                 self.face.center_y - self.face.r * gv[1] / g
 77                 )
 78             Line(points=[
 79                     self.face.center_x, self.face.center_y,
 80                     pos[0], pos[1]
 81                     ], width=5, cap="round")
 82             ellips_r = 25
 83             Ellipse(pos=[pos[0] - ellips_r,
 84                          pos[1] - ellips_r],
 85                     size=[ellips_r * 2, ellips_r * 2])
 86             sc = math.sqrt(gv[0]**2 + gv[1]**2)
 87             if sc > g / 3:
 88                 x, y = gv[0] / sc, gv[1] / sc
 89                 rx = x * math.cos(math.pi / 2) - y * math.sin(math.pi / 2)
 90                 ry = x * math.sin(math.pi / 2) + y * math.cos(math.pi / 2)
 91                 Color(0.2, 0.2, 0.7)
 92                 Line(points=[
 93                         self.face.center_x - self.face.r * rx,
 94                         self.face.center_y - self.face.r * ry,
 95 
 96                         self.face.center_x + self.face.r * rx,
 97                         self.face.center_y + self.face.r * ry
 98                         ], width=2, cap="round")
 99 
100         # Theoretical gravity (using GRS80)
101         # g(\phi)= 9.780327 \left(1+0.0053024\sin^2(\phi) - 0.0000058\sin^2(2 \phi) \right)\;[\frac{m}{s^2}]
102         gth = 9.780327 * (
103             1.0 + 0.0053024 * math.sin(math.radians(self.lat))**2 - \
104                 0.0000058 * math.sin(math.radians(2 * self.lat))**2)
105 
106         self.result = """
107 * latitude: {}
108 * observed gravity: {:.6f}
109 
110   * X: {:.6f}
111   * Y: {:.6f}
112   * Z: {:.6f}
113 
114 * theoretical gravity (using GRS80): {:.6f}
115 * gravity anomaly: {:.6f}
116 """.format(self.lat, g, gv[0], gv[1], gv[2], gth, g - gth)
117 
118 
119 class GravityDemoApp(App):
120     def build(self):
121         return GravityDemo()
122 
123 
124 if __name__ == '__main__':
125     GravityDemoApp().run()

ので:

ひたすらにかっちょ悪い GUI だが、気になるなら自分で直しなはれ。

水準器ね、ワタシもたまにこれは欲しいのでいいんだけどね、「正規重力と重力異常」はワタシにとってはオモロイのねん。ので相変わらず表示しとる。普通こんなん興味なかろうから、いらないなら自分で消したまえよ。