一个串行通信 - Python脚本和Arduino之间的多次读写

时间:2013-03-30 00:56:34

标签: python serial-port arduino

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

问题在于,当第一次通信顺利时,之后没有任何内容通过串行发送。如果我为它的每个请求建立一个新的连接,但它使程序非常慢,我想避免。 编辑真正的问题是,当发送正确的字符串到arduio evrything顺利但是当我发送错误的串口端口块并且它永远不会再次重新确定corrct字符串时(问题是在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);
}

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

我认为 @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()) {
     ....

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