Cannot send integer to the arduino (serial communication)

Hello everyone:

I am doing a project with an arduino mega. I am using the arduino mega to control two stepper motors. If I upload the arduino code on the arduino, I can control it with the serial monitor. Now, I have eclipse installed on Ubuntu on my machine, and I am using the code bellow to send integers to the arduino via cmd. It works, the problem is that if I try to send the command from the code itself, it does not do anything. I am not sure what is happening. The code does not give me any error, it just doesn’t do anything. I am changing the code to send the integer this way:

input[0]='1';
write(fd, &input[0], sizeof(&input[0]);

C++ code:

#include <stdio.h> // standard input / output functions
#include <string.h> // string function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitionss
#include <time.h>   // time calls
#include <sys/signal.h>
#include <sys/types.h>
#include <sstream>
#include <iostream>
#include <string>
#include <cstdlib>

//Global variables
char buf[255]={};
int res;
char input[10]={};


// Functions Headers
int open_port(void);
int configure_port(int fd);
int read_write_arduino(int fd);

int main(void)
{
int n=30;

    while(n){
        int fd = open_port();
                    if (fd==-1) return(-1);
        read_write_arduino(fd);

                    n--;
        close(fd); //close serial stream

    }
    return(0);
}



int open_port(void)
{
    int fd; // file description for the serial port

    fd = open("/dev/ttyACM1", O_RDWR | O_NOCTTY | O_NDELAY);

    if(fd == -1) // if open is unsucessful
    {
                perror("open_port: Unable to open /dev/ttyACM0 - ");
                return(-1);
  }

    if (configure_port(fd)==-1)
   {
                close(fd);
                perror("configure_port(): Unable initialize serial port - ");
                return(-1);
}
    return(fd);
}


int configure_port(int fd)      // configure the port
{
    struct termios port_settings;      // structure to store the port settings in
    int ret=-1;
    ret = fcntl(fd, F_SETFL, 0);

    // Read current settings for the serial port (fd) into variable "port_settings"
    ret = tcgetattr(fd, &port_settings);
    // Set baud rates for serial input to 9600
    ret= cfsetispeed(&port_settings, B9600);
// Set baud rates for serial output to 9600
 ret= cfsetospeed(&port_settings, B9600);


    port_settings.c_cflag |= (CLOCAL | CREAD); // ignore status lines (such as carrier detect)
    port_settings.c_cflag &= ~PARENB;    // set no parity, stop bits, data bits
    port_settings.c_cflag &= ~CSTOPB; // 1 stop bit (complement of CSTOP, otherwise 2 stop bits)
    port_settings.c_cflag &= ~CSIZE;
    port_settings.c_cflag |= CS8;           // 8 data bits
    port_settings.c_lflag |= ICANON;
    port_settings.c_lflag &= ~( ISIG | ECHO | ECHOE); // don't: enable signals, echo input

    ret= tcsetattr(fd, TCSANOW, &port_settings);    // apply the settings to the port
    return(ret);

}

int read_write_arduino(int fd)   // query modem with an AT command
{
    int pid;
    int e;

    pid = fork(); //splits process for recieving and sending

          if(pid != 0)
          {

                                scanf("%s", input);
                                write(fd, input, strlen(input));
                                //fprintf(stdout, "%s\n", input);


                           for(e=0; e< strlen(input) ; e++ ){
                           input[e]=0;

          }
          }

          else
          { //should continually receive

                    if (read(fd, &buf, 255)>0)
                          { //if there's something to be read from the serial port
                        //buf[read(fd, &buf, 255)]=0;
                        fprintf(stdout, "%s", buf);
                          }
                    for(e=0; e< strlen(buf) ; e++ ){
                                	  	  buf[e]=0;
                                    	}



        }

          return(0);

}

Arduino Code:

#include <Servo.h> 

int MstepR=9;
int MstepL=8;
int DirR=34;
int DirL=32;
int i;
int vl;
int indix;

Servo rservo;  // create servo object to control a servo 
Servo lservo;                // a maximum of eight servo objects can be created 
int rpos = 180;    // variable to store the servo position 
int lpos = 0;
int disk = 1;
int hold = 2;



void setup()
{
  //Create Serial Object
  Serial.begin(9600);
  
  pinMode(MstepR, OUTPUT); // set pin to output
  pinMode(MstepL, OUTPUT); //set pin to output
  
  pinMode(DirR, OUTPUT);  
  pinMode(DirL, OUTPUT);
  
  pinMode(hold, OUTPUT);
  rservo.attach(13);  // attaches the servo on pin 9 to the servo object 
  lservo.attach(12);
  
  vl=600;
}

void loop()
{
  int cons=74;
  int cons2=74;
  int val=0;
  int inp=0;
  int fixl=0;
  int lonbac=0;
  int lonfor=0;
  int lonrig=0;
  int lonlef=0;
  int numcal=0;
  int cal=1;  
  int v2=1100;
  int vb=1400;
  int vba=800;
  int vbf=800;
  int valle=2;
  int valle2=4;
  
  if (Serial.available() == 0){
 
  delay(10);
  while (Serial.available()>0){
  inp*= 10;
  inp += Serial.read() - '0';
  }

  }
  else {
   while(Serial.available()>0) Serial.read();
  }

val=inp;

  switch (val){
    
    case 0:{break;}
  
    case 1:
    {
      
        Serial.println("Backward"); 
        Serial.println("Get Distance");
        
        while(Serial.available() == 0);
 
        delay(10);
        while (Serial.available()>0){
        lonbac*= 10;
        lonbac += Serial.read() - '0';
        }
          
        while(Serial.available()>0) Serial.read();
        
        Serial.println(lonbac);
        
        for (int i=0; i<=lonbac; i++)
        {
          digitalWrite(DirR,LOW);
          digitalWrite(DirL,HIGH);
          digitalWrite(MstepL, HIGH);
          digitalWrite(MstepR, HIGH);
          delayMicroseconds(vba);
          digitalWrite(MstepL,LOW);
          digitalWrite(MstepR, LOW);
          delayMicroseconds(vba);   
          
                    if(cons2==78){
      for (int i=0; i<=valle2; i++)
        {
           
          digitalWrite(DirR,LOW);
          digitalWrite(DirL,LOW);
          
          digitalWrite(MstepL, HIGH);
          digitalWrite(MstepR, HIGH);
          delayMicroseconds(vl);
          digitalWrite(MstepL,LOW);
          digitalWrite(MstepR, LOW);
          delayMicroseconds(vl);   
          
        }
        cons=0;
      }
          cons++;
          
          
          if (i==lonbac-1) Serial.println("Done!")  ;
        }// end for case 0
      val=0;
      break;  
    }// end case 0
 } //end switch
}

Opening an closing a port will reset the arduino. It looks like you are not waiting long enough after opening the port for the boot loader to finish befor you shoot off a command to the arduino. Then you are closing the port and again reaseting the arduino before it can do anything. That arduino code, do you need to initialise all those values each time round the loop? Should they not be static variables or global ones?

I changed it to the code below, but it still doesn't work.

        int fd = open_port();
                    if (fd==-1) return(-1);
    while(true){
        read_write_arduino(fd);
    }

        close(fd); //close serial stream

    return(0);

Some of them are statics, and some of them need to be initialize. That is an extract of all the arduino code, I have like seven cases.

You're really slaughtering your process table there for no apparent reason.

You should really be working with FDs (open/read/write/close), not STDIO (fopen/fclose etc), then you can use non-blocking IO and the select() function to handle the IO from one single process. As it is, every single pass through your main while() is forking a new process just to read one string.

I changed it to the code below, but it still doesn't work.

Why should it. You haven't addressed what I said.

Just bear a little more, please. I am really new in this. I am just trying to figure things out. I thought that you said that I didn't need to initialize the port each time I want to write on it. That is why the "while" only includes the function that reads and writes to the arduino. Moreover, I add a usleep(1000) before the line "write", but it doesn't work either. Can you be more explicit with what you mean, please? Sorry, for the silly questions, I just do not know much about any of this.

You should open the port, then wait a period of time before doing anything else to allow the Arduino to reboot. usleep(1000) will wait for about 1ms - I would have thought that would be a bit short, try waiting for quite a bit longer. Personally in this situation I have the Arduino output a “ready” message that the PC waits for so it knows the Arduino has rebooted and is ready to accept commands. This could be as simple as one single character.

You should open the serial port in non-blocking mode

#include <fcntl.h>
//...
int fd;
fd = open("/dev/ttyACM0", O_RDWR | O_NONBLOCK);

Then you can use select to see if there is any data to receive, and wait with a timeout until data does arrive. Or, just try and read, and if there is nothing to read, then it just skips on - you could cause quite high CPU usage doing this though, it’s best to use select with a very short timeout really.

See “man select” on Linux for how to use select.

hey mayenko, I tried to do what you suggested. I have this, but still don't know what is wrong.

{
    int n;
    fd_set rdfs;
    struct timeval timeout;

    timeout.tv_sec = 5;
    timeout.tv_usec = 0;

    write(fd, "1", 3);  // send an AT command followed by a CR

    res = read(fd,buf,255);
if (res>0){
    buf[res]=0;
    printf("%s", buf, res);
}
   n = select(fd + 1, &rdfs, NULL, NULL, &timeout);

}

robotarduino: hey mayenko, I tried to do what you suggested. I have this, but still don't know what is wrong.

I think it would be worth reposting the whole of your C++ code, not just snippets. There were some quite nasty problems with the original (not allowing time for the Arduino to reset, resetting after every command, forking processes left right and center) and I don't want to have to guess how many of these you have fixed so far.

Hey Peter this is the c++ code:

#include <stdio.h>
#include <string.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <termios.h> 
#include <time.h>   
#include <sys/signal.h>
#include <sys/types.h>
#include <sstream>
#include <iostream>
#include <string>
#include <cstdlib>

//Global variables
char buf[255]={};
int res;
char input[10]={};


// Functions Headers
int open_port(void);
int configure_port(int fd);
int read_write_arduino(int fd);

int main(void)
{
int n=30;

        int fd = open_port();
                    if (fd==-1) return(-1);

    while(n>0){
          buf[255]={};
         input[10]={};
        read_write_arduino(fd);
}
        close(fd); //close serial stream

    
    return(0);
}



int open_port(void)
{
    int fd; // file description for the serial port

    fd = open("/dev/ttyACM1", O_RDWR | O_NONBLOCK);

    if(fd == -1) // if open is unsucessful
    {
                perror("open_port: Unable to open /dev/ttyACM0 - ");
                return(-1);
  }

    if (configure_port(fd)==-1)
   {
                close(fd);
                perror("configure_port(): Unable initialize serial port - ");
                return(-1);
}
    return(fd);
}


int configure_port(int fd)      // configure the port
{
    struct termios port_settings;      // structure to store the port settings in
    int ret=-1;
    ret = fcntl(fd, F_SETFL, 0);

    // Read current settings for the serial port (fd) into variable "port_settings"
    ret = tcgetattr(fd, &port_settings);
    // Set baud rates for serial input to 9600
    ret= cfsetispeed(&port_settings, B9600);
// Set baud rates for serial output to 9600
 ret= cfsetospeed(&port_settings, B9600);


    port_settings.c_cflag |= (CLOCAL | CREAD); // ignore status lines (such as carrier detect)
    port_settings.c_cflag &= ~PARENB;    // set no parity, stop bits, data bits
    port_settings.c_cflag &= ~CSTOPB; // 1 stop bit (complement of CSTOP, otherwise 2 stop bits)
    port_settings.c_cflag &= ~CSIZE;
    port_settings.c_cflag |= CS8;           // 8 data bits
    port_settings.c_lflag |= ICANON;
    port_settings.c_lflag &= ~( ISIG | ECHO | ECHOE); // don't: enable signals, echo input

    ret= tcsetattr(fd, TCSANOW, &port_settings);    // apply the settings to the port
    return(ret);

}

int read_write_arduino(int fd)   // query modem with an AT command
{
    int pid,k;
    int e;

    usleep(100000);

    pid = fork(); //splits process for recieving and sending

          if(pid != 0)
          {
               write(fd, "1",3);
          }

          else
          {
                     k=read(fd, &buf, 255);
                    if (k>0)
                          { 
                        buf[k]=0;
                        fprintf(stdout, "%s", buf);
                          }
        }

          return(0);

}
usleep(100000);

It takes the arduino about 2 seconds to be in a state to accept or send commands. That delay is far too short.