Kivy clocks issue(something doubles every time) - python

So my problem is that whenever i create a new game by create_game() method something strange happens and everything starts to move 2 times faster i think it is due to a Clock issue but i am not sure. My question is what can i do to make it run in normal pace. Here is code:
def create_game(self):
for i in range(1,11):
for j in range(15):
brick = Brick(pos = [self.width/15*j,self.height - self.height/30*i - self.height/6], size_hint = [1/15,1/30] )
a = random.randint(1,3)
if(a!=3):
self.brick_container.add_widget(brick)
ball = Ball(pos = (self.paddle.center_x, self.paddle.height + 1), size_hint = [None,None], size = [self.width/50,self.width/50])
self.ball_container.add_widget(ball)
self.game_on_pause = True
self.update()
def serve_ball(self):
self.ball_container.children[0].velocity = Vector(3,3)
if(len(self.ball_container.children) == 0):
self.level += 1
self.brick_container.clear_widgets()
self.ball_container.clear_widgets()
self.bonus_container.clear_widgets()
Clock.unschedule(self.update)
self.create_game()
Clock.schedule_once(self.update, 1.0 / 60.0)

Save the Clock.schedule_once to a variable, event and replace Clock.unschedule(self.update) with self.event.cancel()
if(len(self.ball_container.children) == 0):
...
self.bonus_container.clear_widgets()
self.event.cancel()
self.create_game()
self.event = Clock.schedule_once(self.update, 1.0 / 60.0)
Note
An alternative is to use Trigger events.
Each time you call trigger(), it will schedule a single call of your
callback. If it was already scheduled, it will not be rescheduled.
self.trigger = Clock.create_trigger(my_callback, 1.0 / 60.0)
self.trigger() # schedule it
self.trigger.cancel() # cancel / unschedule it

Related

Process executes functions, but they are not doing their job

I'm doing project on RPi and came across problem, that I can't solve. I'm using multiprocess to calculate wind speed with anemometer, and servo based platform to move around pv panel. In the main function I declare processes and objects:
def main():
ane = Anemometer(pin=38, radius=65, anamometer_factor=1, action_time=5,
measurment_fraquency=0.01, max_wind_speed=40, mesurment_time=30)
prb = PhotoresistorBase(TR=1, TL=3, BR=0, BL=2, signifficant_diff=40)
BS = Servo(pin=12, min_val=10, max_val=50)
US = Servo(pin=18, min_val=29, max_val=43)
pv_based = Pv(6)
pv_servo = Pv(5)
...
calculate_wind_vel_p = Process(target=calculate_wind_vel, args=(ane, BS, US))
calculate_power_p = Process(target=calculate_power, args=(pv_based, pv_servo))
turn_platform_p = Process(target=turn_platform, args=(prb, BS, US))
calculate_wind_vel_p.start()
calculate_power_p.start()
turn_platform_p.start()
calculate_wind_vel_p.join()
calculate_power_p.join()
turn_platform_p.join()
Process calculate_power_p works great, problem appears in two other processes
Process calculate_wind_vel_p targets function calculate_wind_vel, which looks like this:
def calculate_wind_vel(ane, BS, US):
while True:
wind_speed = ane.calculate_mean_wind_velocity()
...
data = (datetime.datetime.now(), wind_speed)
insert_vel_data(conn, data)
time.sleep(1)
and Anemometer class, which contains calculate_mean_wind_velocity() looks like this:
class Anemometer:
def __init__(self, pin, radius, anamometer_factor, action_time,
measurment_fraquency, max_wind_speed, mesurment_time):
...
def calculate_wind_velocity(self) -> float:
rotations = 0
count = 0
endtime = time.time() + self.action_time
sensorstart = GPIO.input(self.pin)
circumference = (self.radius * 2 / 1000) * math.pi
while time.time() < endtime:
if GPIO.event_detected(self.pin):
count = count + 1
**print(count)**
if rotations==1 and sensorstart==1:
rotations = 0
rots_per_second = float(count/3/self.action_time)
wind_vel = float((rots_per_second)*circumference*self.anamometer_factor)
**print("Wind vel: " + str(wind_vel))**
return wind_vel
def calculate_mean_wind_velocity(self) -> float:
sum = 0
measure_count = int(self.mesurment_time/self.action_time)
for _ in range(measure_count):
sum += self.calculate_wind_velocity()
return float(sum/measure_count)
The Problem:
When process executes calculate_wind_vel() it jumps to ane.calculate_mean_wind_velocity(). The second function, executes calculate_wind_velocity e.g 4 times and calculate mean wind speed.
When calculate_wind_velocity() starts, program prints 'count' only once (first bolded print) and later count does not increment despite event is triggered. Than it calculate wind speed, with that one counted interruption. Later when calculate_wind_velocity() is execute again (process target has while True:) count is not incremented at all!
weirdest thing is that, when I run this code without process, just paste this into main():
ane = Anemometer(pin=38, radius=65, anamometer_factor=1, action_time=5,
measurment_fraquency=0.01, max_wind_speed=40, mesurment_time=30)
while True:
ret = ane.calculate_mean_wind_velocity()
print(ret)
time.sleep(2)
It works perfect - it calculates every single GPIO.event_detected(self.pin) and wind_speed, so it has smth to do with processes!.
Similar problem with moving platform - process executes functions from servo class, but it does not move, functions don't calculate/change state.

Python 3 Turtle - Simultaneous Press

So I followed the instructions here on how to take two inputs at the same time to execute a different function than either key press individually.
My code doesn't want to work but only the function that requires two key presses ('w', 'a'): upLeft and I can't figure out why. I tested my function in the provided solution and it worked. I can't seem to see any tangible differences between what I have here and what is provided in the link.
import turtle
import time
# Draw initial screen
wn = turtle.Screen()
wn.title("Cool Game Bro")
wn.bgcolor("grey")
wn.setup(width=800, height=600)
wn.tracer(0)
# main player character
character = turtle.Turtle()
character.speed(0)
character.shape("circle")
character.color("yellow")
character.penup()
character.goto(0, 0)
def process_events():
events = tuple(sorted(key_events))
if events and events in key_event_handlers:
(key_event_handlers[events])()
key_events.clear()
wn.ontimer(process_events, 200)
def Up():
key_events.add('w')
def Left():
key_events.add('a')
def Down():
key_events.add('s')
def Right():
key_events.add('d')
def charUp():
y = character.ycor()
y += 10
character.sety(y)
def charLeft():
x = character.xcor()
x -= 10
character.setx(x)
def charRight():
x = character.xcor()
x += 10
character.setx(x)
def charDown():
y = character.ycor()
y -= 10
character.sety(y)
def upLeft():
y = character.ycor()
y+=10
character.sety(y)
x = character.xcor()
x -=10
character.setx(x)
key_event_handlers = { \
('w',): charUp,\
('a',): charLeft,\
('d',): charRight,\
('s',): charDown,\
('w', 'a'): upLeft,\
}
key_events = set()
wn.onkeypress(Up, 'w')
wn.onkeypress(Left, 'a')
wn.onkeypress(Right, 'd')
wn.onkeypress(Down, 's')
wn.listen()
process_events()
while True:
wn.update()
Appreciate the help!
A set stores things alphabetically. Use
('a','w'): upLeft
and it will work fine.
BTW1, you could have learned this if you had just added print(events) in your process_events function, as I did.
BTW2, you don't need backslashes in your definition. Anything contained in parens, square brackets, or curly brackets can automatically be continued onto another line.

Kivy: How To Limit Simultaneous Touches to One?

I am using Kivy 1.9.1 and Python 3.5.2. My application breaks when more than one touch event is fired before the first has finished processing. I'm looking for some way to either restrict the number of touch events at a given time to one (something like the max_pointers attribute in the HTML5 engine Phaser) or to filter the touch events and only process the first. As far as I'm aware, the touch event doesn't hold this information about itself.
I don't believe the specifics of my code are relevant, but better safe than sorry:
def on_touch_down(self, touch):
x, y = touch.x, touch.y
x -= self.img_board.pos[0]
y -= self.img_board.pos[1]
if not (0 <= x <= self.img_board.size[0] and
0 <= y <= self.img_board.size[1]):
touch.ud['piece'] = None
return
file = int(x / self.square_size)
rank = int(y / self.square_size)
self.select((file, rank))
piece = Board.instance.at_square(self.selected)
touch.ud['piece'] = piece
if piece:
self.canvas.remove(piece.rect)
self.canvas.after.add(piece.rect)
def on_touch_move(self, touch):
piece = touch.ud['piece']
if piece:
if Board.instance.to_move == piece.color:
piece.rect.pos = (touch.x - piece.rect.size[0]/2,
touch.y - piece.rect.size[1]/2)
def on_touch_up(self, touch):
piece = touch.ud['piece']
if piece:
self.canvas.after.remove(piece.rect)
self.canvas.add(piece.rect)
if Board.instance.to_move != piece.color:
return
x, y = touch.x, touch.y
x -= self.img_board.pos[0]
y -= self.img_board.pos[1]
if not (0 <= x <= self.img_board.size[0] and
0 <= y <= self.img_board.size[1]):
self.update_geometry()
return
dest = Board.an_from_tup( (int(x / self.square_size),
int(y / self.square_size)) )
if dest in piece.get_valid_moves():
Board.instance.move(piece.position,dest)
self.select(dest)
self.update_geometry()
I was able to implement this by creating a TouchHandler widget:
class TouchHandler(Widget):
""" Non-display widget to handle touch order """
instance = None
def __init__(self):
super().__init__()
TouchHandler.instance = self
self.active = None
Then overriding Window's on_motion method prior to calling MyApp().run():
if __name__ == '__main__':
# Ignore new touches before first touch has resolved
TouchHandler()
def on_motion(self, etype, me):
if 'pos' in me.profile:
if etype == 'begin':
if not TouchHandler.instance.active:
TouchHandler.instance.active = me
Window.bind(on_motion=on_motion)
Window.size = (500,500)
MyApp().run()
For this to work, you need to manage your touch events very carefully and reset TouchHandler.instance.active to None when you're done with the touch in the on_touch_up method for any widget that will use the touch:
def on_touch_up(self, touch):
if touch != TouchHandler.instance.active:
return True # Signals Kivy to kill the event
piece = touch.ud['piece']
if piece:
# ...
self.update_geometry()
TouchHandler.instance.active = None
This is an answer, but I'm kind of afraid of it, I'm pretty sure it's bad programming practice but:
I created a global variable with touch_counter = 0, then in on_touch_down I referenced the global variable and then += 1 it, and in on_touch_up I -= 1 it. In on_touch_move I check if the touch_counter == 1 and then performed what I wanted it to do with only one touch.
This works with multitouch_sim, I realize this might mess up with actually multitouch devices, but so far so good.

Timer for python functions

I'm trying to do an automatic mouse clicker. My main issue now is how to do a timer for each function, for example, function 1 works for about 15 minutes, then function 2 after the 15 minutes starts to work just one time, then comeback to function 1. And i want to function4 Works independente from the others, i want it to click everytime even if the function 1 is running ( im not sure if this is possible) here is my code:
import pyautogui, sys
pyautogui.size()
(1280, 800)
def function1():
pyautogui.click(button='left', x=619, y=266)
pyautogui.PAUSE = 3.9
pyautogui.click(button='left', x=617, y=475)
def function2():
pyautogui.click(button='left', x=624, y=347)
pyautogui.PAUSE = 5.0
pyautogui.click(button='left', x=615, y=431)
pyautogui.PAUSE = 5.0
pyautogui.click(button='left', x=315, y=483)
pyautogui.PAUSE = 5.0
pyautogui.click(button='left', x=616, y=390)
def function3 ():
pyautogui.click(button='left', x=617, y=522)
pyautogui.PAUSE = 5.0
def function4():
pyautogui.click(button='left', x=1257, y=432)
Thank you all :)
Because it is not easy to manage multiple functions with wait independently without introducing a signal and multi-thread, here is another way to manage multiple click() functions with the PyAutoGUI library.
The solution is a multi-sequencer class (called class TimerExec).
Step 1 - Use a class TimerSeq to store sequencer parameters
Only the constructor is needed
class TimerSeq:
def __init__(self, iseq, tseq, bexe, bloop):
self.iseq = iseq
self.tseq = tseq
self.bexe = bexe
self.bloop = bloop
Step 2 - Create a class TimerExec to manage a list of sequencers
The constructor create an empty list
class TimerExec:
def __init__(self):
self.list = [ ]
self.stop = True
self.chrono = -1
self.delay = -1
A simple floating-point seconds value to int milliseconds
#
# convert float seconds to milliseconds
def tomilli(self, fsec):
return int(round(fsec * 1000))
Add a new sequencer in the list
#
# append new sequences to the list
def append(self, func, loop=False):
self.list.append([func, TimerSeq(-1, -1, False, loop)])
print('list:',self.list)
Verify if the sequencer is complete or restart when loop
#
# check end of sequence or restart
def nextcheck(self, seq):
if seq[1].iseq >= len(seq[0]):
if seq[1].bloop:
seq[1].iseq = 0 # restart
return True
return False
Compute parameters for the next sequence in the current sequencer
#
# switch to the next sequence
def nextstep(self, seq):
if seq[1].iseq >= len(seq[0]):
return True
seq[1].iseq = seq[1].iseq+1
seq[1].tseq = self.tomilli(time.time())
seq[1].bexe = False
return False
Manage the current sequencer and execute the current function then
delay the next sequence
#
# explore sequence and execute when
def exestep(self, seq):
bseq = False
if seq[1].tseq < 0:
bseq = self.nextstep(seq)
else:
bseq = self.nextcheck(seq)
if bseq:
return True
pseq = seq[0][seq[1].iseq]
tnow = self.tomilli(time.time())
tdel = self.tomilli(pseq[0])
if seq[1].bexe == False:
print('execute(%d):'% (tnow-self.chrono),pseq)
# execute the selected function
pseq[1](pseq[2],pseq[3],pseq[4])
seq[1].bexe = True
tseq = seq[1].tseq
if tnow > (tseq+tdel):
bseq = self.nextstep(seq)
return bseq
Main loop function to explore all sequencers until complete or
max_delay
#
# loop to execute all sequences with max_delay (s)
def execute(self, max_delay):
print('start:',time.strftime("%H:%M:%S", time.localtime()))
self.stop = False
self.delay = self.tomilli(max_delay)
self.chrono = self.tomilli(time.time())
while self.stop == False:
tnow = self.tomilli(time.time())
#if tnow > (self.chrono + self.delay):
# break
bstop = True
for seq in self.list:
bseq = self.exestep(seq)
bstop = bstop & bseq
if bstop == True:
self.stop = True
print('stop:',time.strftime("%H:%M:%S", time.localtime()),
((tnow-self.chrono)/1000.0))
Step 3 - declare your sequencer based to your declared function
For function1(), use a 2 steps sequencer:
def function1():
pyautogui.click(button='left', x=619, y=266)
pyautogui.PAUSE = 3.9
pyautogui.click(button='left', x=617, y=475)
The sequencer is:
fct1 = [
# pyautogui.click(button='left', x=619, y=266)
[ 3.9, pyautogui.click, 'left', 619, 266 ],
# pyautogui.click(button='left', x=617, y=475)
[ 0.0, pyautogui.click, 'left', 617, 475 ]
]
Step 4 - Create TimerExec object, add sequencer then execute.
The duration is limited to 13.6 seconds maximum
tSeq = TimerExec()
tSeq.append(fct1)
tSeq.execute(13.6)

How to interact with mayavi window while animating particles? (during Particle Swarm Optimization)

I am trying to do an animation of a Particle Swarm Optimization using Python and Mayavi2.
The animation is working fine, my problem is that it is not possible to interact with the plot while it is animating the movement. Specifically i would like to turn the graph and zoom. Maybe someone has experience doing animations?
The way i do it is first to calculate the positions of the particles and then to store them. After the calculation is finished i plot the positions of the particle at the first instace of time with point3d() and then i iterate through time updating the data using the set() method.
Is there a way to make it possible to turn the graph? I have heard about something with threads, disabeling the the rendering, but i could not figure out how to do it in my code. Besides lots of other stuff, I have read:
http://code.enthought.com/projects/mayavi//docs/development/html/mayavi/mlab_animating.html
http://code.enthought.com/projects/mayavi//docs/development/html/mayavi/tips.html#acceleration-mayavi-scripts
but it can't see how to use it.
Any suggestions?
Here is my code:
#!/usr/bin/env python
'''
#author rt
'''
import pylab as plt
from numpy import *
from mayavi import mlab
from threading import Thread # making plotting faster?
import ackley as ac
class Swarm(Thread, object):
'''
constructor for the swarm
initializes all instance variables
'''
def __init__(self,objective_function):
Thread.__init__(self)
# optimization options
self.omega = 0.9 # inertial constant
self.c1 = 0.06 # cognitive/private constant
self.c2 = 0.06 # social constant
self.objective = objective_function # function object
self.max_iteration = 100 # maximal number of iterations
# Swarm stuff
self.number = 0
self.best = [] # gbest; the global best position
self.particles = [] # empty list for particles
# temporary
self.min = self.objective.min
self.max = self.objective.max
self.best_evolution = []
# self.dimensions = 2 # dimensions NB!
'''
add particles to the swarm
find the best position of particle in swarm to set global best
'''
def add_particles(self, n):
for i in range(n):
particle = Particle(self)
if i == 0: # initialize self.best
self.best = particle.position
if particle.eval() < self._eval(): # check if there is a better and if, set it
self.best = copy(particle.position)
self.particles.append(particle) # append the particle to the swarm
def _eval(self):
return self.objective.evaluate(self.best)
def plot(self):
for i in range(self.max_iteration):
pos_x = []
pos_y = []
pos_z = []
#print pos_x
for particle in self.particles:
[x,y,z] = particle.trail[i]
pos_x.append(x)
pos_y.append(y)
pos_z.append(z)
#print pos_x
if i ==0:
g = mlab.points3d(pos_x, pos_y,pos_z, scale_factor=0.5)
ms =g.mlab_source
ms.anti_aliasing_frames = 0
ms.set(x=pos_x, y = pos_y, z = pos_z,scale_factor=0.5) #updating y value
#print pos_y
#ms.set(x=pos_x) # update x values
#ms.set(y=pos_y) #updating y value
#ms.set(z=pos_z) #updating y value
#for p in self.particles:
#p.plot()
def plot_objective(self):
delta = 0.1
v = mgrid[self.min:self.max:delta,self.min:self.max:delta]
z = self.objective.evaluate(v)
#mlab.mesh(v[0],v[1],z)
mlab.surf(v[0],v[1],z) # surf creates a more efficient data structure than mesh
mlab.xlabel('x-axis', object=None)
mlab.ylabel('y-axis', object=None)
mlab.zlabel('z-axis', object=None)
def _info(self):
self.plot()
print '----------------------------'
print 'The best result is:'
print 'Coordinates:', self.best
print 'Value: ', self._eval()
#print 'with ', nreval, 'evaluations'
print 'nr of particles: ', len(self.particles)
print '----------------------------'
def run(self):
self.plot_objective()
self.best = self.particles[0].get_position()
iteration = 0
while iteration < self.max_iteration:
#if iteration!= 0: obj.scene.disable_render = True
#disable_render = True
for particle in self.particles:
rnd_c1 = array([random.uniform(0,1),random.uniform(0,1)])
rnd_c2 = array([random.uniform(0,1),random.uniform(0,1)])
particle.velocity = self.omega * array(particle.velocity) + \
self.c1 * rnd_c1 * (array(particle.best) - array(particle.position)) + \
self.c2 * rnd_c2 * (array(self.best) - array(particle.position)) # TODO: change so independent rnd for components
particle.position = array(particle.position) + particle.velocity
if particle.eval() < particle.best_eval():
particle.best = copy(particle.position)
if particle.eval() < self._eval():
self.best = copy(particle.position)
particle.update() # add the point to the trail
iteration +=1
self.best_evolution.append(self._eval())
#obj.scene.disable_render = False
print 'finished: ', iteration
self._info()
'''
Class modeling particle
'''
class Particle():
def __init__(self, swarm):
self.swarm = swarm
x_rand = random.uniform(self.swarm.min,self.swarm.max)
y_rand = random.uniform(self.swarm.min,self.swarm.max)
self.position = array([x_rand,y_rand])
v_x_rand = random.uniform(self.swarm.min,self.swarm.max)
v_y_rand = random.uniform(self.swarm.min,self.swarm.max)
self.velocity = array([v_x_rand, v_y_rand])
self.size = 0.5
self.best = self.position
# visualization
self.trail = []
def plot(self):
[x,y] = self.position
z = self.eval()
mlab.points3d(x,y,z,scale_factor=self.size)
def eval(self):
return self.swarm.objective.evaluate(self.position)
def best_eval(self):
return self.swarm.objective.evaluate(self.best)
def get_position(self):
return self.position
def update(self):
[x,y] = self.position
z = self.eval()
#print [x,y,z]
self.trail.append([x,y,z])
def plot_trail(self,index):
[x,y,z] = self.trail[index]
mlab.points3d(x,y,z,scale_factor=self.size)
# Make the animation
mlab.figure(1, bgcolor=(0, 0, 0), size=(1300, 700)) # create a new figure with black background and size 1300x700
objective = ac.Ackley() # make an objective function
swarm = pso.Swarm(objective) # create a swarm
nr_of_particles = 25 # nr of particles in swarm
swarm.add_particles(nr_of_particles)
swarm.run()
#swarm.start()
mlab.show()
print '------------------------------------------------------'
print 'Particle Swarm Optimization'
#objective.info()
print 'Objective function to minimize has dimension = ', objective.get_dimension()
print '# of iterations = ', 1000
print '# of particles in swarm = ', nr_of_particles
print '------------------------------------------------------'
In my case, even though I was somewhat able to do what Brandon Rhodes suggested for a mock program (https://stackoverflow.com/questions/16617814/interacting-with-mlab-scene-while-it-is-being-drawn), I could not manage to convert my already existing larger program.
Then I found this link: http://wiki.wxpython.org/LongRunningTasks
So, I just sprinkled a lot of wx.Yield() s inside my loops. This way I did not need to change my program structure, and I am able to interact with the window. I think better ways are explained in the link.
Your problem is that the wx event loop, which runs the Mayavi GUI window and listens for mouse clicking and dragging and responds by moving the scene, is not getting any time to run during your animation because you are keeping Python captive in your loop without ever letting it return control.
Instead of keeping control of the program with a loop of your own, you need to create a wx.Timer class that advances the scene by one frame update, and that then returns control to the wx event loop after scheduling itself again. It will look something like this:
import wx
...
class Animator(wx.Timer):
def Notify(self):
"""When a wx.Timer goes off, it calls its Notify() method."""
if (...the animation is complete...):
return
# Otherwise, update all necessary data to advance one step
# in the animation; you might need to keep a counter or
# other state as an instance variable on `self`
# [DATA UPDATE GOES HERE]
# Schedule ourselves again, giving the wx event loop time to
# process any pending mouse motion.
self.Start(0, oneShot=True) # "in zero milliseconds, call me again!"
I played with slightly higher values like 1 for the number of milliseconds that wx gets to run the UI with, but could not really tell a difference between that and just choosing 0 and having control returned "immediately".

Categories