简体   繁体   English

无法将字符串从python发送到arduino

[英]can't send string from python to arduino

So I am trying to create a simple program that allows me to control the colors of a RGB LED with my computer. 因此,我试图创建一个简单的程序,使我可以用计算机控制RGB LED的颜色。 I created a little window with tkinter on python 3 in order to control the color, but the problem is that when I try to change the color it simply doesn't respond. 为了控制颜色,我在python 3上创建了一个带有tkinter的小窗口,但是问题是当我尝试更改颜色时,它根本没有响应。 I have no idea what is going on. 我不知道发生了什么。 I tried to put the string in the arduino code and it worked out, but it simply doesn't respond when I send through a serial communication. 我试图将字符串放入arduino代码中,但可以解决,但是当我通过串行通信发送时,它根本没有响应。

Arduino code 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]);  


  }

And here is the python code: 这是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")

Update 更新资料

So changing the arduino code (at the part that receives the string) for this: 因此,为此更改arduino代码(在接收字符串的部分):

  while(Serial.available() == 0);
  data = Serial.readStringUntil('\n');
  Serial.setTimeout(0.01);

And the part of the python code which sends the string to this: while 1: window.update_idletasks() window.update() 以及将字符串发送到此的python代码部分: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 lastMsg != finalString:
        finalString= finalString.encode("utf-8")
        arduino.write(finalString)
        lastMsg = finalString

    print(finalString)

The LED changes it's color, but it, sometimes, changes to other colors and the the python program crashes!!!! LED会更改其颜色,但有时会更改为其他颜色,并且python程序崩溃! Is there anything missing in Serial.readStringUntil("\\n") or in the arduino.write(finalString)? Serial.readStringUntil(“ \\ n”)或arduino.write(finalString)中是否缺少任何内容?

You are sending just too many messages one after another to Arduino , so what happens is that when it invokes readString() it takes a very long string , and increments pos past the legitimate interval 0..2 , which means that you are corrupting the memory stack and from there anything can happen. 您正在一次又一次地向Arduino发送太多消息,所以发生的事情是,当它调用readString()时,它需要一个很长的字符串 ,并且会在合法间隔0..2增加pos ,这意味着您正在破坏memory stack ,从那里可能发生任何事情。


Proposed fixes: 建议的修复程序:

  1. Replace Serial.readString() with Serial.readStringUntil('\\n') , the former returns when it times out , whereas the latter returns when it matches a newline character or it times out . Serial.readStringUntil('\\n')替换Serial.readString()前者 超时时返回,后者匹配换行符 超时时返回 The default timeout is 1 second . 默认超时为1秒

  2. Change 更改

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

    to

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

    and remove print("\\n") 并删除print("\\n")

  3. Change your python code so that it sends a message to Arduino only when the content of the message has changed wrt. 更改您的python代码,以便仅在消息内容已更改 wrt时才向Arduino发送消息。 the last one that was sent: 发送的最后一个:

     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) 

Note 01: even after you fixed it, consider posting your Arduino code to code review for some feedback on code styling and strong design . 注意01:即使在修复它之后,也可以考虑将Arduino代码发布到代码审查中,以获取有关代码样式强大设计的一些反馈。

Note 02: Even with the proposed fixes, the source code remains vulnerable to wrong behaviours given the right set of circumstances (eg: what happens if readStringUntil() timeouts before \\n is matched? how do you deal with partial input?) 注02:即使使用了建议的修复程序,在正确的情况下, 源代码仍然容易受到 错误行为的影响 (例如:如果\\n之前readStringUntil()超时匹配,会发生什么情况?如何处理部分输入?)


EDIT 1: The python code crashes due to the fact that you do not check for the validity of objects RedScale , GreenScale and BlueScale before accessing them with get() , and this obviously fails right after the tk window is closed . 编辑1:由于您在使用get()访问对象之前未检查对象RedScaleGreenScaleBlueScale的有效性,因此python代码崩溃,并且 关闭 tk窗口 ,这显然失败了。

A naive solution would be the following: 一个天真的解决办法是以下几点:

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()

Note that, although stackoverflow is overcrowded with people suggesting this solution, i think that it is bad design and I suspect still buggy . 需要注意的是,虽然计算器挤满了人建议这个解决方案,我认为它是坏的设计 ,我怀疑还是马车 A proper solution would be to override the event listener for the adjustment of the Scale instances, so that the value of the Scale is only read and sent when it is actually changed by the user. 正确的解决方案是重写 Scale实例的事件侦听器,以便仅当用户实际更改Scale的值时才读取和发送Scale的值。 I'll let you work out the details. 我会让你弄清楚细节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM