10
\$\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\$
  • \$\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 '12 at 4:12
  • \$\begingroup\$ You're right. I fixed it now. But the problem still remains. \$\endgroup\$ – user1068636 Oct 26 '12 at 4:52
20
\$\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 you Arduino code buffer each character it recieves and only act on the message once it recieves 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 you're 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\$
  • 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\$ – Toby Lawrence Oct 26 '12 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\$ – user1068636 Oct 26 '12 at 13:54
5
\$\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\$
  • \$\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\$ – The Vivandiere Sep 1 '15 at 21:57
  • 1
    \$\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 '15 at 15:05
2
\$\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\$
1
\$\begingroup\$

Use .readline instead of .read

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

\$\endgroup\$
  • \$\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\$ – Nick Alexeev May 4 '15 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\$ – Sean Boddy May 4 '15 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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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