Go Down

Topic: USB Read/Write between Arduino and Ubuntu pc (Read 4359 times) previous topic - next topic

marcus barnet

I have to control my Arduino from Ubuntu and so i connected it to my pc with the USB cable.
From my pc, i have to send some command strings to Arduino and wait for the answer.

For example:

my pc sends "check"
Arduino answer: "everything_ok"
my pc then sends: "start"
Arduino: receive "start" and begin some routines
and so on.

I wrote a C code and it does not work everytime and it is not able to read and receive strings in the correct way.
I'm using termios to open and manage the serial port and then i use these functions to read and receive:

Code: [Select]
int serialport_write(int fd, const char* str)
{
    int len = strlen(str);
    int n = write(fd, str, len);
    if( n!=len )
        return -1;
    return 0;
}

int serialport_read(int fd)
{

unsigned char c='D';
while (c !='q')
{

if (read(fd,&c,1)>0)        write(STDOUT_FILENO,&c,1);              // if new data is available on the serial port, print it out
if (read(STDIN_FILENO,&c,1)>0)  write(fd,&c,1);                     // if new data is available on the console, send it to the serial port
}
   
return 0;

}


Can you help me to solve my problem, please?
Any input or advice?

PaulS

Quote
I wrote a C code and it does not work everytime

Does not work every time? Or, does not work any time?

When the PC is sending, does the RX light on the Arduino flash?

marcus barnet

It works.. sometimes.

Arduino receives something but not the correct string because, as i think, it receives also some garbage and so it is not able to recognize the full correct string.
In fact, when i send strings from my application, RX blinks, but it doesn't recognize the commands every time.

I was reading about LibSerial as a more robust solution even if i'd like to continue to use C instead of C++.

PaulS

Quote
It works.. sometimes.

We'd need to see ALL of your PC code and your Arduino code.

marcus barnet

#4
Jan 26, 2012, 08:27 pm Last Edit: Jan 26, 2012, 08:35 pm by marcus barnet Reason: 1
I'm using LibSerial on Ubuntu because this library seems to be more roboust.

At the moment, i'm able to read correctly all the data sent by Arduino, but i'm not able to write any commands because when i try to send "check" string, i receive nothing and sometimes i receive "Error".
When i try to write on serial port, TX led blinks on Arduino.

May be, it sends also some garbage with the commands and Arduino is not able to recognize it?

This is the C/C++ code:

Code: [Select]
#include <SerialStream.h>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <string>

int
main( int    argc,
      char** argv  )
{
    //
    // Open the serial port.
    //
    using namespace std;
    using namespace LibSerial ;
    SerialStream serial_port ;
    char c;
    serial_port.Open( "/dev/ttyACM0" ) ;
    if ( ! serial_port.good() )
    {
        std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] "
                  << "Error: Could not open serial port."
                  << std::endl ;
        exit(1) ;
    }
    //
    // Set the baud rate of the serial port.
    //
    serial_port.SetBaudRate( SerialStreamBuf::BAUD_9600 ) ;
    if ( ! serial_port.good() )
    {
        std::cerr << "Error: Could not set the baud rate." <<  
std::endl ;
        exit(1) ;
    }
    //
    // Set the number of data bits.
    //
    serial_port.SetCharSize( SerialStreamBuf::CHAR_SIZE_8 ) ;
    if ( ! serial_port.good() )
    {
        std::cerr << "Error: Could not set the character size." <<  
std::endl ;
        exit(1) ;
    }
    //
    // Disable parity.
    //
    serial_port.SetParity( SerialStreamBuf::PARITY_NONE ) ;
    if ( ! serial_port.good() )
    {
        std::cerr << "Error: Could not disable the parity." <<  
std::endl ;
        exit(1) ;
    }
    //
    // Set the number of stop bits.
    //
    serial_port.SetNumOfStopBits( 1 ) ;
    if ( ! serial_port.good() )
    {
        std::cerr << "Error: Could not set the number of stop bits."
                  << std::endl ;
        exit(1) ;
    }
    //
    // Turn off hardware flow control.
    //
    serial_port.SetFlowControl( SerialStreamBuf::FLOW_CONTROL_NONE ) ;
    if ( ! serial_port.good() )
    {
        std::cerr << "Error: Could not use hardware flow control."
                  << std::endl ;
        exit(1) ;
    }
    //
    // Do not skip whitespace characters while reading from the
    // serial port.
    //
    // serial_port.unsetf( std::ios_base::skipws ) ;
    //
    // Wait for some data to be available at the serial port.
    //
    //
    // Keep reading data from serial port and print it to the screen.
    //
 // Wait for some data to be available at the serial port.
    //
    while( serial_port.rdbuf()->in_avail() == 0 )
    {
        usleep(100) ;
    }

    usleep(10000);
   
    char out_buf[] = "check";
    serial_port.write(out_buf, 1);
    while( 1  )
    {
        char next_byte;
        serial_port.get(next_byte);
        std::cerr << next_byte;
       
    }
    std::cerr << std::endl ;
    return EXIT_SUCCESS ;
}


and this is the code on Arduino side:

Code: [Select]

void setup()
{
Serial.begin(9600);
}
void loop(){
inputSize = 0;

if (Serial.available() > 0) {
  delay(300);
  inputSize = Serial.available();
  for (int i = 0; i < inputSize; i++){
    myCmd[i] = Serial.read();
  }

if (strcmp(myCmd, "check") == 0){
String start = sonar + token + check_sonar() + end_char; // this string is: Sonar@1\n
Serial.print(start);
start = gyroscope + token + check_gyroscope() + end_char; // this string is: Gyroscope@1\n
Serial.print(start);
start = encoders + token + check_encoders() + end_char; // this string is Encoders@1\n
Serial.print(start);
}
if (strcmp(myCmd, "start") == 0){
START = true;
}
if (strcmp(myCmd, "stop") == 0){
START = false;
}
else if ( !(strcmp(myCmd, "check") == 0) && !(strcmp(myCmd, "start") == 0) && !(strcmp(myCmd, "stop") == 0) ) {
Serial.print("Error\n");
}

 
// END FIRST CHECK
}
}


PaulS

Code: [Select]
if (Serial.available() > 0) {
   delay(300);
   inputSize = Serial.available();
   for (int i = 0; i < inputSize; i++){
     myCmd[i] = Serial.read();
   }

if (strcmp(myCmd, "check") == 0){

If the data does not all arrive in 300 seconds, it's OK to just ignore the rest?

The strcmp() function expects two strings as arguments. myCmd is NOT a string.

A string is a NULL terminated array of chars. myCmd is an array of chars. It is not NULL terminated, therefore it is not a string, and should not be passed to strcmp() with any reasonable expectation that it will be properly recognized/dealt with.

marcus barnet

If I use Serial Monitor to test the Arduino sketch, it works very well because it receive and recognize the strings very well.
For this reason, i was supposing that the sketch was good.

What i should do in order to fix the problem?
What's the best way to read from serial and compare two strings in Arduino?

I hope you can help me.

marcus barnet

Since a string is an array of characters with the null termination, can i add '\n' to myCmd to obtein a string in order to succefully use strcmp()?

PaulS

Quote
Since a string is an array of characters with the null termination, can i add '\n' to myCmd to obtein a string in order to succefully use strcmp()?

\n is a carriage return, Adding it will not NULL terminate the string.

The NULL terminator is \0. Adding that WILL help.

marcus barnet

#9
Jan 27, 2012, 05:31 pm Last Edit: Jan 27, 2012, 05:36 pm by marcus barnet Reason: 1
I tryed to add the NULL termination character, but now it does not recognize any input when i try to send commands from Serial Monitor.
It writes "Error" all the time.

Code: [Select]
if (Serial.available() > 0) {
 
  inputSize = Serial.available();
  for (int i = 0; i < inputSize; i++){
    myCmd[i] = Serial.read();
  }
  myCmd[i] = '\0';  <-- Added here

// FIRST CHECK

if (strcmp(myCmd, "check") == 0){


EDIT: Weird error! i is equal to ZERO outer the for loop.

marcus barnet

Ok, now i think i did the right thing!

Code: [Select]
if (Serial.available() > 0) {
 
   inputSize = Serial.available();
   for (int i = 0; i < inputSize; i++){
     myCmd[i] = Serial.read();
    if (i == inputSize){
     myCmd[i] = '\0';
     }
   }


In this way, I obtein a string with a NULL character at the end.

Paul, do you think it's correct?

PaulS

The string should ALWAYS be NULL terminated, not just once.
Code: [Select]
   for (int i = 0; i < inputSize; i++)
   {
     myCmd[i] = Serial.read();
     myCmd[i+1] = '\0';
   }

marcus barnet

You have reason, in this way it adds a NULL character after the last character read.
It is correct :)

Sorry, i didn't get it immediately.

marcus barnet

Now the problem is that Arduino is not able to recognize the commands sent by the C program: it always returns Error.

I do not know the reason because i simply open the connection and try to send "check".
May be is there an error with the connection time scheduling between Arduino and the C program and Arduino read just a part of the full string command?

This is the C code (I use LibSerial):

Code: [Select]
#include <SerialStream.h>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <string>

int
main( int    argc,
       char** argv  )
{
     //
     // Open the serial port.
     //
     using namespace std;
     using namespace LibSerial ;
     SerialStream serial_port ;
     char c;
     serial_port.Open( "/dev/ttyACM0" ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] "
                   << "Error: Could not open serial port."
                   << std::endl ;
         exit(1) ;
     }
     //
     // Set the baud rate of the serial port.
     //
     serial_port.SetBaudRate( SerialStreamBuf::BAUD_9600 ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not set the baud rate." << 
std::endl ;
         exit(1) ;
     }
     //
     // Set the number of data bits.
     //
     serial_port.SetCharSize( SerialStreamBuf::CHAR_SIZE_8 ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not set the character size." << 
std::endl ;
         exit(1) ;
     }
     //
     // Disable parity.
     //
     serial_port.SetParity( SerialStreamBuf::PARITY_NONE ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not disable the parity." << 
std::endl ;
         exit(1) ;
     }
     //
     // Set the number of stop bits.
     //
     serial_port.SetNumOfStopBits( 1 ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not set the number of stop bits."
                   << std::endl ;
         exit(1) ;
     }
     //
     // Turn off hardware flow control.
     //
     serial_port.SetFlowControl( SerialStreamBuf::FLOW_CONTROL_NONE ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not use hardware flow control."
                   << std::endl ;
         exit(1) ;
     }
     //
     // Do not skip whitespace characters while reading from the
     // serial port.
     //
     // serial_port.unsetf( std::ios_base::skipws ) ;
     //
     // Wait for some data to be available at the serial port.
     //
     //
     // Keep reading data from serial port and print it to the screen.
     //
  // Wait for some data to be available at the serial port.
     //
     while( serial_port.rdbuf()->in_avail() == 0 )
     {
         usleep(100) ;
     }

     usleep(10000);
     
     char out_buf[] = "check";
     serial_port.write(out_buf, 1);  <-- HERE I SEND CHECK AND I RECEIVE ERROR
     while( 1  )
     {
         char next_byte;
         serial_port.get(next_byte);
         std::cerr << next_byte;
         
     }
     std::cerr << std::endl ;
     return EXIT_SUCCESS ;
}

PaulS

Quote
Now the problem is that Arduino is not able to recognize the commands sent by the C program: it always returns Error.

So you post the PC code. Why?

Go Up