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
    12136
    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 @pulbrich last edited by

      @pulbrich it seems, yes 😀

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

        Hi guys, thank you soo much for your support. I need some time to go through the code, because I want to understand it. Thank you soo much and don't worry @cvp it is perfectly okay.

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

          @ProgrammingGo please try this one, automatic (instead of manual) simulation of Bluetooth values and using continuous animation

          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, SCNNode, SCNMaterial, SCNCamera, SCNLight, SCNAction, SCNLookAtConstraint = map(ObjCClass, ['SCNView', 'SCNScene', 'SCNBox', 'SCNNode', 'SCNMaterial', 'SCNCamera', 'SCNLight', 'SCNAction',  'SCNLookAtConstraint' ])
          
          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()
          		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
          			# change euler angles but by an animation
          			SCNTransaction.begin()
          			SCNTransaction.setAnimationDuration(0.3)
          			self.geometry_node.setEulerAngles((pitch, yaw, roll))
          			SCNTransaction.commit()
          			if self.stop:
          				break
          
          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)
            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((-30,30,30))
            root_node.addChildNode_(camera_node) 
            
            geometry = SCNBox.boxWithWidth_height_length_chamferRadius_(10, 10, 10, 0)
             
            geometry_node = SCNNode.nodeWithGeometry_(geometry)
            root_node.addChildNode_(geometry_node)
            
            Materials = []
            colors = ['red','blue','green','yellow','orange','pink']
            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)
          
            # 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()
          
          ProgrammingGo 1 Reply Last reply Reply Quote 0
          • ProgrammingGo
            ProgrammingGo @cvp last edited by

            @cvp Hi cvp thank you soo much. I will give a look on that. Thank you for your time. If I will have questions I will write here. I am thinking that it would be better to use quaternions instead of euler angler to avoid gimbal lock. I think there should be a lib for that, right?

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

              @ProgrammingGo said:

              I think there should be a lib for that

              I suppose but I really don't know anything about that.

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

                okay, I will give a trial. What for me is unclear is how I can map the sensor values to the graphic. I mean I know that I have a referential coordinate system and based on that my sensor is moving, but it is not clear how to do it.

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

                  @ProgrammingGo Euler angles are orientation data of your object (here a cube) versus the 3 axes, thus SceneKit geometry node is easy to orientate.

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

                    @cvp you don’t need a separate thread with all the overhead to update the scene objects. There is the scene renderer delegate (can be the same class instance as your main), which has an 'update' method to take care of exactly these type of tasks.

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

                      @pulbrich Thanks, the thread was for the Bluetooth listening, here simulated

                      1 Reply Last reply Reply Quote 1
                      • pulbrich
                        pulbrich @ProgrammingGo last edited by

                        @ProgrammingGo if you ever need to penetrate the domain of various coordinate system representations (angles included) I recommend you look at Pyrr

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

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

                          1. The iPhone script would get the pitch, yaw, and roll of the iPhone and transmit that over Bluetooth.
                          2. The iPad script could use those Bluetooth signals to change the angel of the airplane on the iPad screen.
                          cvp mikael 4 Replies Last reply Reply Quote 0
                          • 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
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors