无法从python发送字符串到arduino

时间:2016-12-31 14:22:57

标签: python string tkinter arduino pyserial

所以我试图创建一个简单的程序,允许我用我的电脑控制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)中是否缺少任何内容?

1 个答案:

答案 0 :(得分:2)

您只是将太多消息一个接一个地发送到 Arduino ,那么当它调用 readString()时会发生什么呢?一个非常长的字符串,并在合法间隔pos之后递增0..2,这意味着您正在破坏memory stack,并且从那里可以发生任何事情。

建议的修正:

  1. Serial.readString()替换为Serial.readStringUntil('\n')former超出时返回,而后者则与换行符匹配时返回字符 超时默认超时 1秒

  2. 更改

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

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

    并删除print("\n")

  3. 更改您的python代码,以便仅当消息的内容发生更改时,它才会向 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)
    
  4. 注意01:即使修复了它,也可以考虑将 Arduino 代码发布到code review,以获得有关代码样式的反馈强大的设计

    注意02:即使使用了建议的修补程序,源代码仍然易受攻击 错误行为正确的情况(例如:如果readStringUntil()之前的\n超时匹配会发生什么?你如何处理部分输入?)

    编辑1 python代码因为您没有检查对象RedScaleGreenScale的有效性而崩溃在使用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()
    

    请注意,虽然 stackoverflow 过度拥挤,人们建议使用此解决方案,但我认为它是设计糟糕,我怀疑仍然。一个合适的解决方案是覆盖 事件监听器以调整 Scale 实例,以便只读取Scale的值当用户实际更改时发送。我会让你弄清楚细节。