Shoutbox

Python help - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Skype & Technology (/forumdisplay.php?fid=9)
+---- Forum: Tech Talk (/forumdisplay.php?fid=17)
+----- Thread: Python help (/showthread.php?tid=92203)

Python help by Chancer on 09-14-2009 at 01:47 AM

I'm coding a program that sends some data via serial when a key is pressed:

Python code:
from Tkinter import *
from serial import Serial
 
Arduino = Serial(3)
Arduino.baudrate = 115200
 
root = Tk()
 
def Acelerate (event):
    Arduino.write ("Ax")
def Reverse (event):
    Arduino.write ("Rx")
def Right (event):
    Arduino.write ("xD")
def Left (event):
    Arduino.write ("xE")
 
root.bind ('<Up>', Acelerate)
root.bind ('<Down>', Reverse)
root.bind ('<Right>', Right)
root.bind ('<Left>', Left)
root.mainloop()


It's working pretty fine. You press Up in you keyboard, it sends data which makes an RC car move forward. You press Down, it moves backward. When you press Right or Left, it turns its wheels to that side.

Now I need to do this: when I press, for example, Up and Right at the same time, I need to send "AD" (stupid math, "Ax + xD"), and analog for other combinations.
How can I do this multi-key binding?

I saw some examples with modifier keys, like "root.bind ('<Control-A>', asd)", but this combination <'Key1-Key2'> seems to work only with these modifiers (Control, Alt, Shift, etc).

So, do you think it's possible?
RE: Python help by Ezra on 09-14-2009 at 05:23 PM

Why are you trying to do this with python?

I see that your are working with arduino, try processing.

It's the language that the arduino language is based upon and it has a similar editor and has some arduino libraries to make it easier for you to create applications that can work together with your arduino.


RE: Python help by Chancer on 09-14-2009 at 08:55 PM

It's a college projetc. We must use Python, however they don't teach us it...


RE: Python help by Jarrod on 09-15-2009 at 08:11 AM

I <3 python I can help you with this and I know some ppl who might be more help than me, do you have to use Tkinter?
something like pyglet might be more viable


RE: Python help by Chancer on 09-15-2009 at 08:45 PM

No, Tkinter is not mandatory. It's the only solution I found so far.
What do you suggest?


RE: Python help by matty on 09-16-2009 at 12:36 PM

quote:
Originally posted by Chancer
What do you suggest?
quote:
Originally posted by Jarrod
something like pyglet might be more viable
I wonder what he suggests... lol sorry I had to!
RE: Python help by Chancer on 09-16-2009 at 05:55 PM

I know, I know... I mean, how can I use it?
I read it's documentation, but I can't make it detect multiple keys at once. All I could do was as functional as my code in first post.

I was expecting a piece of code, an example...


RE: Python help, Solution :) by Jarrod on 09-20-2009 at 01:33 PM

Python code:
import pyglet as pyg
import random
from pyglet.window import key
window=pyg.window.Window()
 
#map- when arrow keys are pressed in pyglet, the symbol that represents them is a number
#he numbers are:
#65361 = left = 0
#65362 = up = 1
#65363 = right = 2
#65364 = down = 3
#we now have 4 numbers 1-4, each representing an arrow key
#
keys=[False]*4
#so now we have a list of 4 False values, which will represent each arrow,
#python indexes an array/list starting from 0
 
#above we mention 4 numbers, 65361,65362,65363,65364
#instead of mapping each to a dictionary if we get the last digit and subtract 1 we end up with a set like
#0,1,2,3
#so now if we let this number index keys like this
#keys[((int(str(symbol)[-1]))-1)]
#it is the same as saying:
#
#def on_key_press(symbol,modifiers,keys=keys):
#   if symbol == 65361:
#       keys[0]=True    #keys[0] is left
#   if symbol == 65362:
#       keys[1] == True
# #ect,ect
 
#keys are mapped ((int(str(symbol)[-1]))-1)
 
@window.event
def on_key_press(symbol,modifiers,keys=keys):
    #print symbol,((int(str(symbol)[-1]))-1)
    keys[((int(str(symbol)[-1]))-1)] = True
@window.event
 
def on_key_release(symbol,modifiers,keys=keys):
    keys[((int(str(symbol)[-1]))-1)] = False
 
def update(dt,keys=keys):
    #by using this statement we determine more complex events first (left + up) so it fulfils these instead fulfilling a less complex (left)
    if keys[0] and keys[1]:
        print 'left'+'up'
    elif keys[1] and keys[2]:
        print 'right'+'up'
    elif keys[0] and keys[3]:
        print 'down'+'left'
    elif keys[2] and keys[3]:
        print "down"+'right'
    elif keys[0]:
        print "left"    #due to this, if two conflicting keys are help the upper most one will occur
    elif keys[1]:
        print "up"      #up occurs if 'down' and 'up' are down, left occurs if 'left' and 'right' are down
    elif keys[2]:
        print 'right'
    elif keys[3]:
        print "down"
   
 
pyg.clock.schedule_interval(update, 0.1)
pyg.app.run()


try that,
sorry for the delay been a touch busy
RE: Python help by Chancer on 09-20-2009 at 03:26 PM

Great, man. It works just fine! Thanks!
I'll take a few time trying to decipher and understanding the code (I'm learning by myself... it's been kinda hard), and fine tuning the update interval.

One more question: using pyglet to do this will force me to create the whole interface with pyglet?


RE: Python help by Jarrod on 09-20-2009 at 09:40 PM

I added a few comments so you can understand it better (edited into the code above),
I'm going to yes, using pyglet will force you to do the whole interface in pyglet, technically you could create a Tkinter window as well but it would be cumbersome, eg the pyglet window would need to be focused to take input.
writing the interface in pyglet would not be a particularly bad idea and should be quite workable


RE: Python help by Chancer on 09-20-2009 at 10:05 PM

Cool :)
Actually, the "hard part" was

Python code:
((int(str(symbol)[-1]))-1)


You get a simbol (65361, 65362, etc);
convert it to a string;
get only the last character ([-1]);
convert into an integer;
subtract 1.
Is this right?
RE: Python help by Jarrod on 09-20-2009 at 10:08 PM

yep that's it, you could do it with dictionaries or more if statements, but indexes just seemed like a thinner way to code it, it also gave me less to think about,

Python code:
>>> symbol=65361
>>> str(symbol)[-1]
'1'
>>> int(str(symbol)[-1])
1
>>> int(str(symbol)[-1])-1
0


RE: Python help by Chancer on 09-21-2009 at 01:06 AM

Or even easier:

Python code:
symbol % 10 - 1

It worked.
RE: Python help by Jarrod on 09-21-2009 at 01:23 AM

that's probably more efficient too,
well if you need any help with getting pyglet to do anything else I'm happy to give you a hand


RE: Python help by Chancer on 09-26-2009 at 11:20 PM

Here I am once again.
Our teacher told us to use pygame to create the interface, so I was wondering if it was possible to port that code you did to pygame libraries.

I made a big progress, but it's not good enough:

Python code:
import pygame
from pygame.locals import *
 
def main():
    pygame.init()
    screen = pygame.display.set_mode((75, 55))
    screen = pygame.display.set_caption('Projeto 39')  
    screen = pygame.display.get_surface()
    background = pygame.Surface(screen.get_size())
    background = background.convert()
    background.fill((250, 255, 255))
    screen.blit(background, (0, 0))
   
    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
                return      # Close window when clicking X ou hitting Escape
           
            elif event.type == KEYDOWN:     # Verify pressed keys
                key = pygame.key.get_pressed()
               
                if key[K_UP] and key[K_RIGHT]:
                    print 'AD'
               
                elif key[K_UP] and key[K_LEFT]:
                    print 'AE'
               
                elif key[K_DOWN] and key[K_RIGHT]:
                    print 'RD'
               
                elif key[K_DOWN] and key[K_LEFT]:
                    print 'RE'
               
                elif key[K_UP]:
                    print 'Ax'
               
                elif key[K_DOWN]:
                    print 'Rx'
               
                elif key[K_RIGHT]:
                    print 'xD'
               
                elif key[K_LEFT]:
                    print 'xE'
       
        screen.blit(background, (0, 0))
        pygame.display.flip()
 
main()

This does print the codes (AD, Ax, etc) when I press the keys, but it does it only once per keypress, and I need it to do it repeatedly.
What do you say? Is it possible?
RE: Python help by Jarrod on 09-27-2009 at 09:35 AM

well this is why I suggested pyglet over pygame, AFAIK in pygame you have an update method just like in pyglet but it needs to be inherited from a sprite object this is a sample I found on the net,

Python code:
class Fist(pygame.sprite.Sprite):
    """moves a clenched fist on the screen, following the mouse"""
    def __init__(self):
        pygame.sprite.Sprite.__init__(self) #call Sprite initializer
        self.image, self.rect = load_image('fist.bmp', -1)
        self.punching = 0
 
    def update(self):
        "move the fist based on the mouse position"
        pos = pygame.mouse.get_pos()
        self.rect.midtop = pos
        if self.punching:
            self.rect.move_ip(5, 10)

so the problem with the code you currently have is the while True loop, and while it seems natural that that should work, it doesn't seem to work in pygame or even pyglet for that matter.
To rectify this I would create a sprite object and put your key test in the update method similar to what we did in pyglet. Were there any advantages for pygame over pyglet? When I was informed about which one to use I was told pygame might be easier but pyglet is definitely more feature rich, unless it is expected that you use pygame, you might like to consider sticking to pyglet that is if you have the choice.
RE: Python help by Chancer on 09-27-2009 at 02:39 PM

Well. I didn't say, but this will control an RC car, and we're planning to have a wheel which will turn right and left when we press right and left.
So I guess this will do the job.

I read this chimp example, but I couldn't get much info. Thanks for this.

I'm using pygame because our teacher told us to. I guess he has experience with pygame...


RE: Python help by Jarrod on 09-27-2009 at 09:12 PM

well it's been a while since I did pygame but hopefully this is kinda right,

Python code:
import pygame
from pygame.locals import *
class Mover(pygame.sprite.Sprite):
    """moves a clenched fist on the screen, following the mouse"""
    def __init__(self):
        pygame.sprite.Sprite.__init__(self) #call Sprite initializer
 
    def update(self):
        "move the fist based on the mouse position"
        pos = pygame.mouse.get_pos()
        if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
            return
        elif event.type == KEYDOWN:     # Verify pressed keys
            key = pygame.key.get_pressed()
         
            if key[K_UP] and key[K_RIGHT]:
                print 'AD'    
                elif key[K_UP] and key[K_LEFT]:
                    print 'AE'
                elif key[K_DOWN] and key[K_RIGHT]:
                    print 'RD'
                elif key[K_DOWN] and key[K_LEFT]:
                    print 'RE'
                elif key[K_UP]:
                    print 'Ax'
                elif key[K_DOWN]:
                    print 'Rx'
                elif key[K_RIGHT]:
                    print 'xD'
                elif key[K_LEFT]:
                    print 'xE'
   
   
            self.rect.move_ip(5, 10)
def main():
    pygame.init()
    screen = pygame.display.set_mode((75, 55))
    screen = pygame.display.set_caption('Projeto 39')  
    screen = pygame.display.get_surface()
    background = pygame.Surface(screen.get_size())
    background = background.convert()
    background.fill((250, 255, 255))
    screen.blit(background, (0, 0))
    m=Mover()
    screen.blit(background, (0, 0))
    pygame.display.flip()
 
main()


note: I haven't tested that but I think that's how pygame does it
RE: Python help by Chancer on 09-27-2009 at 10:47 PM

Yeah! I did it :)
Just changes a little bit that while True loop.

Python code:
while True:
    for event in pygame.event.get():
        if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
            return
        key = pygame.key.get_pressed() # Added only to check the condition below        while key[K_UP] or key[K_DOWN] or key[K_RIGHT] or key[K_LEFT]           
            key = pygame.key.get_pressed()
           
            if key[K_UP] and key[K_RIGHT]:
                SendData('AD')
           
            elif key[K_UP] and key[K_LEFT]:
                SendData('AE')
           
            elif key[K_DOWN] and key[K_RIGHT]:
                SendData('RD')
           
            elif key[K_DOWN] and key[K_LEFT]:
                SendData('RE')
           
            elif key[K_UP]:
                SendData('Ax')
           
            elif key[K_DOWN]:
                SendData('Rx')
           
            elif key[K_RIGHT]:
                SendData('xD')
           
            elif key[K_LEFT]:
                SendData('xE')
            pygame.time.delay(10) # Added to have a better control - 10 ms between each loop            pygame.event.pump() # This makes the trick, but I don't know exactly how it works


Also, already added the command to send data via serial.
RE: Python help by Chancer on 10-04-2009 at 04:05 AM

Hey there again. I don't need help this time, I'm here just to show how it is going:
http://www.youtube.com/watch?v=p9gCWCcFW5Y