omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    interactive animation based on orientation data of IMU

    Pythonista
    7
    36
    12174
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • cvp
      cvp @ccc last edited by

      @ccc getting the data is easy.
      But I don't know anything about the Bluetooth part transmit/receive

      1 Reply Last reply Reply Quote 0
      • ccc
        ccc last edited by

        http://omz-software.com/pythonista/docs/ios/cb.html

        cvp 1 Reply Last reply Reply Quote 0
        • cvp
          cvp @ccc last edited by

          @ccc yes, I know and understand but I don't have any experience with it

          1 Reply Last reply Reply Quote 0
          • mikael
            mikael @ccc last edited by

            @ccc, would suggest multipeer for that. Uses bluetooth without the need to think about it.

            1 Reply Last reply Reply Quote 2
            • cvp
              cvp @ccc last edited by cvp

              @ccc said:

              What would be cool would be to have two Pythonista scripts.

              The iPhone script would get the pitch, yaw, and roll of the iPhone and transmit that over Bluetooth.
              The iPad script could use those Bluetooth signals to change the angel of the airplane on the iPad screen.

              Pitch, yaw and roll of iDevice + AirPlane, but not Bluetooth, nor WiFi
              You can turn the device and pinch/rotate the image

              Dirty (more than usual, believe me) and (not so) quick, but for the fun

              from objc_util import *
              import ctypes
              import ui
              from math import pi
              from ImageColor import getrgb
              import threading
              from random import random
              
              load_framework('SceneKit')
              
              SCNView, SCNScene, SCNBox, SCNPyramid, SCNCone, SCNCylinder, SCNSphere, SCNPlane, SCNNode, SCNMaterial, SCNCamera, SCNLight, SCNAction, SCNLookAtConstraint = map(ObjCClass, ['SCNView', 'SCNScene', 'SCNBox', 'SCNPyramid', 'SCNCone', 'SCNCylinder', 'SCNSphere', 'SCNPlane', 'SCNNode', 'SCNMaterial', 'SCNCamera', 'SCNLight', 'SCNAction',  'SCNLookAtConstraint' ])
              
              class CMRotationRate (Structure):
              	_fields_ = [('x', c_double), ('y', c_double), ('z', c_double)]
              
              class my_thread_bt(threading.Thread):
              	def __init__(self, geometry_node):
              		threading.Thread.__init__(self)
              		self.name = 'bt'
              		self.stop = False
              		self.geometry_node = geometry_node
              	def run(self):
              		pitch = 0
              		yaw   = 0
              		roll  = 0
              		delta_ang = pi/10
              		SCNTransaction = ObjCClass('SCNTransaction').alloc()
              		# https://forum.omz-software.com/topic/3030
              		CMMotionManager = ObjCClass('CMMotionManager').alloc().init()
              		#print(CMMotionManager.isDeviceMotionAvailable())
              		CMMotionManager.startGyroUpdates()
              		while True:
              			# EulerAngles is a SCNVector3
              			# The order of components in this vector matches the axes of rotation:
              			# Pitch (the x component) is the rotation about the node’s x-axis.
              			# Yaw (the y component) is the rotation about the node’s y-axis.
              			# Roll (the z component) is the rotation about the node’s z-axis.
              			#pitch += (random() - 0.5) * delta_ang	
              			#yaw   += (random() - 0.5) * delta_ang	
              			#roll  += (random() - 0.5) * delta_ang 
              			gyro_data = CMMotionManager.gyroData()
              			if not gyro_data:
              				#print('data not available (yet?)')
              				continue
              			# Using the custom struct here:
              			rate = gyro_data.rotationRate(argtypes=[], restype=CMRotationRate)
              			# You can now access the struct's fields as x, y, z:
              			roll  = rate.z
              			pitch = rate.x
              			yaw   = rate.y
              			#print(rate.x, rate.y, rate.z)
              
              			# change euler angles but by using animation
              			SCNTransaction.begin()
              			SCNTransaction.setAnimationDuration(0.3)
              			self.geometry_node.setEulerAngles((pitch, yaw, roll))
              			SCNTransaction.commit()
              			if self.stop:
              				break
              		CMMotionManager.stopGyroUpdates()
              		CMMotionManager.release()
              
              class MyView(ui.View):
               ###@on_main_thread
               def __init__(self,w,h):
                self.width = w
                self.height = h
                self.name = 'SceneKit IMU'
                self.background_color = 'white'
                
                main_view_objc = ObjCInstance(self)
                scene_view = SCNView.alloc().initWithFrame_options_(((0, 0),(self.width,self.height)), None).autorelease()
                scene_view.setAutoresizingMask_(18)
                scene_view.setAllowsCameraControl_(True)
                #scene_view.setDebugOptions_(0xFFFF)
                main_view_objc.addSubview_(scene_view)
                
                scene = SCNScene.scene()
                scene_view.setScene_(scene)
                
                root_node = scene.rootNode()
                
                camera = SCNCamera.camera()
                camera_node = SCNNode.node()
                camera_node.setCamera(camera)
                camera_node.setPosition((-35,35,35))
                root_node.addChildNode_(camera_node) 
                
                # build an image with text to use as material on wing: begin
                l = 40
                r = 2
                h = 3*15	# 3 x height of text
                sc = h / (2*pi*r)
                w = l*sc
                h = 2*pi*r*sc
                with ui.ImageContext(w,h) as ctx:
                  path = ui.Path.rect(0,0,w,h)
                  ui.set_color('blue')
                  path.fill()
                  x = w/10
                  y = h/3
                  t = 'Pytho'
                  ui.draw_string(t, rect=(x, y, 8*w/10, 2+h/3), font=('<System-Bold>',15), color='white', alignment=ui.ALIGN_LEFT)
                  x = 6*w/10
                  t = 'nista'
                  ui.draw_string(t, rect=(x, y, 8*w/10, 2+h/3), font=('<System-Bold>',15), color='white', alignment=ui.ALIGN_LEFT)
                  ui_image = ctx.get_image()
                  #ui_image.show()
                Material_pyth = SCNMaterial.material()
                Material_pyth.contents = ObjCInstance(ui_image)
                # build an image with text to use as material on wing: end
                
                # build an image with text to use as material on cockpit: begin
                l = 40
                r = 2
                h = 3*15	# 3 x height of text
                sc = h / (2*pi*r)
                w = l*sc
                h = 2*pi*r*sc
                with ui.ImageContext(w,h) as ctx:
                  path = ui.Path.rect(0,0,w,h)
                  ui.set_color('gray')
                  path.fill()
                  x = w/2 - 15/2 - 2
                  y = h/3
                  path1 = ui.Path.rect(x, y, 20, 2+h/3)
                  ui.set_color('lightgray')
                  path1.fill()
                  t = '👨‍✈️'
                  ui.draw_string(t, rect=(x, y, 20, 2+h/3), font=('<System-Bold>',15), color='white', alignment=ui.ALIGN_LEFT)
                  ui_image = ctx.get_image()
                  #ui_image.show()
                Material_nose = SCNMaterial.material()
                Material_nose.contents = ObjCInstance(ui_image)
                # build an image with text to use as material on cockpit: end
                
                # build an image with text to use as material on vertical stabilizer: begin
                w = 22
                h = 17
                with ui.ImageContext(w,h) as ctx:
                  path = ui.Path.rect(0,0,w,h)
                  ui.set_color((0.17, 0.6, 0.0))
                  path.fill()
                  x = 8
                  y = 0
                  t = 'V'
                  ui.draw_string(t, rect=(x, y, w, h), font=('<System-Bold>',15), color='white', alignment=ui.ALIGN_LEFT)
                  ui_image = ctx.get_image()
                  #ui_image.show()
                Material_icon1 = SCNMaterial.material()
                Material_icon1.contents = ObjCInstance(ui_image)
                # build an image with text to use as material on vertical stabilizer: end
                
                # build an image with text to use as material on vertical stabilizer: begin
                w = 22
                h = 17
                with ui.ImageContext(w,h) as ctx:
                  path = ui.Path.rect(0,0,w,h)
                  ui.set_color((0.17, 0.6, 0.0))
                  path.fill()
                  x = 3
                  y = 0
                  t = 'Λ'
                  ui.draw_string(t, rect=(x, y, w, h), font=('<System-Bold>',15), color='white', alignment=ui.ALIGN_LEFT)
                  ui_image = ctx.get_image()
                  #ui_image.show()
                Material_icon2 = SCNMaterial.material()
                Material_icon2.contents = ObjCInstance(ui_image)
                # build an image with text to use as material on vertical stabilizer: end
                
                geometry = SCNCylinder.cylinderWithRadius_height_(r,l)
                lc = l/10
                cone = SCNCone.coneWithTopRadius_bottomRadius_height_(r,r/2,lc)
                sphe = SCNSphere.sphereWithRadius_(r/2)
                wing = SCNBox.boxWithWidth_height_length_chamferRadius_(20*r, 2*r, 0.3, 0)
                vert = SCNBox.boxWithWidth_height_length_chamferRadius_(2*r, r, 0.3, 0)
                hori = SCNBox.boxWithWidth_height_length_chamferRadius_(3*r, r*0.6, 0.3, 0)
                mot1 = SCNCylinder.cylinderWithRadius_height_(r*0.3,r*2)
                mot2 = SCNCylinder.cylinderWithRadius_height_(r*0.3,r*2)
                 
                cone_node = SCNNode.nodeWithGeometry_(cone)
                sphe_node = SCNNode.nodeWithGeometry_(sphe)
                wing_node = SCNNode.nodeWithGeometry_(wing)
                vert_node = SCNNode.nodeWithGeometry_(vert)
                hori_node = SCNNode.nodeWithGeometry_(hori)
                mot1_node = SCNNode.nodeWithGeometry_(mot1)
                mot2_node = SCNNode.nodeWithGeometry_(mot2)
              
                tx,ty,tz = (0,l/2+lc/2,0)
                x = (1,0,0,0, 0,1,0,0, 0,0,1,0, tx,ty,tz,1)
                cone_node.setPivot_(x)
                tx,ty,tz = (0,l/2+lc,0)
                x = (1,0,0,0, 0,1,0,0, 0,0,1,0, tx,ty,tz,1)
                sphe_node.setPivot_(x)
                geometry_node = SCNNode.nodeWithGeometry_(geometry)
                geometry_node.addChildNode_(cone_node)
                geometry_node.addChildNode_(sphe_node)
                geometry_node.addChildNode_(wing_node)
                
                # vertical stabilizer: rotation 90° around axe y
                tx,ty,tz = (2*r,-l/2+r/2,0)
                x = (0,0,1,0, 0,1,0,0, -1,0,0,0, tx,ty,tz,1)
                vert_node.setPivot_(x)
                geometry_node.addChildNode_(vert_node)
                
                tx,ty,tz = (0,-l/2+r*0.4,-r*1.5)
                x = (1,0,0,0, 0,1,0,0, 0,0,1,0, tx,ty,tz,1)
                hori_node.setPivot_(x)
                geometry_node.addChildNode_(hori_node)
                
                tx,ty,tz = (5*r,-0.2,0.5)
                x = (1,0,0,0, 0,1,0,0, 0,0,1,0, tx,ty,tz,1)
                mot1_node.setPivot_(x)
                geometry_node.addChildNode_(mot1_node)
                
                tx,ty,tz = (-5*r,-0.2,0.5)
                x = (1,0,0,0, 0,1,0,0, 0,0,1,0, tx,ty,tz,1)
                mot2_node.setPivot_(x)
                geometry_node.addChildNode_(mot2_node)
                
                root_node.addChildNode_(geometry_node)
                
                # cylinder horizontal: rotation 90° around axe x
                x = (1,0,0,0, 0,0,1,0, 0,-1,0,0, 0,0,0,1) 
                geometry_node.setPivot_(x)	
                			
                Materials = []
                colors = ['red','gray','gray','yellow','orange','gray','lightgray']
                for i in range(0,6):
                  rgb = getrgb(colors[i])
                  r,g,b = tuple(c/255.0 for c in rgb)
                  Material = SCNMaterial.material()
                  Material.contents = ObjCClass('UIColor').colorWithRed_green_blue_alpha_(r,g,b,1.0)
                  Materials.append(Material)
                geometry.setMaterials_(Materials)
                cone.setMaterial_(Material_nose)
                #cone.setMaterials_(Materials[3:5])
                sphe.setMaterials_(Materials[4:5])
                hori.setMaterial_(Materials[1])
                mot1.setMaterials_(Materials)
                mot2.setMaterials_(Materials)
                wing_Materials = [Material_pyth,Materials[1],Material_pyth]+[Materials[1]]*3
                wing.setMaterials_(wing_Materials)
                vert_Materials = [Material_icon2,Materials[1],Material_icon1]+[Materials[1]]*3
                vert.setMaterials_(vert_Materials)
              
                # Add a constraint to the camera to keep it pointing to the target geometry
                constraint = SCNLookAtConstraint.lookAtConstraintWithTarget_(geometry_node)
                constraint.gimbalLockEnabled = True
                camera_node.constraints = [constraint]
                
                light_node = SCNNode.node()
                light_node.setPosition_((30, 0, -30))
                light = SCNLight.light()
                #light.setType_('spot')
                light.setType_('probe')
                #light.setType_('directional')
                light.setCastsShadow_(True)
                light.setColor_(UIColor.whiteColor().CGColor())
                light_node.setLight_(light)
                root_node.addChildNode_(light_node)
                
                thread_bt = my_thread_bt(geometry_node)
                thread_bt.start()
                
               def will_close(self):
               	for t in threading.enumerate():
               		if t.name == 'bt':
               			t.stop = True
               			return
              
              def main():	
              	w, h = ui.get_screen_size()
              	MainView = MyView(w, h)
              	MainView.present('fullscreen', hide_title_bar=False)
              	
              # Protect against import	
              if __name__ == '__main__':
                main()
              
              1 Reply Last reply Reply Quote 0
              • cvp
                cvp @ccc last edited by cvp

                @ccc said:

                the angel of the airplane

                I hope it's its guardian angel 😀 (humor, not mockery)

                1 Reply Last reply Reply Quote 1
                • ccc
                  ccc last edited by ccc

                  LOL... I read @mikael ‘s impressive multipeer this morning and then wrote the iPhone piece of the two iOS device idea that I mentioned above. If you add multipeer to your code above, the angle (but perhaps not the angel) of the plane ✈️ on the iPad will react to iPhone movements.
                  https://github.com/cclauss/Ten-lines-or-less/blob/master/attitude_to_multipeer.py

                  cvp 2 Replies Last reply Reply Quote 0
                  • cvp
                    cvp @ccc last edited by

                    @ccc Did you try my script on only one iDevice , it reacts to its movements.
                    I always only work on my iPad because my iPhone is very old and slow (iPhone 5s) but if you want, I could spend some time tomorrow to try what you say.

                    1 Reply Last reply Reply Quote 0
                    • cvp
                      cvp @ccc last edited by cvp

                      @ccc Done, thanks to marvelous multipeer of @mikael.
                      I use your attitude_to_multipeer.py on my iPhone and my script modified to get infos from iPhone on my iPad, source here

                      mikael 1 Reply Last reply Reply Quote 0
                      • pavlinb
                        pavlinb last edited by

                        It’s great how community supports Pythonista live.

                        1 Reply Last reply Reply Quote 1
                        • mikael
                          mikael @cvp last edited by

                          @cvp, @ccc, ah, this begs for a dogfight game — two controller iPhones and an iPad mirrored to Apple TV.

                          cvp 1 Reply Last reply Reply Quote 0
                          • cvp
                            cvp @mikael last edited by

                            @mikael wooow, a full game is a too long work for me but I would be available to help with little parts

                            1 Reply Last reply Reply Quote 0
                            • mikael
                              mikael @Guest last edited by

                              @adomanim, ”easy” might be a relative term here, but if you have a skeleton model, moving arms and legs could be accomplished with SceneKit and Inverse Kinematics constraints (and again, @pulbrich’s SceneKit wrapper).

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post
                              Powered by NodeBB Forums | Contributors