11
\$\begingroup\$

I followed the instructions on this website successfully:

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

and I was able to get communication between the pi and my arudino mega exactly as the website specifies.

However, instead of sending an integer representing the number of times the LED blinks, I want to sent ASCII text like:

"MOVE 5 METERS FORWARD", "TURN LEFT", "MOVE 10 METERS BACKWARD" to the arduino from the pi.

I wrote the following code:

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);
    }
}

I flashed above code succesfully to my Arduino Mega 2560.

I switched to my python terminal on the Raspberry Pi and in the console I typed:

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

What gets displayed on my Arduino's Serial Monitor is as follows:

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

But what I want is:

Arduino Received: MOVE

How do I change the code above to get all characters into the inData buffer?

\$\endgroup\$
2
  • \$\begingroup\$ Are you sure you've copied your code correctly? The way I see your code, regardless of what's in inData, the line "Arduino Received" would only ever be printed once. You sure that's all in your setup() function? \$\endgroup\$
    – NickHalden
    Oct 26, 2012 at 4:12
  • \$\begingroup\$ You're right. I fixed it now. But the problem still remains. \$\endgroup\$ Oct 26, 2012 at 4:52

6 Answers 6

24
\$\begingroup\$

The problem is that the Arduino is looping around so fast, it will execute the if (numBytesAvailable > 0) line several times between each character arriving through the serial port. So as soon as a character does arrive, it grabs it, loops from zero to one, and prints a single character out.

What you should do is send an end of line character ('\n') after each command from your Python program. Then have your Arduino code buffer each character it receives and only act on the message once it receives the end-of-line character.

So if you change your Python code do send an end of line character, like so:

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

Then your Arduino code can be something like this:

// 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
        }
    }
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Also, a potential twist on this for more generic usages (like in straight up C where you don't have a convenient String class) is that you peek at what's in the buffer to see if you've received a \n yet. This way you keep everything in the internal buffer before you make a copy of it. The downfall here is that the internal buffer has to be big enough to let you capture your longest single line. Otherwise, you potentially gain in processing speed as you avoid likes like String (presumably, that is) recomputing and allocating memory to expand itself. \$\endgroup\$ Oct 26, 2012 at 11:57
  • \$\begingroup\$ Your code worked! I had to change a couple lines like inData="" and inData+= received. I don't think the compiler liked it. \$\endgroup\$ Oct 26, 2012 at 13:54
6
\$\begingroup\$

Your Python script is sending four bytes, M, O, V, and E. How is the Arduino supposed to know that that's a single string? Consider that the Python code:

ser.write("MOVE")

is completely identical to

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

from the Arduino's point of view. Serial ports transfer characters, not strings.

In your code, the Arduino is fast (compared to the 9600 baud rate), so every time it calls Serial.available(), it only sees one of those four characters. That's why you got the output you did.

What you'll need to do is come up with some way of delimiting strings, i.e. marking them in some way from Python so that the Arduino can append the individual characters that it receives into your high-level concept of a string.

Using lines is straightforward: send every string terminated with a newline character ('\n'). On the Arduino, read characters and append them to your string. When you see a '\n', the string is over and you can print it.

\$\endgroup\$
2
  • \$\begingroup\$ Isn't appending individual characters to a string slower than just waiting for the newline character, and reading in the entire character sequence in one go when the newline character is received. \$\endgroup\$ Sep 1, 2015 at 21:57
  • 2
    \$\begingroup\$ Not sure what you're proposing -- you can't "wait" for a newline character except by reading it, and by the time you've read it, you necessarily read all the previous characters as well (which means they need to have been saved in some way -- whether that's "appending to a string" or some other method of saving them is up to you). \$\endgroup\$
    – Jim Paris
    Sep 10, 2015 at 15:05
3
\$\begingroup\$
  if(Serial.available() > 0) {
     str = Serial.readStringUntil('\n');
     Serial.println(str);

The above code works perfect on my connection between Pi and Arduino

\$\endgroup\$
0
\$\begingroup\$

Use .readline instead of .read

I had the same issue and this fixed it right away. Hope this helped!

\$\endgroup\$
2
  • \$\begingroup\$ This is a bit thin for an answer on EE.SE. Especially considering that this is a 2 year old thread. Please elaborate. \$\endgroup\$ May 4, 2015 at 3:37
  • \$\begingroup\$ Welcome to the stack, sam. We're glad to have you aboard. This isn't like a lot of other forums, in that we try hard to be as clear and detailed as possible, so that every person finding our writing in the future can get the maximum benefit from that knowledge. Did you have the exact same issue? With those exact components? And that exact code? What conditions in this setup made your code work, and why didn't it work before? The community wants your help, and your insight. \$\endgroup\$
    – user39962
    May 4, 2015 at 4:12
0
\$\begingroup\$

This is how I did it from the first example:

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 = "";
}
\$\endgroup\$
0
\$\begingroup\$

With both Putty and Tera Term hyperterminal programs the only way I could detect a new line was to use cartridge return detection '\r' instead of '\n' linefeed. Then use the trim command to remove unwanted handshaking characters. For this project I needed to use a TTL serial input and not USB. Using the Arduino terminal select "Carriage return" instead of "Newline" Sample code below that forms a string to process instead of a byte.

if (Serial1.available() > 0) {
    char inChar = (char)Serial1.read();
    // add it to the inputString:
    inputString += inChar;
    //Serial1.println(inChar, BIN); Used while testing to see hidden characters
    if (inChar == '\r') {  // use '\n' for new line and '\r' for Carriage return 
      inputString.trim(); //trim string to remove handshaking characters CR and LF
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.