无法将字符串从 python 发送到 arduino
Posted
技术标签:
【中文标题】无法将字符串从 python 发送到 arduino【英文标题】:can't send string from python to arduino 【发布时间】:2016-12-31 14:22:57 【问题描述】:所以我正在尝试创建一个简单的程序,让我可以用我的计算机控制 RGB LED 的颜色。我在 python 3 上用 tkinter 创建了一个小窗口以控制颜色,但问题是当我尝试更改颜色时它根本没有响应。我不知道发生了什么。我试图将字符串放入 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.close()
调用:可能存在 Python 程序时数据没有刷新。
我已经尝试过了,但我认为问题在于发送字符串的方式。串口门没有问题(我尝试直接在arduino上的串口监视器中写入字符串,效果很好),但是当我发送代码时它根本没有响应。
【参考方案1】:
您只是一个接一个地向 Arduino 发送 太多 消息,所以当它调用 readString() 时会发生一个很长的字符串,并增加pos
超过合法间隔0..2
,这意味着您正在破坏memory stack
,从那里任何事情都可能发生。
建议的修复:
将Serial.readString()
替换为Serial.readStringUntil('\n')
,former在超时时返回,而后者在匹配换行符字符时返回strong>或它超时。 默认超时时间是1秒。
改变
finalString = RED + "," + GREEN + "," + BLUE
到
finalString = RED + "," + GREEN + "," + BLUE + "\n"
并删除print("\n")
更改您的 python 代码,使其仅在消息内容已更改 wrt 时才向 Arduino 发送消息。最后发送的:
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,以获取有关 代码样式 和 的反馈em>强大的设计。
注意 02:即使有建议的修复,源代码仍然容易受到错误行为的影响,因为正确的情况(例如:如果在\n
匹配之前readStringUntil()
超时会发生什么?你如何处理部分输入?)
编辑 1: python 代码 崩溃是因为您之前没有检查对象 RedScale
、GreenScale
和 BlueScale
的有效性使用get()
访问它们,这显然在 tk 窗口 关闭之后失败。
天真的解决方案如下:
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()
请注意,虽然 *** 人满为患 有人建议这种解决方案,但我认为这是 糟糕的设计,我仍然怀疑 越野车。一个合适的解决方案是覆盖 事件监听器 来调整 Scale 实例,这样 Scale 的值只会被读取并在用户实际更改时发送。我会让你弄清楚细节。
【讨论】:
嘿,感谢您的回复,但现在的问题是,如果我更改例如绿色,它将主要是绿色,但有时它会很快变为蓝色并返回绿色,最后程序崩溃了。 @ddmdavid 正如我在 note 中所写,您的代码仍然不够健壮 无法处理部分输入 .要么您将具有固定 width 的int
值从 Python 发送到 Arduino(例如 001
而不是 1
),然后等到Serial
缓冲区中至少有12
字节,或者您将所有字节累积到长度为12
的本地数组中,并且只有当您匹配整行时,您才解码存储在中的RGB
值它。
crash 是因为您在使用get()
访问对象之前没有检查对象RedScale
、GreenScale
和BlueScale
的有效性,当您关闭 tk 窗口 时,这显然会失败,因为 它只关闭窗口,释放其资源,并且不退出 python 代码。
不,但问题是 arduino 很好,但是 python 程序只是崩溃了,我不明白为什么。
我刚刚向您解释了原因:关闭窗口时,python 代码仍在运行,因此它会尝试访问不再有效的对象 :)以上是关于无法将字符串从 python 发送到 arduino的主要内容,如果未能解决你的问题,请参考以下文章
如何将 JSON 对象从 Python 脚本发送到 jQuery?
将数据从 Python Web 套接字客户端发送到 Django 通道