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:
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?
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++.
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:
#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:
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
}
}
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.
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 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.
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.
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.
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):
#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 ;
}
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?
Because I thought the sketch is correct now since it manages the string correctly, so i posted the C code in order to receive some help on it.
May be, i'm not sending the commands in the correct way with my C code and someone can give me some suggestions.
In fact, to test it I added a println(myCmd) after the for loop in order to get back the string received and i noticed that Arduino receives just the "c" character of the whole string "check" sent my the C program.
C program sends "check"
Arduino receive "c" and then sends "Error".