Introduction to Kivy

Objective: create a simple Kivy using the Pong Game Tutorial.


In [3]:
%%file kivy_pong.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ReferenceListProperty,\
    ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock
from random import randint

class PongPaddle(Widget):
    score = NumericProperty(0)
    
    def bounce_ball(self, ball):
        if self.collide_widget(ball):
            vx, vy = ball.velocity
            offset = (ball.center_y - self.center_y) / (self.height / 2)
            bounced = Vector(-1 * vx, vy)
            vel = bounced * 1.1
            ball.velocity = vel.x, vel.y + offset

class PongBall(Widget):
    velocity_x = NumericProperty(0)
    velocity_y = NumericProperty(0)
    velocity = ReferenceListProperty(velocity_x, velocity_y)
    
    def move(self):
        self.pos = Vector(*self.velocity) + self.pos
        
class PongGame(Widget):
    ball = ObjectProperty(None)
    player1 = ObjectProperty(None)
    player2 = ObjectProperty(None)
#     square = ObjectProperty(None)
    
    def serve_ball(self, vel=(4, 0)):
        self.ball.center = self.center
        self.ball.velocity = Vector(4, 0).rotate(randint(0, 360))
 
    def update(self, dt):
        # Call ball.move and other stuff.
        self.ball.move()
#         self.square.move()
        
        # Bounce of paddles.
        self.player1.bounce_ball(self.ball)
        self.player2.bounce_ball(self.ball)
        
        # Bounce off top or bottom.
        if (self.ball.y < self.y) or (self.ball.top > self.top):
            self.ball.velocity_y *= -1

            
        # Went off to side to score point.
        if self.ball.x < self.x:
            self.player2.score += 1
            self.serve_ball(vel=(4, 0))
        if self.ball.x > self.width:
            self.player1.score += 1
            self.serve_ball(vel=(-4, 0))
            
    def on_touch_move(self, touch):
        if touch.x < self.width / 3:
            self.player1.center_y = touch.y
        if touch.x > self.width - self.width / 3:
            self.player2.center_y = touch.y
        
            
class PongApp(App):
    def build(self):
        game = PongGame()
        game.serve_ball()
        Clock.schedule_interval(game.update, 1.0 / 60.0)
        return game
    
if __name__ == "__main__":
    PongApp().run()


Overwriting kivy_pong.py

In [6]:
%%file pong.kv
#:kivy 1.0.9

<PongBall>:
    size: 50, 50
    canvas:
        Color:
            rgb: 1, 1, 0.2
        Ellipse:
            pos: self.pos
            size: self.size
                
<PongPaddle>:
    size: 25, 200
    canvas:
        Color:
            rgb: 1, 1, 1
        Rectangle:
            pos: self.pos
            size: self.size

<PongGame>:
    ball: pong_ball
    player1: player_left
    player2: player_right

    canvas.before:
        Color:
            rgba: 0.1, 1, 0.1, 0.5
        Rectangle:
            pos: self.pos
            size: self.size
    
    canvas:
        Color:
            rgb: 1, 1, 1
        Rectangle:
            pos: self.center_x - 5, 0
            size: 10, self.height
                
    Label:
        font_size: 40
        center_x: root.width / 4
        top: root.top - 10
        text: "Player 1: " + str(root.player1.score)
            
    Label:
        font_size: 40
        center_x: root.width * 3 / 4
        top: root.top - 10  
        text: "Player 2: " + str(root.player2.score)
            
    PongBall:
        id: pong_ball
        center: self.parent.center
            
    PongPaddle:
        id: player_left
        x: root.x
        center_y: root.center_y
            
    PongPaddle:
        id: player_right
        x: root.width - self.width
        center_y: root.center_y


Overwriting pong.kv

In [7]:
!kivy kivy_pong.py


[INFO              ] Kivy v1.8.0
[INFO              ] [Logger      ] Record log in /Users/mikemcfarlane/.kivy/logs/kivy_14-05-08_50.txt
[INFO              ] [Factory     ] 157 symbols loaded
[DEBUG             ] [Cache       ] register <kv.lang> with limit=None, timeout=Nones
[DEBUG             ] [Cache       ] register <kv.image> with limit=None, timeout=60s
[DEBUG             ] [Cache       ] register <kv.atlas> with limit=None, timeout=Nones
[INFO              ] [Image       ] Providers: img_imageio, img_tex, img_dds, img_pygame, img_gif (img_pil ignored)
[DEBUG             ] [Cache       ] register <kv.texture> with limit=1000, timeout=60s
[DEBUG             ] [Cache       ] register <kv.shader> with limit=1000, timeout=3600s
[DEBUG             ] [App         ] Loading kv <./pong.kv>
[DEBUG             ] [Window      ] Ignored <egl_rpi> (import error)
[INFO              ] [Window      ] Provider: pygame(['window_egl_rpi'] ignored)
[DEBUG             ] [Window      ] Display driver Quartz
[DEBUG             ] [Window      ] Actual window size: 800x600
[DEBUG             ] [Window      ] Actual color bits r8 g8 b8 a8
[DEBUG             ] [Window      ] Actual depth bits: 24
[DEBUG             ] [Window      ] Actual stencil bits: 8
[DEBUG             ] [Window      ] Actual multisampling samples: 2
[INFO              ] [GL          ] OpenGL version <2.1 ATI-1.20.11>
[INFO              ] [GL          ] OpenGL vendor <ATI Technologies Inc.>
[INFO              ] [GL          ] OpenGL renderer <AMD Radeon HD 6750M OpenGL Engine>
[INFO              ] [GL          ] OpenGL parsed version: 2, 1
[INFO              ] [GL          ] Shading version <1.20>
[INFO              ] [GL          ] Texture max size <16384>
[INFO              ] [GL          ] Texture max units <16>
[DEBUG             ] [Shader      ] Fragment compiled successfully
[DEBUG             ] [Shader      ] Vertex compiled successfully
[DEBUG             ] [ImageImageIO] Load </Applications/Kivy.app/Contents/Resources/kivy/kivy/data/glsl/default.png>
[INFO              ] [GL          ] BGRA texture support is available
[INFO              ] [Window      ] virtual keyboard not allowed, single mode, not docked
[INFO              ] [Text        ] Provider: pygame
[INFO              ] [OSC         ] using <multiprocessing> for socket
[DEBUG             ] [Base        ] Create provider from mouse
[INFO              ] [Base        ] Start application main loop
[INFO              ] [GL          ] NPOT texture support is available
[INFO              ] [Base        ] Leaving application in progress...

A paint app!

A simple paint app from the paint app tutorial.


In [1]:
%%file paint.py
from random import random
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Ellipse, Line

class MyPaintWidget(Widget):

	def on_touch_down(self, touch):
		print "touch: ", touch
		color = (random(), 1, 1)
		
		with self.canvas:
			Color(*color, mode = 'hsv')
			d = 30.
			Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size = (d, d))
			touch.ud['line'] = Line(points = (touch.x, touch.y))
			
	def on_touch_move(self, touch):
		touch.ud['line'].points += [touch.x, touch.y]

	def on_touch_up(self, touch):
		color = (random(), 1, 1)

		with self.canvas:
			Color(*color, mode = 'hsv')
			d = 30.
			Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size = (d, d))
		
class MyPaintApp(App):

	def build(self):
		parent = Widget()
		painter = MyPaintWidget()
		clearbtn = Button(text='Clear')
		parent.add_widget(painter)
		parent.add_widget(clearbtn)

		def clear_canvas(obj):
			painter.canvas.clear()
		
		clearbtn.bind(on_release=clear_canvas)

		return parent

if __name__ == "__main__":
	MyPaintApp().run()


Overwriting paint.py

In [1]:
!kivy paint.py


[INFO              ] Kivy v1.8.0
[INFO              ] [Logger      ] Record log in /Users/mikemcfarlane/.kivy/logs/kivy_14-05-15_12.txt
[INFO              ] [Factory     ] 157 symbols loaded
[DEBUG             ] [Cache       ] register <kv.lang> with limit=None, timeout=Nones
[DEBUG             ] [Cache       ] register <kv.image> with limit=None, timeout=60s
[DEBUG             ] [Cache       ] register <kv.atlas> with limit=None, timeout=Nones
[INFO              ] [Image       ] Providers: img_imageio, img_tex, img_dds, img_pygame, img_gif (img_pil ignored)
[DEBUG             ] [Cache       ] register <kv.texture> with limit=1000, timeout=60s
[DEBUG             ] [Cache       ] register <kv.shader> with limit=1000, timeout=3600s
[INFO              ] [Text        ] Provider: pygame
[DEBUG             ] [App         ] Loading kv <./mypaint.kv>
[DEBUG             ] [App         ] kv <./mypaint.kv> not found
[DEBUG             ] [Window      ] Ignored <egl_rpi> (import error)
[INFO              ] [Window      ] Provider: pygame(['window_egl_rpi'] ignored)
[DEBUG             ] [Window      ] Display driver Quartz
[DEBUG             ] [Window      ] Actual window size: 800x600
[DEBUG             ] [Window      ] Actual color bits r8 g8 b8 a8
[DEBUG             ] [Window      ] Actual depth bits: 24
[DEBUG             ] [Window      ] Actual stencil bits: 8
[DEBUG             ] [Window      ] Actual multisampling samples: 2
[INFO              ] [GL          ] OpenGL version <2.1 ATI-1.20.11>
[INFO              ] [GL          ] OpenGL vendor <ATI Technologies Inc.>
[INFO              ] [GL          ] OpenGL renderer <AMD Radeon HD 6750M OpenGL Engine>
[INFO              ] [GL          ] OpenGL parsed version: 2, 1
[INFO              ] [GL          ] Shading version <1.20>
[INFO              ] [GL          ] Texture max size <16384>
[INFO              ] [GL          ] Texture max units <16>
[DEBUG             ] [Shader      ] Fragment compiled successfully
[DEBUG             ] [Shader      ] Vertex compiled successfully
[DEBUG             ] [ImageImageIO] Load </Applications/Kivy.app/Contents/Resources/kivy/kivy/data/glsl/default.png>
[INFO              ] [GL          ] BGRA texture support is available
[INFO              ] [Window      ] virtual keyboard not allowed, single mode, not docked
[INFO              ] [OSC         ] using <multiprocessing> for socket
[DEBUG             ] [Base        ] Create provider from mouse
[INFO              ] [Base        ] Start application main loop
[INFO              ] [GL          ] NPOT texture support is available
[DEBUG             ] [Atlas       ] Load </Applications/Kivy.app/Contents/Resources/kivy/kivy/data/../data/images/defaulttheme.atlas>
[DEBUG             ] [Atlas       ] Need to load 1 images
[DEBUG             ] [Atlas       ] Load </Applications/Kivy.app/Contents/Resources/kivy/kivy/data/../data/images/defaulttheme-0.png>
[DEBUG             ] [ImageImageIO] Load </Applications/Kivy.app/Contents/Resources/kivy/kivy/data/../data/images/defaulttheme-0.png>
touch:  <MouseMotionEvent spos=(0.29, 0.5233333333333333) pos=(231.99999999999997, 314.0)>
touch:  <MouseMotionEvent spos=(0.3225, 0.2616666666666667) pos=(258.0, 157.00000000000003)>
touch:  <MouseMotionEvent spos=(0.16, 0.3733333333333333) pos=(128.0, 223.99999999999997)>
touch:  <MouseMotionEvent spos=(0.26, 0.5716666666666667) pos=(208.0, 343.0)>
touch:  <MouseMotionEvent spos=(0.3625, 0.77) pos=(290.0, 462.0)>
touch:  <MouseMotionEvent spos=(0.70625, 0.5033333333333334) pos=(565.0, 302.00000000000006)>
touch:  <MouseMotionEvent spos=(0.1625, 0.4733333333333334) pos=(130.0, 284.00000000000006)>
[INFO              ] [Base        ] Leaving application in progress...

NAO plays pong

Let's get NAO and Kivy working together using proxies.


In [12]:
%%file nao_pong.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ReferenceListProperty,\
    ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.core.audio import SoundLoader

from random import randint
from time import sleep

from naoqi import ALProxy


NAO_IP = "mistcalf.local"
# Setup animatedSpeech.
BODYLANGUAGEMODECONFIG = {"bodyLanguageMode" : "contextual"}

tts = None
animatedSpeech = None
robotMotion = None

class NAOPongPaddle(Widget):
    score = NumericProperty(0)

    sound1 = SoundLoader.load('Sounds/bipReco1.wav')
    sound2 = SoundLoader.load('Sounds/bipReco2.wav')
    
    def bounce_ball(self, ball):
        print "ball:", self.player_id
        
        if self.collide_widget(ball):
            vx, vy = ball.velocity
            offset = (ball.center_y - self.center_y) / (self.height / 2)
            bounced = Vector(-1 * vx, vy)
            vel = bounced * 1.1
            ball.velocity = vel.x, vel.y + offset
            self.sound1.play()

class NAOPongBall(Widget):
    velocity_x = NumericProperty(0)
    velocity_y = NumericProperty(0)
    velocity = ReferenceListProperty(velocity_x, velocity_y)
    
    def move(self):
        self.pos = Vector(*self.velocity) + self.pos
        

class NAOPongGame(Widget):
    ball = ObjectProperty(None)
    player1 = ObjectProperty(None)
    player_nao = ObjectProperty(None)

    global tts
    
    def serve_ball(self, vel=(4, 0)):
        self.ball.center = self.center
        self.ball.velocity = Vector(4, 0).rotate(randint(0, 360))
    
    def update(self, dt):
        # Call ball.move and other stuff.
        self.ball.move()
  
        # Bounce of paddles.
        self.player1.bounce_ball(self.ball)
        self.player_nao.bounce_ball(self.ball)
        
        # Bounce off top or bottom.
        if (self.ball.y < self.y) or (self.ball.top > self.top):
            self.ball.velocity_y *= -1
            
        # Went off to side to score point.
        if self.ball.x < self.x:
            id = animatedSpeech.post.say("I win!", BODYLANGUAGEMODECONFIG)
            animatedSpeech.wait(id, 0)
            self.player_nao.score += 1
            self.serve_ball(vel=(4, 0))
        if self.ball.x > self.width:
            id = animatedSpeech.post.say("Ouch", BODYLANGUAGEMODECONFIG)
            animatedSpeech.wait(id, 0)
            self.player1.score += 1
            self.serve_ball(vel=(-4, 0))

        #print "ball.x: {}, x: {}, ball.y: {}, y: {}".format(self.ball.x, self.x, self.ball.y, self.y)
            
    def on_touch_move(self, touch):
        if touch.x < self.width / 3:
            self.player1.center_y = touch.y
        if touch.x > self.width - self.width / 3:
            self.player_nao.center_y = touch.y
        
            
class NAOPongApp(App):
    def build(self):
        game = NAOPongGame()
        game.serve_ball()
        Clock.schedule_interval(game.update, 1.0 / 60.0)
        return game

def NAO_setup():
    """ Setup NAO inc proxies.

    """
    # Define globals for holding proxies.
    global tts
    global animatedSpeech
    global robotMotion

    # Setup proxies.
    try:
        tts = ALProxy("ALTextToSpeech", NAO_IP, 9559)
    except Exception, e:
        print "Could not setup tts, error: ", e
    try:
        animatedSpeech = ALProxy("ALAnimatedSpeech", NAO_IP, 9559)
    except Exception, e:
        print "Could not setup animatedSpeech, error: ", e
    try:
        robotMotion = ALProxy("ALMotion", NAO_IP, 9559)
    except Exception, e:
        print "Could not setup robotMotion, error: ", e

    # Wake NAO up.
    robotMotion.wakeUp()

def NAO_instructions():
    """ Provides game instructions.

    """
    global tts

    id = animatedSpeech.post.say("We are going to play ping pong. I play on the right, you play on the left.", BODYLANGUAGEMODECONFIG)
    animatedSpeech.wait(id, 0)
    sleep(1.0)

def main():
    NAO_setup()
    #NAO_instructions()
    NAOPongApp().run()
    
if __name__ == "__main__":
    main()


Overwriting nao_pong.py

In [11]:
%%file NAOPong.kv
#:kivy 1.0.9

<NAOPongBall>:
    size: 50, 50
    canvas:
        Color:
            rgb: 1, 1, 0.2
        Ellipse:
            pos: self.pos
            size: self.size
                
<NAOPongPaddle>:
    size: 25, 200
    canvas:
        Color:
            rgb: 1, 1, 1
        Rectangle:
            pos: self.pos
            size: self.size

<NAOPongGame>:
    ball: pong_ball
    player1: player_left
    player_nao: player_right

    canvas.before:
        Color:
            rgba: 0.1, 1, 0.1, 0.5
        Rectangle:
            pos: self.pos
            size: self.size
    
    canvas:
        Color:
            rgb: 1, 1, 1
        Rectangle:
            pos: self.center_x - 5, 0
            size: 10, self.height
                
    Label:
        font_size: 40
        center_x: root.width / 4
        top: root.top - 10
        text: "You: " + str(root.player1.score)
            
    Label:
        font_size: 40
        center_x: root.width * 3 / 4
        top: root.top - 10  
        text: "NAO: " + str(root.player_nao.score)
            
    NAOPongBall:
        id: pong_ball
        center: self.parent.center
            
    NAOPongPaddle:
        id: player_left
        x: root.x
        center_y: root.center_y
        player_id: 5
            
    NAOPongPaddle:
        id: player_right
        x: root.width - self.width
        center_y: root.center_y
        player_id: 6


Overwriting NAOPong.kv

In [10]:
!kivy nao_pong.py


[INFO              ] Kivy v1.8.0
[INFO              ] [Logger      ] Record log in /Users/mikemcfarlane/.kivy/logs/kivy_14-05-08_51.txt
[INFO              ] [Factory     ] 157 symbols loaded
[DEBUG             ] [Cache       ] register <kv.lang> with limit=None, timeout=Nones
[DEBUG             ] [Cache       ] register <kv.image> with limit=None, timeout=60s
[DEBUG             ] [Cache       ] register <kv.atlas> with limit=None, timeout=Nones
[INFO              ] [Image       ] Providers: img_imageio, img_tex, img_dds, img_pygame, img_gif (img_pil ignored)
[DEBUG             ] [Cache       ] register <kv.texture> with limit=1000, timeout=60s
[DEBUG             ] [Cache       ] register <kv.shader> with limit=1000, timeout=3600s
[I] 3343 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 3343 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 3343 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://169.254.197.226:64522
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://192.168.0.6:64522
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:64522
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.22:64522
Could not setup tts, error:  	ALBroker::createBroker
	Cannot connect to tcp://mistcalf.local:9559
[I] 3343 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://169.254.197.226:64523
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://192.168.0.6:64523
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:64523
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.22:64523
Could not setup animatedSpeech, error:  	ALBroker::createBroker
	Cannot connect to tcp://mistcalf.local:9559
[I] 3343 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://169.254.197.226:64524
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://192.168.0.6:64524
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:64524
[I] 3343 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.22:64524
[W] 4355 qimessaging.transportsocket: resolved: Host not found (authoritative)
Could not setup robotMotion, error:  	ALBroker::createBroker
	Cannot connect to tcp://mistcalf.local:9559
 Traceback (most recent call last):
   File "nao_pong.py", line 132, in <module>
     main()
   File "nao_pong.py", line 127, in main
     NAO_setup()
   File "nao_pong.py", line 114, in NAO_setup
     robotMotion.wakeUp()
 AttributeError: 'NoneType' object has no attribute 'wakeUp'

How can NAO move with the bat?

There are three ways to control NAO motion:

Cartesian control is the obvious starter.

It is worth knowing the axes from cartesian control pages and dimensions from NAO H-25 dimensions.


In [21]:
from IPython.core.display import Image
Image(filename='Images/frame_definition.png')


Out[21]:

In [22]:
Image(filename='Images/hardware_overview3_3.png')


Out[22]:

To do next:

  1. get sound working. - DONE
  2. add restart button - DONE
  3. add motion
  4. get a quit button to quit game and safely shut NAO down

Example of cartesian control using almotion_cartesianTorsoArm1.py example


In [37]:
%%file almotion_cartesianTorsoArm1.py
'''Cartesian control: Multiple Effector Trajectories ***'''

import argparse
import motion
import almath
from naoqi import ALProxy

def main(robotIP, PORT=9559):
    ''' Simultaneously control three effectors:
    the Torso, the Left Arm and the Right Arm
    Warning: Needs a PoseInit before executing
    '''

    motionProxy  = ALProxy("ALMotion", robotIP, PORT)
    postureProxy = ALProxy("ALRobotPosture", robotIP, PORT)

    # Wake up robot
    motionProxy.wakeUp()

    # Send robot to Stand Init
    postureProxy.goToPosture("StandInit", 0.5)

    frame      = motion.FRAME_WORLD
    coef       = 0.5                   # motion speed
    times      = [coef, 2.0*coef, 3.0*coef, 4.0*coef]
    useSensorValues = False

    # Relative movement between current and desired positions
    dy         = +0.03                 # translation axis Y (meters)
    dz         = -0.03                 # translation axis Z (meters)
    dwx        = +8.0*almath.TO_RAD   # rotation axis X (radians)

    # Motion of Torso with post process
    effector   = "Torso"

    path = []
    initTf = almath.Transform(motionProxy.getTransform(effector, frame, useSensorValues))
    # point 1
    deltaTf  = almath.Transform(0.0, -dy, dz)*almath.Transform().fromRotX(-dwx)
    targetTf = initTf*deltaTf
    path.append(list(targetTf.toVector()))

    # point 2
    path.append(list(initTf.toVector()))

    # point 3
    deltaTf  = almath.Transform(0.0, dy, dz)*almath.Transform().fromRotX(dwx)
    targetTf = initTf*deltaTf
    path.append(list(targetTf.toVector()))

    # point 4
    path.append(list(initTf.toVector()))

    axisMask   = almath.AXIS_MASK_ALL  # control all the effector axes
    motionProxy.post.transformInterpolations(effector, frame, path,
                                           axisMask, times)

    # Motion of Arms with block process
    frame     = motion.FRAME_TORSO
    axisMask  = almath.AXIS_MASK_VEL  # control just the position
    times     = [1.0*coef, 2.0*coef]  # seconds

    # Motion of Right Arm during the first half of the Torso motion
    effector  = "RArm"

    path = []
    currentTf = motionProxy.getTransform(effector, frame, useSensorValues)
    targetTf  = almath.Transform(currentTf)
    targetTf.r1_c4 += 0.01 # x ?
    targetTf.r2_c4 -= 0.08 # y
    path.append(list(targetTf.toVector()))
    path.append(currentTf)

    motionProxy.transformInterpolations(effector, frame, path, axisMask, times)

    # Motion of Left Arm during the last half of the Torso motion
    effector   = "RArm"

    path = []
    currentTf = motionProxy.getTransform(effector, frame, useSensorValues)
    targetTf  = almath.Transform(currentTf)
    targetTf.r2_c4 += 0.08 # y
    path.append(list(targetTf.toVector()))
    path.append(currentTf)

    motionProxy.transformInterpolations(effector, frame, path, axisMask, times)

    # Go to rest position
    motionProxy.rest()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip", type=str, default="mistcalf.local",
                        help="Robot ip address")
    parser.add_argument("--port", type=int, default=9559,
                        help="Robot port number")

    args = parser.parse_args()
    main(args.ip, args.port)


Overwriting almotion_cartesianTorsoArm1.py

In [38]:
!python almotion_cartesianTorsoArm1.py


[I] 4359 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 4359 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 4359 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://169.254.210.28:52942
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://192.168.0.9:52942
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:52942
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.14:52942

A nice smooth cartesian example of hula hoop motion


In [40]:
%%file almotion_hulaHoop.py
# -*- encoding: UTF-8 -*-

'''Motion: Hula Hoop ***'''

import argparse
import motion
import almath
from naoqi import ALProxy

def main(robotIP, PORT=9559):
    '''
         Example showing a Hula Hoop Motion
         with the NAO cartesian control of torso
    '''

    motionProxy  = ALProxy("ALMotion", robotIP, PORT)
    postureProxy = ALProxy("ALRobotPosture", robotIP, PORT)

    # end initialize proxy, begin go to Stand Init

    # Wake up robot
    motionProxy.wakeUp()

    # Send robot to Stand Init
    postureProxy.goToPosture("StandInit", 0.5)

    # end go to Stand Init, begin define control point
    effector        = "RArm"
    frame           =  motion.FRAME_ROBOT
    axisMask        = almath.AXIS_MASK_ALL
    isAbsolute      = True
    useSensorValues = False

    currentTf = almath.Transform(motionProxy.getTransform(effector, frame, useSensorValues))

    # end define control point, begin define target

    # Define the changes relative to the current position
    dx         = 0.03                    # translation axis X (meter)
    dy         = 0.03                    # translation axis Y (meter)
    dwx        = 8.0*almath.TO_RAD       # rotation axis X (rad)
    dwy        = 8.0*almath.TO_RAD       # rotation axis Y (rad)

    # point 01 : forward  / bend backward
    target1Tf = almath.Transform(currentTf.r1_c4, currentTf.r2_c4, currentTf.r3_c4)
    target1Tf *= almath.Transform(dx, 0.0, 0.0)
    target1Tf *= almath.Transform().fromRotY(-dwy)

    # point 02 : right    / bend left
    target2Tf = almath.Transform(currentTf.r1_c4, currentTf.r2_c4, currentTf.r3_c4)
    target2Tf *= almath.Transform(0.0, -dy, 0.0)
    target2Tf *= almath.Transform().fromRotX(-dwx)

    # point 03 : backward / bend forward
    target3Tf = almath.Transform(currentTf.r1_c4, currentTf.r2_c4, currentTf.r3_c4)
    target3Tf *= almath.Transform(-dx, 0.0, 0.0)
    target3Tf *= almath.Transform().fromRotY(dwy)

    # point 04 : left     / bend right
    target4Tf = almath.Transform(currentTf.r1_c4, currentTf.r2_c4, currentTf.r3_c4)
    target4Tf *= almath.Transform(0.0, dy, 0.0)
    target4Tf *= almath.Transform().fromRotX(dwx)

    path = []
    path.append(list(target1Tf.toVector()))
    path.append(list(target2Tf.toVector()))
    path.append(list(target3Tf.toVector()))
    path.append(list(target4Tf.toVector()))

    path.append(list(target1Tf.toVector()))
    path.append(list(target2Tf.toVector()))
    path.append(list(target3Tf.toVector()))
    path.append(list(target4Tf.toVector()))

    path.append(list(target1Tf.toVector()))
    path.append(list(currentTf.toVector()))

    timeOneMove  = 0.5 #seconds
    times = []
    for i in range(len(path)):
        times.append((i+1)*timeOneMove)

    # end define target, begin call motion api

    # call the cartesian control API

    motionProxy.transformInterpolations(effector, frame, path, axisMask, times)

    # Go to rest position
    motionProxy.rest()

    # end script

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip", type=str, default="mistcalf.local",
                        help="Robot ip address")
    parser.add_argument("--port", type=int, default=9559,
                        help="Robot port number")

    args = parser.parse_args()
    main(args.ip, args.port)


Overwriting almotion_hulaHoop.py

In [41]:
!python almotion_hulaHoop.py


[I] 4359 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 4359 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 4359 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://169.254.210.28:52991
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://192.168.0.9:52991
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:52991
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.14:52991

Prefered control with whole body balancer with multiple efeectors example almotion_wbMultipleEffectors.py


In [42]:
%%file almotion_wbMultipleEffectors.py
# -*- encoding: UTF-8 -*-

''' Whole Body Motion: Multiple Effectors control ***'''

import argparse
import motion
import almath
import time
from naoqi import ALProxy

def main(robotIP, PORT=9559):
    '''
        Example of a whole body multiple effectors control "LArm", "RArm" and "Torso"
        Warning: Needs a PoseInit before executing
                 Whole body balancer must be inactivated at the end of the script
    '''

    motionProxy  = ALProxy("ALMotion", robotIP, PORT)
    postureProxy = ALProxy("ALRobotPosture", robotIP, PORT)

    # end initialize proxy, begin go to Stand Init

    # Wake up robot
    motionProxy.wakeUp()

    # Send robot to Stand Init
    postureProxy.goToPosture("StandInit", 0.5)

    # end go to Stand Init, begin initialize whole body

    # Enable Whole Body Balancer
    isEnabled  = True
    motionProxy.wbEnable(isEnabled)

    # Legs are constrained fixed
    stateName  = "Fixed"
    supportLeg = "Legs"
    motionProxy.wbFootState(stateName, supportLeg)

    # Constraint Balance Motion
    isEnable   = True
    supportLeg = "Legs"
    motionProxy.wbEnableBalanceConstraint(isEnable, supportLeg)

    # end initialize whole body, define arms motions

    isAbsolute   = True
    useSensorValues = False

    # Arms motion
    effectorList = ["LArm", "RArm"]

    frame        = motion.FRAME_ROBOT

    # pathLArm
    pathLArm = []
    currentTf = motionProxy.getTransform("LArm", frame, useSensorValues)
    # 1
    target1Tf  = almath.Transform(currentTf)
    target1Tf.r1_c4 += 0.00 # x?
    target1Tf.r2_c4 += 0.00 # y
    target1Tf.r3_c4 += 0.00 # z

    # 2
    target2Tf  = almath.Transform(currentTf)
    target2Tf.r1_c4 += 0.20 # x?
    target2Tf.r2_c4 -= 0.00 # y
    target2Tf.r3_c4 += 0.20 # z

    pathLArm.append(list(target1Tf.toVector()))
    pathLArm.append(list(target2Tf.toVector()))
    pathLArm.append(list(target1Tf.toVector()))
    pathLArm.append(list(target2Tf.toVector()))
    pathLArm.append(list(target1Tf.toVector()))

    # pathRArm
    pathRArm = []
    currentTf = motionProxy.getTransform("RArm", frame, useSensorValues)
    # 1
    target1Tf  = almath.Transform(currentTf)
    target1Tf.r1_c4 += 0.00 # x?
    target1Tf.r2_c4 += 0.00 # y
    target1Tf.r3_c4 += 0.00 # z

    # 2
    target2Tf  = almath.Transform(currentTf)
    target2Tf.r1_c4 += 0.00 # x?
    target2Tf.r2_c4 -= 0.20 # y
    target2Tf.r3_c4 += 0.20 # z

    pathRArm.append(list(target1Tf.toVector()))
    pathRArm.append(list(target2Tf.toVector()))
    pathRArm.append(list(target1Tf.toVector()))
    pathRArm.append(list(target2Tf.toVector()))
    pathRArm.append(list(target1Tf.toVector()))
    pathRArm.append(list(target2Tf.toVector()))

    pathList = [pathLArm, pathRArm]

    axisMaskList = [almath.AXIS_MASK_VEL, # for "LArm"
                    almath.AXIS_MASK_VEL] # for "RArm"

    coef       = 1.5
    timesList  = [ [coef*(i+1) for i in range(5)],  # for "LArm" in seconds
                   [coef*(i+1) for i in range(6)] ] # for "RArm" in seconds

    # called cartesian interpolation
    motionProxy.transformInterpolations(effectorList, frame, pathList, axisMaskList, timesList)

    # end define arms motions, define torso motion

    # # Torso Motion
    # effectorList = ["Torso", "LArm", "RArm"]

    # dy = 0.06
    # dz = 0.06

    # # pathTorso
    # currentTf = motionProxy.getTransform("Torso", frame, useSensorValues)
    # # 1
    # target1Tf  = almath.Transform(currentTf)
    # target1Tf.r2_c4 += dy
    # target1Tf.r3_c4 -= dz

    # # 2
    # target2Tf  = almath.Transform(currentTf)
    # target2Tf.r2_c4 -= dy
    # target2Tf.r3_c4 -= dz

    # pathTorso = []
    # for i in range(3):
    #     pathTorso.append(list(target1Tf.toVector()))
    #     pathTorso.append(currentTf)
    #     pathTorso.append(list(target2Tf.toVector()))
    #     pathTorso.append(currentTf)

    # pathLArm = [motionProxy.getTransform("LArm", frame, useSensorValues)]
    # pathRArm = [motionProxy.getTransform("RArm", frame, useSensorValues)]

    # pathList = [pathTorso, pathLArm, pathRArm]

    # axisMaskList = [almath.AXIS_MASK_ALL, # for "Torso"
    #                 almath.AXIS_MASK_VEL, # for "LArm"
    #                 almath.AXIS_MASK_VEL] # for "RArm"

    # coef       = 0.5
    # timesList  = [
    #               [coef*(i+1) for i in range(12)], # for "Torso" in seconds
    #               [coef*12],                       # for "LArm" in seconds
    #               [coef*12]                        # for "RArm" in seconds
    #              ]

    # motionProxy.transformInterpolations(effectorList, frame, pathList, axisMaskList, timesList)

    # # end define torso motion, disable whole body

    # Deactivate whole body
    isEnabled    = False
    motionProxy.wbEnable(isEnabled)

    # Send robot to Pose Init
    postureProxy.goToPosture("StandInit", 0.3)

    # Go to rest position
    motionProxy.rest()

    # end script

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip", type=str, default="mistcalf.local",
                        help="Robot ip address")
    parser.add_argument("--port", type=int, default=9559,
                        help="Robot port number")

    args = parser.parse_args()
    main(args.ip, args.port)


Overwriting almotion_wbMultipleEffectors.py

Notes:

  • r1_c4 = x-axis
  • r2_c4 = y-axis
  • r3_c4 = z-axis

With:

frame        = motion.FRAME_ROBOT
target1Tf.r1_c4 += 0.00 # x
target1Tf.r2_c4 += 0.00 # y
target1Tf.r3_c4 += 0.00 # z

Is essentially the standinit pose with arm slightly bent and out front.


In [43]:
!python almotion_wbMultipleEffectors.py


[I] 4359 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 4359 qimessaging.session: Session listener created on tcp://0.0.0.0:0
[I] 4359 qi.eventloop: Creating event loop while no qi::Application() is running
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://169.254.210.28:53023
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://192.168.0.9:53023
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://127.0.0.1:53023
[I] 4359 qimessaging.transportserver: TransportServer will listen on: tcp://10.137.0.14:53023

In [ ]: