I'm writing a simple python code to receive a serial string defining a joystick's position, separate X and Y and do keyboard commands accordingly.
In my code I'm attempting to that, while the user holds the joystick to the right, the -> stays pressed and it's release afterwards. To do this I'm using the PyUserInput library. What happens however is that the right key stays pressed indefinately and the character (Megaman inside an emulator) just runs towads it's death. Could anyone help me figure out why is this happening and how can I fix it?
import serial
from pykeyboard import PyKeyboard
control = PyKeyboard()
try:
arduino = serial.Serial('/dev/ttyACM0', 9600)
except:
print "Failed to connect on /dev/ACMDUSB0"
while True:
xy = arduino.readline()
if xy is "":
print ("NULL")
else:
x, y = xy.split("_")
x = int(x)
y = int(y)
while(x > 700):
control.press_key(control.right_key)
control.release_key(control.right_key)
print ("X = {0}\nY = {1}".format(x, y))
As pointed by #Ignacio Vazquez-Abrams in the comments section the error was due to me not rechecking which controls were pressed at the end of the while loop, thus making it run indefinately.
Related
I'm trying to make a hotkey that when i click in some other program (while script running) a hotkey "1" for example or any other key i assign that it write down the mouse positions and RGB in a text file a single time without spamming it and here is the closest code i could found that at least print the result of mouse position but it doesn't get the colors "RGB"
import pyautogui
import time
import keyboard
c = open("log.txt", "w")
def a():
while True:
if keyboard.read_key() == "1":
x, y = pyautogui.position()
positionStr = str(x).rjust(4) + str(y).rjust(4)
print(positionStr)
c.write(positionStr + '\n')
c.flush()
time.sleep(0.1)
else:
a()
a()
how ever i did find out that one codepyautogui.displayMousePosition() that do show xy and also RGB but im a beginner script kid that have no idea how to save the results to any .txt file
side note: the shown code is copied from some other answer here "https://stackoverflow.com/questions/64046117/write-mouse-position-to-txt-file" and just made the hotkey edit part
and i tried to get it done with myself like this:
c = open("log.txt", "w")
def b(): pyautogui.displayMousePosition()
def a():
while True:
if keyboard.read_key()== '1':
print(b())
c.write(b())
c.flush()
sleep(1)
else:
a()
a()
but it just stuck in the print(b()) command like in a infinite loop showing live xy and RGB but not saving it and when doing ctrl+c it dont save
ok guy i figured it out
c = open("log.txt", "w")
def a():
while True:
if keyboard.is_pressed('1'):
x, y = pyautogui.position()
r,g,b = pyautogui.pixel(x,y)
positionsANDrgb = str(r).rjust(4)+str(g).rjust(4)+str(b).rjust(4)
print(positionsANDrgb)
c.write(positionsANDrgb+'\n')
c.flush()
sleep(1)
a()
i had to add the "sleep(1)" cuz in my single press takes some time like 2third of a second or something like that and command spam as long as i was pressing the hot key
and the '\n' part means new line
u can name the "positionsANDrgb" any thing u want but i just chose this name to make it easier to know what this name for
u dont need the print(positionsANDrgb) part it dont have anything to do with the log.txt but i just added it to see when command is active and "rjust(4)" it adds 4 character of what ever u choose(default is sapce) like "rjust(4,'b')" supposed to give 4 b's sometimes it dont work just increase the 4 till it do in case u wanted it in future
i hope this helped u there who ever needed this like me
I want to paint some special words while the program is getting them , actually in real-time .
so I've wrote this piece of code which do it quite good but i still have problem with changing the location of the pointer with move keys on keyboard and start typing from where i moved it .
can anyone give me a hint how to do it ?
here is the CODE :
from colorama import init
from colorama import Fore
import sys
import msvcrt
special_words = ['test' , 'foo' , 'bar', 'Ham']
my_text = ''
init( autoreset = True)
while True:
c = msvcrt.getch()
if ord(c) == ord('\r'): # newline, stop
break
elif ord(c) == ord('\b') :
sys.stdout.write('\b')
sys.stdout.write(' ')
my_text = my_text[:-1]
#CURSOR_UP_ONE = '\x1b[1A'
#ERASE_LINE = '\x1b[2K'
#print ERASE_LINE,
elif ord(c) == 224 :
set (-1, 1)
else:
my_text += c
sys.stdout.write("\r") # move to the line beginning
for j, word in enumerate(my_text.split()):
if word in special_words:
sys.stdout.write(Fore.GREEN+ word)
else:
sys.stdout.write(Fore.RESET + word)
if j != len(my_text.split())-1:
sys.stdout.write(' ')
else:
for i in range(0, len(my_text) - my_text.rfind(word) - len(word)):
sys.stdout.write(' ')
sys.stdout.flush()
Doing it the easy way
As you already seem to be using the colorama module, the most easy and portable way to position the cursor should be to use the corresponding ANSI controlsequence (see: http://en.m.wikipedia.org/wiki/ANSI_escape_code)
The one you are looking for should be CUP – Cursor Position (CSI n ; m H)positioning the cursor in row n and column m.
The code would look like this then:
def move (y, x):
print("\033[%d;%dH" % (y, x))
Suffering by doing everything by hand
The long and painful way to make things work even in a windows console, that doesn't know about the above mentioned control sequence would be to use the windows API.
Fortunately the colorama module will do this (hard) work for you, as long as you don't forget a call to colorama.init().
For didactic purposes, I left the code of the most painful approach leaving out the functionality of the colorama module, doing everything by hand.
import ctypes
from ctypes import c_long, c_wchar_p, c_ulong, c_void_p
#==== GLOBAL VARIABLES ======================
gHandle = ctypes.windll.kernel32.GetStdHandle(c_long(-11))
def move (y, x):
"""Move cursor to position indicated by x and y."""
value = x + (y << 16)
ctypes.windll.kernel32.SetConsoleCursorPosition(gHandle, c_ulong(value))
def addstr (string):
"""Write string"""
ctypes.windll.kernel32.WriteConsoleW(gHandle, c_wchar_p(string), c_ulong(len(string)), c_void_p(), None)
As already stated in the comment section this attempt still leaves you with the problem, that your application will only work in the named console, so maybe you will still want to supply a curses version too.
To detect if curses is supported or you will have to use the windows API, you might try something like this.
#==== IMPORTS =================================================================
try:
import curses
HAVE_CURSES = True
except:
HAVE_CURSES = False
pass
I have a program that is supposed to take joystick position readings from an arduino (over serial), and translate them to mouse movements on my computer.
There is only one problem with this...
The string to integer conversion is way too slow, and it takes forever for the movements to register. I need either a faster way to convert a string to an integer value, or a way to skip the conversion altogether.
This is my current code:
import serial
import pyautogui
import time
ser = serial.Serial('COM3', 9600, timeout=1)
while True:
time.sleep(0.0001)
ser_bytes = ser.readline()
decoded_bytes = ser_bytes[0:len(ser_bytes)-2].decode("utf-8")
pos = decoded_bytes.split(':')
xpos = int(pos[0])
ypos = int(pos[1])
print("x:", xpos, " y:", ypos)
pyautogui.move(xpos, ypos)
Note: Output from arduino has 3 values:
0:0:0
First number: x
Second number: y
Third number: joystick button
Perhaps something like this will work? This way you can read more than one line of input for each time you call move(). Some lines of input will be ignored, but that seems necessary if you're getting input faster than you can use it.
import serial
import pyautogui
import time
ser = serial.Serial('COM3', 9600, timeout=1)
while True:
time_to_move = time.time() + 0.001
while True:
ser_bytes = ser.readline()
if time.time() >= time_to_move:
break
x_bytes, y_bytes = ser_bytes[:-2].split(b':')
x, y = int(x_bytes), int(y_bytes)
pyautogui.move(x, y)
Hey guys I am sending load cell data to my raspberry PI via Arduino. The Arduino sends out data to serial in chunks like this:
0,0
2,3
5,6
0,0
So what I want to do is split the left reading from the right reading using the split function and the following python code:
import serial
ser = serial.Serial('/dev/ttyACM0',9600)
while True:
read_serial=ser.readline()
x = read_serial
y = x.split(",")
left = y[0]
right = y[1]
print(left)
print(' ')
print(right)
I get the following error:
File "arduino_communication.py", line 10, in <module>
right = y[1]
IndexError: list index out of range
When I comment out that line and also comment out right = y[1] I get the reading of the left load cell correctly. So I'm a bit unsure of what the reason is as to why I'm not able to get the right load cell (which has been split into position 1 of an array)
maybe serial data hasn't comma or empty string.
print x before splitting.
If sometimes serial data hasn't comma or empty string, use try/except please.
try:
y = x.split(",")
left = y[0]
right = y[1]
except IndexError:
right = 0(or use the other value)
I think the problem is that your python script is trying to read the serial line faster than your arduino is writing values, which means that sometimes the python script reads the serialline as an empty string like this: ''.
If you put all the code inside a try/block, the code will only run when the arduino actually has wrote some values.
Hopefully this will help you:
while True:
try:
read_serial=ser.readline()
x = read_serial
y = x.split(",")
left = y[0]
right = y[1]
print(left)
print(' ')
print(right)
except Exception as e:
raise
Actually I am importing serial data from arduino and I am using python to move the current location of the mouse at specific pixels. My problem is whenever my if statement is true for even one second, python performs the function which is (mousemove) to move the mouse for more than 5 to 10 seconds. I am getting delayed response everytime. I want the program to work instantly as reading changes so I can move mouse smoothly.
My code:
import pyautogui
import serial
irData = serial.Serial('com3',9600)
print('Press Ctrl-C to quit.')
def movemouse( int ):
print(dataint)
pyautogui.moveTo(500,500)
return;
while 1:
while(irData.inWaiting()==0):
pass
data = irData.readline() #collecting data from serial port and assigning into data varibale
try:
dataint = int(data) # Return an integer value from a string
x, y = pyautogui.position() # Assign the mose position into varibale x and y
positionStr = 'X: ' + str(x).rjust(4) + ' Y: ' + str(y).rjust(4)
#It allows the program to take same amount of space inspite of having different integer values as in unit or thousands and show it in proper x & y format.
if dataint >=120:
movemouse(dataint)
else:
print(dataint) #Print the current mouse coordinates.
except KeyboardInterrupt:
print "Done"