【问题标题】:can't send string from python to arduino无法将字符串从 python 发送到 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上的串口监视器中写入字符串,效果很好),但是当我发送代码时它根本没有响应。

标签: python string tkinter arduino pyserial


【解决方案1】:

您只是一个接一个地向 Arduino 发送 太多 消息,所以当它调用 readString() 时会发生一个很长的字符串,并增加pos 超过合法间隔0..2,这意味着您正在破坏memory stack,从那里任何事情都可能发生。


建议的修复:

  1. Serial.readString()替换为Serial.readStringUntil('\n')former超时时返回,而后者在匹配换行符字符时返回strong>或它超时默认超时时间是1秒

  2. 改变

    finalString = RED + "," + GREEN + "," + BLUE
    

    finalString = RED + "," + GREEN + "," + BLUE + "\n"
    

    并删除print("\n")

  3. 更改您的 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 代码 崩溃是因为您之前没有检查对象 RedScaleGreenScaleBlueScale 的有效性使用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()

请注意,虽然 stackoverflow 人满为患 有人建议这种解决方案,但我认为这是 糟糕的设计,我仍然怀疑 越野车。一个合适的解决方案是覆盖 事件监听器 来调整 Scale 实例,这样 Scale 的值只会被读取并在用户实际更改时发送。我会让你弄清楚细节。

【讨论】:

  • 嘿,感谢您的回复,但现在的问题是,如果我更改例如绿色,它将主要是绿色,但有时它会很快变为蓝色并返回绿色,最后程序崩溃了。
  • @ddmdavid 正如我在 note 中所写,您的代码仍然不够健壮 无法处理部分输入 .要么您将具有固定 widthint 值从 Python 发送到 Arduino(例如 001 而不是 1),然后等到Serial 缓冲区中至少有12 字节,或者您将所有字节累积到长度为12 的本地数组中,并且只有当您匹配整行时,您才解码存储在中的RGB 值它。
  • crash 是因为您在使用get() 访问对象之前没有检查对象RedScaleGreenScaleBlueScale 的有效性,当您关闭 tk 窗口 时,这显然会失败,因为 它只关闭窗口,释放其资源,并且不退出 python 代码
  • 不,但问题是 arduino 很好,但是 python 程序只是崩溃了,我不明白为什么。
  • 我刚刚向您解释了原因:关闭窗口时,python 代码仍在运行,因此它会尝试访问不再有效的对象 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多