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()
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
In [7]:
!kivy kivy_pong.py
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()
In [1]:
!kivy paint.py
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()
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
In [10]:
!kivy nao_pong.py
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:
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)
In [38]:
!python almotion_cartesianTorsoArm1.py
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)
In [41]:
!python almotion_hulaHoop.py
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)
Notes:
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
In [ ]: