2

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

问题是,虽然第一次通信顺利,但之后没有任何东西通过串口发送。如果我为每个请求建立一个新连接,它可以工作,但它会使程序非常慢,我想避免这种情况。 编辑:真正的问题是当向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);
}
4

2 回答 2

2

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

于 2013-03-30T04:19:45.000 回答
0

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

  • index0在比较成功时重置为。因此,您的缓冲区已满,您要查找的字符串不存在,并且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()) {
     ....

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

于 2013-03-30T20:23:23.707 回答