2

Python デーモンと Arduino 間のシリアル通信をセットアップしたいと思います。最初に、Python デーモンは、デーモンの存続期間全体にわたって続くシリアル接続をセットアップします。acksこの接続を介して、Arduino にデータを送信し、Python デーモンがコマンドを受信するたびに変数でデータを受信したいと考えています。

問題は、最初の通信はうまくいきますが、その後シリアル経由で何も送信されないことです。リクエストごとに新しい接続を作成すると機能しますが、プログラムが非常に遅くなるため、避けたいと思います。 編集:本当の問題は、正しい文字列を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 にクリアしていますか? インデックス == 19 のように見えますが、後のロジックに応じて 0 にリセットされる場合とされない場合があります。Comp() をもう一度入力して index >= 19 を入力すると、シリアル ポートを再度読み取ることはありません。

于 2013-03-30T04:19:45.000 に答える
0

@Zeusは完全に正しいと思います(したがって、その答えに賛成しました)が、他にも問題があります。@Zeusが言っていることを繰り返すには:

  • index0比較が成功した場合にのみリセットされます。したがって、バッファがいっぱいで、探している文字列が存在せず、index二度と戻ることはありません0
  • index達する19と、それ以上の読み取りは行われません。その結果、 にあるものは にinDataとどまりinData、将来のすべての比較は失敗します。つまり、indexにリセットされることはありません0

コードには他にも多くの問題がありますが、主な問題は、設計が非常に壊れやすく、まさに発生している種類のエラーが発生しやすいことです。たとえば、Python スクリプトが送信する newlinews が改行の CR+LF であるが、CR のみを期待している場合、現在と同じ種類の失敗が発生します。最初の通信は機能しますが、2 回目は機能しません。

次のようにコードを再編成することをお勧めします。

  • シリアル ポートを読み取る関数は、通信の内容に関係なく、シリアル ポートから行を読み取り、それを (改行なしで) 呼び出し元に返します。
  • 呼び出し元は、シリアル ポートから受信した行を既知のコマンドのリストと比較し、それに応じて実行します。

これは次のように大雑把に見えるかもしれません

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 に答える