【问题标题】:One serial communication - multiple read and write between Python script and Arduino一次串行通信 - Python 脚本和 Arduino 之间的多次读写
【发布时间】:2013-03-30 00:56:34
【问题描述】:

我想在 Python 守护程序和 Arduino 之间建立串行通信。 首先,Python 守护程序建立一个串行连接,该连接将持续到守护程序的整个生命周期。通过这个连接,我想每次 Python 守护进程接收命令时向 Arduino 发送数据并在 acks 变量中接收回数据。

问题是,虽然第一次通信顺利,但之后没有任何东西通过串口发送。如果我为每个请求建立一个新连接,它可以工作,但它会使程序非常慢,我想避免这种情况。 编辑: 真正的问题是当向 arduio 发送正确的字符串时一切顺利,但是当我发送错误的字符串时,串行端口阻塞并且它永远不会再次重新协调正确的字符串(问题是在arduino代码中

Python 代码:

import serial
import time
import sys
from socket import *
import threading
import thread

def handler(clientsock,addr):
    while 1:
        #arduino.flush()
        data = clientsock.recv(BUFSIZ)
        if not data:
            break
        print data
        print data
        #time.sleep(3)
        arduino.write(data)
        #time.sleep(3)
        ack = arduino.readline(1)
        arduino.flush()
        clientsock.send(ack+"\n")
    clientsock.close()

if __name__=='__main__':
    HOST = '0.0.0.0'
    PORT = 21567
    BUFSIZ = 1024
    ADDR = (HOST, PORT)
    arduino = serial.Serial('/dev/ttyACM0',9600,timeout=6)
    serversock = socket(AF_INET, SOCK_STREAM)
    serversock.bind(ADDR)
    serversock.listen(2)

    while 1:
        print 'waiting for connection...'
        clientsock, addr = serversock.accept()
        print '...connected from:', addr
        thread.start_new_thread(handler, (clientsock, addr))

Arduino 代码:

      int relayPinCH1 = 7; // pin de commande du relais 1
  char inData[20]; // Allocate some space for the string
  char inChar=-1; // Where to store the character read
  byte index = 0; // Index into array; where to store the character

void setup()
{
  pinMode(relayPinCH1, OUTPUT);
  Serial.begin(9600);
}



char Comp(char* This) {
    while (Serial.available() > 0) // Don't read unless
                                   // there you know there is data
    {
        if(index < 19) // One less than the size of the array
        {
            inChar = Serial.read(); // Read a character
            inData[index] = inChar; // Store it
            index++; // Increment where to write next
            inData[index] = '\0'; // Null terminate the string
        }
    }
    Serial.flush();
    if (strcmp(inData,This)  == 0) {
        for (int i=0;i<19;i++) {
            inData[i]=0;
        }
        index=0;
        return(0);
    }
    else {
        return(1);
    }
}



void loop()
{
  //Serial.println("Hello Pi");
    if (Comp("l11\n")==0)
    {
      Serial.flush();
      digitalWrite(relayPinCH1, HIGH);
      Serial.println("y");
    }

    if (Comp("l10\n")==0)
    {
      Serial.flush();
      digitalWrite(relayPinCH1, LOW);
      Serial.println("n");
    } 
  delay(1000);
}

【问题讨论】:

    标签: python serial-port arduino


    【解决方案1】:

    在您的 Arduino 代码中,您的逻辑有点古怪 - 所以,我不确定,但您是否在再次开始循环之前将索引清除为 0?看起来一旦 index == 19,它可能会或可能不会重置为 0,具体取决于后面的逻辑。如果您再次输入 Comp() 并且索引 >= 19,那么您将永远不会再次读取串行端口。

    【讨论】:

      【解决方案2】:

      我认为 @Zeus 是完全正确的(因此我赞成这个答案),但也存在其他问题。重申 @Zeus 的意思:

      • index 仅在比较成功时重置为 0。因此,您的缓冲区已满,您要查找的字符串不存在,index 再也不会回到0
      • 一旦index 到达19,就不再进行读取。结果,inData 中的任何内容都保留在 inData 中,并且所有未来的比较都将失败,这意味着 index 永远不会重置为 0

      代码中还有许多其他问题,但主要问题是设计非常脆弱,并且很容易出现您遇到的那种错误。例如,如果您的 Python 脚本发送的换行符是 CR+LF 换行符,但您只期望 CR,您将遇到与现在相同的故障:第一次通信正常,但再也不会。

      我建议您像这样重新组织您的代码:

      • 无论通信内容如何,​​您用于读取串行端口的函数都会从串行端口读取一行并将其返回给调用者(不带换行符)。
      • 调用者将从串行端口接收到的行与已知命令列表进行比较,并相应地执行它们。

      这可能看起来很粗糙,如下所示

      char strCommand[0xFF];
      int idxCommandChar;
      
      // Read a command from serial, returning the command size
      // This function BLOCKS, i.e., doesn't return until a command is available
      int readSerialCommand() {
        // We reset the index to zero on every read: the command is overwritten every time
        idxCommandChar = 0;
      
        // Read serial characters and store them in strCommand
        // until we get a newline
        int in = Serial.read();
        while (in!='\n')  {
          strCommand[idxCommandChar++] = in;
          in = Serial.read();
        }
        // Add the string terminator
        strCommand[idxCommandChar++] = '\0';
        // Return command size
        return idxCommandChar;  
      }
      
      // Get command from serial, and process it.
      void processCommand() {
        readSerialCommand();
        if (strcmp(strCommand, "CMD1")==0) {
          // do something
        } else if (strcmp(strCommand, "CMD2")==0) {
          // do something else
        } else {
          // Unknown command
          Serial.println("Unknown command");
        }
      
      }
      
      void loop() {
        processCommand();
        delay(1000);
      }
      

      此代码在串行上阻塞,即在检测到换行之前不会返回。您可以轻松地将代码修改为非阻塞,可能是这样的:

      /* Read serial characters, if available and store them in strCommand
         until we get a newline
         Returns 0 if no command is available */
      int readSerialCommand() {
        idxCommandChar = 0;
        while (Serial.available()) {
          int in = Serial.read();
          while (in!='\n')  {
            strCommand[idxCommandChar++] = in;
            in = Serial.read();
          }
          strCommand[idxCommandChar++] = '\0';
          return idxCommandChar;  
        }
        return 0;
      }
      
      // Get command from serial (if available), and process it.
      void processCommand() {
        if (readSerialCommand()) {
           ....
      

      在任何一种情况下,您都可能在等待时丢失连续字符,因此您可能需要重新考虑该策略。

      【讨论】:

        猜你喜欢
        • 2020-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多