繁体   English   中英

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

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

因此,我试图创建一个简单的程序,使我可以用计算机控制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代码部分: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)

LED会更改其颜色,但有时会更改为其他颜色,并且python程序崩溃! Serial.readStringUntil(“ \\ n”)或arduino.write(finalString)中是否缺少任何内容?

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


建议的修复程序:

  1. Serial.readStringUntil('\\n')替换Serial.readString()前者 超时时返回,后者匹配换行符 超时时返回 默认超时为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代码发布到代码审查中,以获取有关代码样式强大设计的一些反馈。

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


编辑1:由于您在使用get()访问对象之前未检查对象RedScaleGreenScaleBlueScale的有效性,因此python代码崩溃,并且 关闭 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的值时才读取和发送Scale的值。 我会让你弄清楚细节。

暂无
暂无

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

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