无法将字符串从 python 发送到 arduino
can't send string from python to arduino
所以我想创建一个简单的程序,让我可以用我的电脑控制 RGB LED 的颜色。我在 python 3 上用 tkinter 创建了一个 window 来控制颜色,但问题是当我尝试更改颜色时它根本没有响应。我不知道发生了什么。我试图将字符串放入 arduino 代码中并且成功了,但是当我通过串行通信发送时它根本没有响应。
Arduino 代码
//pin layout
int red = 12;
int green = 11;
int blue = 10;
//string that will receive
String data;
String subData;
//Color values
int value[3];
void setup() {
Serial.begin(9600);
pinMode(red,OUTPUT);
pinMode(green,OUTPUT);
pinMode(blue,OUTPUT);
}
void loop() {
while(Serial.available() == 0);
data = Serial.readString();
int initialVal =0;
int val;
int pos = 0;
do{
val = data.indexOf(',',initialVal);
subData = data.substring(initialVal,val);
value[pos] = subData.toInt();
pos = pos + 1;
initialVal = val + 1;
}while(val != -1);
Serial.println(data);
analogWrite(red,value[0]);
analogWrite(green,value[1]);
analogWrite(blue,value[2]);
}
这里是 python 代码:
from tkinter import *
from serial import *
window = Tk()
#all definitions for the window
window.title("RGB LED control Panel")
window.geometry("300x180")
window.resizable(False,False)
Title = Label(window, text = "RGB control", width = 15)
Title.grid(row = 0, column = 0, columnspan = 3)
Explanation = Label(window, text = " This window controls the \ncolor of an RGB LED. Have \n fun!!!")
Explanation.grid(row =1 , column = 3)
RedTitle = Label(window, text = "Red", width = 5, bg = "Red")
RedTitle.grid(row = 1, column = 0)
GreenTitle = Label(window, text = "Green", width = 5, bg = "Green")
GreenTitle.grid(row = 1, column = 1)
BlueTitle = Label(window, text = "Blue", width = 5, bg = "Blue")
BlueTitle.grid(row = 1, column = 2)
RedScale = Scale(window, from_ = 0, to = 255, orient = VERTICAL)
RedScale.grid(row = 2, column = 0)
GreenScale = Scale(window, from_ = 0, to = 255, orient = VERTICAL)
GreenScale.grid(row = 2, column = 1)
BlueScale = Scale(window, from_ = 0, to = 255, orient = VERTICAL)
BlueScale.grid(row = 2, column = 2)
#now the serial com with the arduino
arduino = Serial()
arduino.baudrate = 9600
arduino.port = "COM3"
arduino.open()
while 1:
window.update_idletasks()
window.update()
RED = str(RedScale.get())
GREEN = str(GreenScale.get())
BLUE = str(BlueScale.get())
finalString = RED + "," + GREEN + "," + BLUE
arduino.write(finalString.encode("utf-8"))
print(finalString)
print("\n")
更新
因此为此更改 arduino 代码(在接收字符串的部分):
while(Serial.available() == 0);
data = Serial.readStringUntil('\n');
Serial.setTimeout(0.01);
以及 python 代码中将字符串发送至此的部分:
而 1:
window.update_idletasks()
window.update()
RED = str(RedScale.get())
GREEN = str(GreenScale.get())
BLUE = str(BlueScale.get())
finalString = RED + "," + GREEN + "," + BLUE + "\n"
if lastMsg != finalString:
finalString= finalString.encode("utf-8")
arduino.write(finalString)
lastMsg = finalString
print(finalString)
LED 会改变它的颜色,但它有时会变成其他颜色并且 python 程序会崩溃!!!! Serial.readStringUntil("\n") 或 arduino.write(finalString) 中是否缺少任何内容?
你只是 太多 一条又一条消息发送到 Arduino,所以当它调用 readString() 它需要很长的 string,并且递增 pos
超过合法间隔 0..2
,这意味着你正在破坏memory stack
从那里任何事情都有可能发生。
建议的修复:
将Serial.readString()
替换为Serial.readStringUntil('\n')
,formerreturns超时,而后者 returns 当它匹配 换行符 字符 或 它 超时 。 默认超时为1秒。
改变
finalString = RED + "," + GREEN + "," + BLUE
至
finalString = RED + "," + GREEN + "," + BLUE + "\n"
并删除 print("\n")
更改您的 python 代码,使其仅在消息内容 发生更改时才向 Arduino 发送消息 wrt。发送的最后一个:
last_msg = ""
while 1:
window.update_idletasks()
window.update()
RED = str(RedScale.get())
GREEN = str(GreenScale.get())
BLUE = str(BlueScale.get())
finalString = RED + "," + GREEN + "," + BLUE + "\n"
if finalString != last_msg:
arduino.write(finalString.encode("utf-8"))
last_msg = finalString
print(finalString)
注意 01: 即使在您修复它之后,考虑将您的 Arduino 代码发布到 code review 以获取关于 代码样式和强大的设计。
注意 02: 即使有建议的修复,源代码 仍然易受攻击 错误的行为在正确的情况下(例如:如果readStringUntil()
在\n
匹配之前超时会发生什么?你如何处理部分输入?)
编辑 1: python 代码 崩溃是因为您没有检查对象的有效性RedScale
、GreenScale
和 BlueScale
在使用 get()
访问它们之前,这显然 在 tk 之后立即失败window 已关闭.
一个天真的解决方案如下:
import sys
import time
global exitFlag
exitFlag = False
...
def endProgram():
global exitFlag
exitFlag = True
window.destroy()
window.protocol("WM_DELETE_WINDOW", endProgram)
...
last_msg = ""
finalString = ""
while 1:
if not exitFlag:
window.update_idletasks()
if not exitFlag:
window.update()
if not exitFlag:
RED = str(RedScale.get())
GREEN = str(GreenScale.get())
BLUE = str(BlueScale.get())
finalString = RED + "," + GREEN + "," + BLUE + "\n"
if finalString != last_msg:
arduino.write(finalString.encode("utf-8"))
last_msg = finalString
print(finalString)
if exitFlag:
sys.exit()
请注意,尽管 Whosebug 人满为患 人们建议使用此解决方案,但我认为这是 糟糕的设计 我怀疑仍然 有问题 。一个合适的解决方案是 override event listener 以调整 Scale 实例,这样Scale 的值仅在用户实际更改时才被读取和发送。我会让你算出细节。
所以我想创建一个简单的程序,让我可以用我的电脑控制 RGB LED 的颜色。我在 python 3 上用 tkinter 创建了一个 window 来控制颜色,但问题是当我尝试更改颜色时它根本没有响应。我不知道发生了什么。我试图将字符串放入 arduino 代码中并且成功了,但是当我通过串行通信发送时它根本没有响应。
Arduino 代码
//pin layout
int red = 12;
int green = 11;
int blue = 10;
//string that will receive
String data;
String subData;
//Color values
int value[3];
void setup() {
Serial.begin(9600);
pinMode(red,OUTPUT);
pinMode(green,OUTPUT);
pinMode(blue,OUTPUT);
}
void loop() {
while(Serial.available() == 0);
data = Serial.readString();
int initialVal =0;
int val;
int pos = 0;
do{
val = data.indexOf(',',initialVal);
subData = data.substring(initialVal,val);
value[pos] = subData.toInt();
pos = pos + 1;
initialVal = val + 1;
}while(val != -1);
Serial.println(data);
analogWrite(red,value[0]);
analogWrite(green,value[1]);
analogWrite(blue,value[2]);
}
这里是 python 代码:
from tkinter import *
from serial import *
window = Tk()
#all definitions for the window
window.title("RGB LED control Panel")
window.geometry("300x180")
window.resizable(False,False)
Title = Label(window, text = "RGB control", width = 15)
Title.grid(row = 0, column = 0, columnspan = 3)
Explanation = Label(window, text = " This window controls the \ncolor of an RGB LED. Have \n fun!!!")
Explanation.grid(row =1 , column = 3)
RedTitle = Label(window, text = "Red", width = 5, bg = "Red")
RedTitle.grid(row = 1, column = 0)
GreenTitle = Label(window, text = "Green", width = 5, bg = "Green")
GreenTitle.grid(row = 1, column = 1)
BlueTitle = Label(window, text = "Blue", width = 5, bg = "Blue")
BlueTitle.grid(row = 1, column = 2)
RedScale = Scale(window, from_ = 0, to = 255, orient = VERTICAL)
RedScale.grid(row = 2, column = 0)
GreenScale = Scale(window, from_ = 0, to = 255, orient = VERTICAL)
GreenScale.grid(row = 2, column = 1)
BlueScale = Scale(window, from_ = 0, to = 255, orient = VERTICAL)
BlueScale.grid(row = 2, column = 2)
#now the serial com with the arduino
arduino = Serial()
arduino.baudrate = 9600
arduino.port = "COM3"
arduino.open()
while 1:
window.update_idletasks()
window.update()
RED = str(RedScale.get())
GREEN = str(GreenScale.get())
BLUE = str(BlueScale.get())
finalString = RED + "," + GREEN + "," + BLUE
arduino.write(finalString.encode("utf-8"))
print(finalString)
print("\n")
更新
因此为此更改 arduino 代码(在接收字符串的部分):
while(Serial.available() == 0);
data = Serial.readStringUntil('\n');
Serial.setTimeout(0.01);
以及 python 代码中将字符串发送至此的部分: 而 1: window.update_idletasks() window.update()
RED = str(RedScale.get())
GREEN = str(GreenScale.get())
BLUE = str(BlueScale.get())
finalString = RED + "," + GREEN + "," + BLUE + "\n"
if lastMsg != finalString:
finalString= finalString.encode("utf-8")
arduino.write(finalString)
lastMsg = finalString
print(finalString)
LED 会改变它的颜色,但它有时会变成其他颜色并且 python 程序会崩溃!!!! Serial.readStringUntil("\n") 或 arduino.write(finalString) 中是否缺少任何内容?
你只是 太多 一条又一条消息发送到 Arduino,所以当它调用 readString() 它需要很长的 string,并且递增 pos
超过合法间隔 0..2
,这意味着你正在破坏memory stack
从那里任何事情都有可能发生。
建议的修复:
将
Serial.readString()
替换为Serial.readStringUntil('\n')
,formerreturns超时,而后者 returns 当它匹配 换行符 字符 或 它 超时 。 默认超时为1秒。改变
finalString = RED + "," + GREEN + "," + BLUE
至
finalString = RED + "," + GREEN + "," + BLUE + "\n"
并删除
print("\n")
更改您的 python 代码,使其仅在消息内容 发生更改时才向 Arduino 发送消息 wrt。发送的最后一个:
last_msg = "" while 1: window.update_idletasks() window.update() RED = str(RedScale.get()) GREEN = str(GreenScale.get()) BLUE = str(BlueScale.get()) finalString = RED + "," + GREEN + "," + BLUE + "\n" if finalString != last_msg: arduino.write(finalString.encode("utf-8")) last_msg = finalString print(finalString)
注意 01: 即使在您修复它之后,考虑将您的 Arduino 代码发布到 code review 以获取关于 代码样式和强大的设计。
注意 02: 即使有建议的修复,源代码 仍然易受攻击 错误的行为在正确的情况下(例如:如果readStringUntil()
在\n
匹配之前超时会发生什么?你如何处理部分输入?)
编辑 1: python 代码 崩溃是因为您没有检查对象的有效性RedScale
、GreenScale
和 BlueScale
在使用 get()
访问它们之前,这显然 在 tk 之后立即失败window 已关闭.
一个天真的解决方案如下:
import sys
import time
global exitFlag
exitFlag = False
...
def endProgram():
global exitFlag
exitFlag = True
window.destroy()
window.protocol("WM_DELETE_WINDOW", endProgram)
...
last_msg = ""
finalString = ""
while 1:
if not exitFlag:
window.update_idletasks()
if not exitFlag:
window.update()
if not exitFlag:
RED = str(RedScale.get())
GREEN = str(GreenScale.get())
BLUE = str(BlueScale.get())
finalString = RED + "," + GREEN + "," + BLUE + "\n"
if finalString != last_msg:
arduino.write(finalString.encode("utf-8"))
last_msg = finalString
print(finalString)
if exitFlag:
sys.exit()
请注意,尽管 Whosebug 人满为患 人们建议使用此解决方案,但我认为这是 糟糕的设计 我怀疑仍然 有问题 。一个合适的解决方案是 override event listener 以调整 Scale 实例,这样Scale 的值仅在用户实际更改时才被读取和发送。我会让你算出细节。