LoginSignup
11
10

More than 5 years have passed since last update.

Pythonista3で、motionセンサのデータをリアルタイム描画

Last updated at Posted at 2017-05-03

前回はscenkitを使って、ipadに合わせて直方体をグルグルさせましたが、
今回はmotionセンサで取得したデータをグラフ表示させてみます。
Pythonistaのuiを使って、pitch,roll,yawの遷移グラフとscenkitを使ったiPadの動きと連動した直方体を表示させます。
IMG_0346.JPG

pyuiのイメージは次のような画面です。
IMG_0347.JPG
サブviewとしてimage viewのimageview1とcustom viewのview2を用意します。
加速度、ジャイロ、磁気センサ表示用のtextBoxも準備しておきます。
今回、textboxの名前は、加速度は、ax,ay,az、ジャイロはgx,gy,gz、磁気センサはmx,my,mzにしています。

描画用のソースは以下のとおり。

motion_graph.py
# coding: utf-8
# For use in pythonista on iOS
from objc_util import *
import ui
import motion
from scene import *
import math
import numpy as np
import time
import ioView
import matplotlib.pyplot as plt
import Image
import sys
import os
from matplotlib.ticker import *
#boxの大きさ
scale = 40
W=3
L=1.5
H=0.5/2

pitch,roll,yaw=0.0,0.0,0.0
ax,ay,az=0.0,0.0,0.0
gx,gy,gz=0.0,0.0,0.0
mgx,mgy,mgz=0.0,0.0,0.0
load_framework('SceneKit')
SCNView, SCNScene, SCNBox, SCNText, SCNNode, SCNLight, SCNCamera, SCNAction, SCNTransaction,UIFont= map(ObjCClass, ['SCNView', 'SCNScene', 'SCNBox', 'SCNText', 'SCNNode', 'SCNLight',  'SCNCamera', 'SCNAction','SCNTransaction','UIFont'])
class SCNVector3 (Structure):
    _fields_ = [('x', c_float), ('y', c_float), ('z', c_float)]

@on_main_thread
class Sceneobj(object):
  def __init__(self):
    self.name = ""
  def make_view(self,mv):
    global pitch,roll,yaw
    global box_node
    self.main_view=mv
    main_view_objc = ObjCInstance(main_view['view2'])
    scene_view = SCNView.alloc().initWithFrame_options_(((0, 0),(400, 400)), None).autorelease()
    scene_view.setAutoresizingMask_(18)
    scene_view.setAllowsCameraControl_(True)
    scene = SCNScene.scene()
    root_node = scene.rootNode()  

    box= SCNBox.boxWithWidth_height_length_chamferRadius_(W, L, H, 0)
    box_node = SCNNode.nodeWithGeometry_(box)
    box_node.setPosition_((0, 1, 0))

    light_node = SCNNode.node()
    light_node.setPosition_((1.5, 1.5, 1.5))
    light = SCNLight.light()
    light.setType_('omni')
    light.setCastsShadow_(True)
    light.setColor_(UIColor.blueColor().CGColor())
    light_node.setLight_(light)

    camera = SCNCamera.camera()
    camera_node = SCNNode.node()
    camera_node.setCamera(camera)
    camera_node.setPosition((0, 0, 5))

    root_node.addChildNode_(camera_node)
    root_node.addChildNode_(box_node)
    root_node.addChildNode_(light_node)

    box_node.runAction_(SCNAction.rotateToX_y_z_duration_(math.pi*pitch/180, math.pi*roll/180, math.pi*yaw/180,0))
    scene_view.setScene_(scene)
    main_view_objc.addSubview_(scene_view)

class MyScene (Scene):
    def setup(self):
        global fig,ax1
        #motionセンサスタート
        motion.start_updates()
        # data initial
        self.py = [pitch for i in range(0, 60)]      # pitch array setup
        self.ry = [roll for i in range(0, 60)]       # roll array setupr
        self.yy = [yaw for i in range(0, 60)]        # yaw array setup
        self.xl = [i for i in range(0, 60)]          # x_line
        # graph set up -------------------------#
        ymin=-180
        ymax=180
        fig = plt.figure()                      # graphics setup
        ax1 = fig.add_subplot(111)              # 
        ax1.grid(True)                          # axis
        plt.ylim(ymin, ymax)
    def draw(self):
        global box_node,box
        global pitch,roll,yaw,ax,ay,az,gx,gy,gz
        global main_view
        global ax1,fig
        #処理が追い付かないのでタイマーをいれる
        #time.sleep(0.01)
        #加速度、ジャイロの値を更新
        ax,ay,az = motion.get_user_acceleration()
        gx,gy,gz= motion.get_gravity()
        gravity_vectors=motion.get_attitude()
        mgx,mgy,mgz,mga=motion.get_magnetic_field()

        pitch, roll, yaw = [x for x in gravity_vectors]
        # ラジアン→度へ変換
        pitch=-pitch*180/3.1415926
        roll=roll*180/3.1415926
        yaw=-yaw*180/3.1415926
        #再描画
        box_node.runAction_(SCNAction.rotateToX_y_z_duration_(math.pi*pitch/180, math.pi*roll/180,-math.pi*yaw/180,0))
        #加速度、ジャイロ、地磁気センサーの値を表示
        main_view['ax'].text=str(round(ax,2))
        main_view['ay'].text=str(round(ay,2))
        main_view['az'].text=str(round(az,2))

        main_view['gx'].text=str(round(gx,2))
        main_view['gy'].text=str(round(gy,2))
        main_view['gz'].text=str(round(gz,2))        

        main_view['mx'].text=str(round(mgx,2))
        main_view['my'].text=str(round(mgy,2))
        main_view['mz'].text=str(round(mgz,2))        
        # graphics
        self.py.pop(0); self.ry.pop(0); self.yy.pop(0)                # left
        self.py.append(pitch); self.ry.append(roll); self.yy.append(yaw)# add data

        ax1.plot(self.xl, self.py, color='lightgreen', lw='1')   # pitch graph
        ax1.plot(self.xl, self.ry, color='red', lw='1')          # roll graph
        ax1.plot(self.xl, self.yy, color='skyblue', lw='1')      # yaw graph        

        plt.savefig('rt.png')       # save the graph on the consolen
        main_view['imageview1'].image = ui.Image.named('rt.png') # imageview
        plt.cla()                   # clear graph
        plt.close()                 # close graph
        fig = plt.figure()          #
        ax1 = fig.add_subplot(111)  #
        ax1.grid(True)
        ymin=-180
        ymax=180
        plt.ylim(ymin, ymax)
if __name__ == "__main__":
    main_view = ui.load_view()
    main_view.name = 'Motion plot Demo'
    my_scene = MyScene()
    scene_view = SceneView(frame=main_view.bounds, flex='WH')
    main_view['view2'].add_subview(scene_view)
    scene_view.scene = my_scene
    scene_kit=Sceneobj()
    scene_kit.make_view(main_view)
    main_view.present('sheet')

リアルタイムグラフの作成は、macsbugさんのDisplay the graph on the iPadを参考にコーディングしました。
ほぼほぼコピペです。
Matplotlibでの描画が画像を保存して、再表示なので遅いです。

次回はGenuino101のimuとbleを使って遊びたいと思います。

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10