无法将字符串从 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 代码 崩溃是因为您之前没有检查对象 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()

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

【讨论】:

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

以上是关于无法将字符串从 python 发送到 arduino的主要内容,如果未能解决你的问题,请参考以下文章

如何将信息从 ComboBox 发送到 Python

Javascript将字符串发送到python脚本

如何将 JSON 对象从 Python 脚本发送到 jQuery?

将数据从 Python Web 套接字客户端发送到 Django 通道

将协议缓冲区编码的消息从 Python 服务器发送到 Java 客户端

无法从 python 服务器将图像上传到 Firebase 存储