How do you fix this code?

Asked

Viewed 99 times

0

  1. When I press the keyboard, for example the "w" to go forward, the robot goes forward and sometimes another motor turns on together.
  2. When I press a command and keep pressed, when stopping pressing the engine it is still running, due to the time set(accumulates), a solution is to define a keydown/keyup, how can I do this?

ADDITIONAL INFORMATION: I am using a Raspberry and a bridge h L298N, to start two engines (I am doing tests for a robot).

I expect suggestions for improvements and thank you in advance.

Code below:

import RPi.GPIO as gpio
import time
import sys
import Tkinter as tk

def init():

    gpio.setmode(gpio.BOARD)
    gpio.setup(7, gpio.OUT)
    gpio.setup(11, gpio.OUT)
    gpio.setup(13, gpio.OUT)
    gpio.setup(15, gpio.OUT)

def frente(tf):
    gpio.output(7, False)
    gpio.output(11, True)
    gpio.output(13, True)
    gpio.output(15, True)
    time.sleep(tf)
    gpio.cleanup()

def tras(tf):
    gpio.output(7, True)
    gpio.output(11, False)
    gpio.output(13, False)
    gpio.output(15, False)
    time.sleep(tf)
    gpio.cleanup()

def esq(tf):
    gpio.output(7, True)
    gpio.output(11, True)
    gpio.output(13, False)
    gpio.output(15, True)
    time.sleep(tf)
    gpio.cleanup()

def dir(tf):
    gpio.output(7, False)
    gpio.output(11, False)
    gpio.output(13, True)
    gpio.output(15, False)
    time.sleep(tf)
    gpio.cleanup()


def key_input(event):
    init()
    print 'Key:', event.char
    key_press = event.char
    sleep_time = (0.02)

    if key_press.lower() == 'w':
        frente(sleep_time)
    elif key_press.lower() == 's':
        tras(sleep_time)
    elif key_press.lower() == 'a':
        esq(sleep_time)
    elif key_press.lower() == 'd':
        dir(sleep_time)


janela = tk.Tk()
janela.bind('<KeyPress>', key_input)
janela.mainloop()

1 answer

1

Yes, the event KeyPress is called whenever a key is pressed - and in general the operating system will have an automatic "auto-repeat": i.e., if the user does not release the key, several events of KeyPress are sent - And, including events that happen while the time.sleep is in force, will be "encavalados" -

That is to say - let’s assume that the system’s keystroke time is "0.1" seconds and its pause is 1 Second: 10 keypress events would arrive during a single team..

And the reverse situation can also be bad from the user’s point of view: you have a time.sleep of 0.02 seconds, and the challenge of the system occurs every 0.1 - that is to say that the engine would be driven by "small jacks": is on 0.02 seconds, wait 0.08 seconds between one drive and another.

Good - what you need is to activate the engine when you receive the first <KeyPress> and stop the same when receiving the evneto from <KeyRelease> - and, or not depending on a time of time.sleep, or find another way to account for the time to an automatic stop. (for example, any mechanism that has to stay exactly the time X on, index the time the key is pressed).

Rewrite the steering functions in this way:

def frente():
    gpio.output(7, False)
    gpio.output(11, True)
    gpio.output(13, True)
    gpio.output(15, True)

and can maintain the function key_input almost as it is, but without passing the Sleep parameter - and a new function:

def keyup(event):
    if event.char in "wasd":
         gpio.cleanup()

And, of course, associate it with the event of dropping a key:

janela.bind("<KeyRelease>", keyup)

Now, if the engine should really stay on for just 0.02 seconds, you need something a little more complex - instead of using the.Leep team, use the call after Tkinter - and only "release" a key to be "repeated" after the corresponding key is pressed.

Create a dictionary in the module, to save the state of each key, "False" to "loose" and "True" to pressed, and only call the trigger functions if the key was not previously pressed.

Change the drive functions to this model:

def esq(tf):
    gpio.output(7, True)
    gpio.output(11, True)
    gpio.output(13, False)
    gpio.output(15, True)
    # Faz a pausa sem bloquear o fluxo do programa:
    tkinter.after(tf * 1000, gpio.cleanup)

pressed_keys = {
  "w": False, "s": False, "a": False, "d": False
}
# e aproveitando um atalho em vez dos "if" repetitivos:
movement_funcs = {
   "w": frente, "s": tras, "a": esq, "d": dir
}



def key_input(event):
    # O "init" realmente tem que ser chaamdo em cada keypress?
    # se sim,  mova essa chamada para dentro das funções de movimento- 
    # assim, os keypress repetidos não vão resetar os GPIOs.
    # mas me parece que essa chamada deveria ser feita no setup da aplicação
    # apenas uma vez:
    init()
    print 'Key:', event.char
    key_press = event.char
    sleep_time = (0.02)

    if event.char in "wsad" and not pressed_keys[event.char]:
         pressed_keys[event.char] = True
         movement_funcs[event.char](sleep_time)

def keyup(event):
    if event.char in "wsad":
        pressed_keys[event.char] = False

# E claro:
janela.bind("<KeyRelease>", keyup)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.