用Python处理串口(Arduino)数据时出现问题



我试图通过Python脚本用连接到Arduino Uno的操纵杆移动光标,因为这个板没有像Arduino Leonardo那样移动鼠标的库。因此,我需要帮助解决我下面提出的问题。你可以看到代码是如何工作的,问题是我的代码的注释。请给我一个解决办法。

import serial
import pyautogui
import time
#I import the libraries.
arduino_port="/dev/ttyACM0" #Serial port for comunication(ubuntu).
baud=9600#frecuency
ser=serial.Serial(arduino_port, baud)# Connect to /dev/ttyACM0 at 9600 bauds
print("Connected to the arduino port at ", baud, "bauds") # Confirm connection
while True:#I'm using a while because I want it to run while the program is running, forever.
data=ser.readline().decode('utf-8').rstrip() # Decode the data printed by arduino in the serial port.
xyValues=data.split(",")# creates an array like this: ['x','y']
final_xyValues=[]# declaration of a new array
for i in xyValues:
final_xyValues.append(int(i))
#When the loop has finished, I have this array: [x, y], where x and y are integers.
print(final_xyValues)
#to check the problem uncomment the code below:
"""
if len(final_xyValues)==2:
pyautogui.moveRel(final_xyValues[0], final_xyValues[1])
time.sleep(0.2)
"""
"""
Here is where I need help. I want to move the cursor with the values that
the program is constantly receiving and converting to an array called
final_xyValues. The array final_xyValues's first value is the x axis and the
second the y axis.
Take in count that the variable data is a string like this: '405,678', which is
transform to an array with two integers as values. Now, you must know that the values
of final_xyValues are from an analog input of a joystick connected to an Arduino Uno
and read in from the serial port. I want to move the cursor with the analog inputs of the
joystick.
ISSUE: when I uncomment the code from line 21 to 25 the first values of the joystick x and y
position in that moment are ok but after that the data continues identical to the first values
read. The values are correctly and constantly been updated if I comment this part of the code,
if I move the joystick the data changes.
"""

你可以在下面的python代码的最后一个注释中看到操纵杆值的问题。上面写着"ISSUE"。我已经找了好几天了,但是什么都没找到。

#define VRX_PIN  A0 // Arduino pin connected to VRX pin
#define VRY_PIN  A1 // Arduino pin connected to VRY pin
void setup() {
Serial.begin(9600) ;
}
void loop() {
int xValue = analogRead(VRX_PIN);//Read the analog value of A0 pin, x axis.
int yValue = analogRead(VRY_PIN);//Read the analog value of A1 pin, y axis.
// read analog X and Y analog values
Serial.print(xValue);
Serial.print(",");
Serial.println(yValue);
//Result: 'x,y'
}

@michael-butscher写了一个很好的评论:

只是猜测:PC每秒只读取五个值(由于睡眠),但Arduino发送更多,因此它们被缓冲,旧的由PC处理。解决方案:在PC端创建一个线程,不断读取值,并在每次睡眠后仅向主线程提供最新的值。或者你减少Arduino输出的睡眠在这一边。

@michael-butscher阐明了这样一个事实,即在短短的一秒钟的时间内,您可能有一百行0,0511,510,或者恰好是模拟电压读数。例如,

511,510
511,510
511,510
511,510
511,510
511,510
511,510
511,510
511,510
511,510
511,510
511,510
511,510
...

这是因为Arduino循环非常快,并且会很快用相同的值淹没你的pyserial输入缓冲区。

另一方面,你的Python循环非常慢(与Arduino相比)。所以每条线都要花费时间,一条接一条,每0.2秒一次。因此,它将被卡在串行输入的开头,读取这些重复的初始值。

不需要移除time.sleep(0.2)延迟。我同意,当Python循环减慢到可管理的速度时,提高可读性是有帮助的。

在我看来,一个简单的解决方案是,在Python方面,当您准备读取Arduino报告的新测量值时,清除串行输入缓冲区。

我建议你尝试下面的无限while循环:

while True:
# Clear entire serial input buffer
ser.reset_input_buffer()
# Read and ignore the next line.
# This solves the issue that if you start reading now, you 
# may be starting in the middle of a line. So we'll discard
# this possibly incomplete line.
ser.readline()
data=ser.readline().decode('utf-8').rstrip()
print(data)
# 'data' is now guaranteed to be a most recent, complete
# line of measurement data from the Arduino.
time.sleep(0.2)

您应该注意到输出现在总是显示Arduino报告的最新模拟测量值。一旦确认了这一点,您就可以执行之前执行的原始数据行解析(转换为int、检查数组大小等)。

最新更新