arduino에서 한 번에 한 문자가 아닌 전체 문자열을 어떻게 수신합니까?


11

이 웹 사이트의 지침을 성공적으로 따랐습니다.

http://www.doctormonk.com/2012/04/raspberry-pi-and-arduino.html

웹 사이트에서 지정한대로 pi와 내 arudino mega 사이의 커뮤니케이션을 얻을 수있었습니다.

그러나 LED가 깜박이는 횟수를 나타내는 정수를 보내는 대신 ASCII 텍스트를 다음과 같이 보내려고합니다.

파이에서 arduino로 "MOVE 5 METERS FORWARD", "TURN LEFT", "MOVE 10 METERS BACKWARD".

다음 코드를 작성했습니다.

char inData[64];
char inChar=-1;

void setup(){
   Serial.begin(9600);
   Serial.begin("Waiting for Raspberry Pi to send a signal...\n");
}


void loop(){
    byte numBytesAvailable= Serial.available();

    // if there is something to read
    if (numBytesAvailable > 0){
        // store everything into "inData"
        int i;
        for (i=0;i<numBytesAvailable;i++){
            inChar= Serial.read();
            inData[i] = inChar;
        }

        inData[i] = '\0';


        Serial.print("Arduino Received: ");
        Serial.println(inData);
    }
}

Arduino Mega 2560에 위의 코드를 성공적으로 플래시했습니다.

Raspberry Pi와 콘솔에서 파이썬 터미널로 전환했습니다.

import serial
ser = serial.Serial('/dev/ttyACM1',9600)
ser.write("MOVE")

Arduino의 Serial Monitor에 표시되는 내용은 다음과 같습니다.

Arduino Received: M
Arduino Received: O
Arduino Received: V
Arduino Received: E

그러나 내가 원하는 것은 :

Arduino Received: MOVE

모든 문자를 inData 버퍼로 가져 오기 위해 위의 코드를 어떻게 변경합니까?


코드를 올바르게 복사 했습니까? inData의 내용에 관계없이 "Arduino Received"행은 한 번만 인쇄됩니다. 이것이 모두 setup () 함수에 있는지?
NickHalden

네가 옳아. 나는 지금 고쳤다. 그러나 문제는 여전히 남아 있습니다.
user1068636

답변:


23

문제는 Arduino가 너무 빨리 루핑되어 if (numBytesAvailable > 0)직렬 포트를 통해 도착하는 각 문자 사이에서 여러 번 라인 을 실행한다는 것 입니다. 따라서 캐릭터가 도착하자마자 캐릭터를 잡고 0에서 1로 반복하며 단일 문자를 인쇄합니다.

파이썬 프로그램의 각 명령 뒤에 줄 끝 문자 ( '\ n')를 보내야합니다. 그런 다음 Arduino 코드가 수신하는 각 문자를 버퍼링하고 줄 끝 문자를 수신 한 후에 만 ​​메시지에 대해 조치를 취하십시오.

따라서 파이썬 코드를 변경하면 다음과 같이 줄 끝 문자를 보냅니다.

import serial
ser = serial.Serial('/dev/ttyACM1',9600)
ser.write("MOVE\n")

그러면 Arduino 코드는 다음과 같습니다.

// Buffer to store incoming commands from serial port
String inData;

void setup() {
    Serial.begin(9600);
    Serial.println("Waiting for Raspberry Pi to send a signal...\n");
}

void loop() {
    while (Serial.available() > 0)
    {
        char recieved = Serial.read();
        inData += recieved; 

        // Process message when new line character is recieved
        if (recieved == '\n')
        {
            Serial.print("Arduino Received: ");
            Serial.print(inData);

            inData = ""; // Clear recieved buffer
        }
    }
}

1
또한 더 일반적인 사용법을 위해 이것에 대한 잠재적 인 비틀림 (편리한 String 클래스가없는 C에서와 같이)은 아직 \ n을 받았는지 버퍼에 있는지 확인합니다. 이렇게하면 복사본을 만들기 전에 모든 것을 내부 버퍼에 보관합니다. 여기서 가장 큰 단점은 내부 버퍼가 가장 긴 단일 라인을 캡처 할 수있을만큼 커야한다는 것입니다. 그렇지 않으면 String (아마도) 메모리를 다시 계산하고 할당하여 자체 확장하는 것과 같은 것을 피할 때 처리 속도가 향상 될 수 있습니다.
Toby Lawrence

코드가 작동했습니다! inData = ""및 inData + =와 같은 몇 줄을 변경해야했습니다. 나는 컴파일러가 그것을 좋아한다고 생각하지 않는다.
user1068636

6

파이썬 스크립트가 4 바이트를 전송하고, M, O, V,와 E. Arduino는 이것이 단일 문자열이라는 것을 어떻게 알 수 있습니까? 파이썬 코드는 다음과 같습니다.

ser.write("MOVE")

완전히 동일한

ser.write("MO")
ser.write("VE")

아두 이노의 관점에서. 직렬 포트는 문자열이 아닌 문자를 전송합니다.

코드에서 Arduino는 빠르므로 (9600 보드 속도와 비교할 때) 호출 할 때마다 Serial.available()4 문자 중 하나만 볼 수 있습니다. 그것이 당신이 한 결과를 얻은 이유입니다.

해야 할 일은 문자열을 구분하는 방법, 즉 파이썬에서 문자열을 표시하여 Arduino가 수신 하는 개별 문자문자열의 고급 개념에 추가 할 수 있도록하는 것 입니다.

줄을 사용하는 것은 간단합니다 : 줄 바꿈 문자 ( '\n')로 끝나는 모든 문자열을 보냅니다 . Arduino에서 문자를 읽고 문자열에 추가하십시오. 가 보이면 '\n'문자열이 끝나서 인쇄 할 수 있습니다.


개행 문자를 기다리는 것보다 느리게 문자열에 개별 문자를 추가하지 않고 개행 문자를 수신 할 때 한 번에 전체 문자 시퀀스를 읽는 것이 아닙니다.
Vivandiere

2
무엇을 제안하고 있는지 잘 모르겠습니다. 줄 바꿈 문자를 읽지 않고 "기다릴"수 없으며, 읽을 때까지 반드시 이전의 모든 문자를 읽어야합니다. "문자열에 추가"인지 또는 다른 방법으로 저장하는 방법은 사용자에게 달려 있습니다.
Jim Paris

2
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

위 코드는 Pi와 Arduino 사이의 연결에서 완벽하게 작동합니다.


1

.readline대신에 사용.read

나는 같은 문제가 있었고 이것이 바로 고쳤다. 이것이 도움이 되었기를 바랍니다!


EE.SE에 대한 답변은 약간 얇습니다. 특히 이것이 2 살짜리 실이라는 것을 고려하십시오. 정교하게 작성하십시오.
Nick Alexeev

스택에 오신 걸 환영합니다, 샘 기꺼이 탑승하게되어 기쁩니다. 미래에 우리의 글을 찾는 모든 사람이 그 지식을 최대한 활용할 수 있도록 가능한 한 명확하고 상세하게 노력하기 때문에 다른 많은 포럼과는 다릅니다. 당신은 있었나요 정확히 같은 문제가? 그와 정확한 구성 요소? 그리고 그 정확한 코드? 이 설정에서 어떤 조건이 코드를 작동 시켰으며, 왜 이전에는 작동하지 않았습니까? 커뮤니티는 여러분의 도움 통찰력을 원합니다 .
Sean Boddy

0

이것이 첫 번째 예에서 내가 한 방법입니다.

String readString;

void setup()
{
    Serial.begin(9600); // initialization
}

void loop()
{
    char incomingByte;
    while (Serial.available() > 0)
    {
        delay(10); // if the data came
        incomingByte = Serial.read(); // read byte
        //Serial.println(incomingByte);
        readString += incomingByte;
    }

    if(readString != "")
    {
        Serial.print("arduino recived this : ");
        Serial.println(readString);
    }
    readString = "";
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.