Go Down

Topic: Serial commands to Arduino 328 (Read 2869 times) previous topic - next topic

XeonCY

Hello there,
This is my first post here so here it goes!  :) I am trying to make an Arduino to start a motor when it receives 1 clockwise,2 counterclockwise and 0 to stop. The speed is increasing in time but this is not the problem. Well i have created a sketch which receives data at 9600 from the serial interface. I have also created a program in VB 2008 where i sent 1,2 and 0 through the serial port (FTDI) and it works. The problem arises when i try to write a program in C in Linux (LXDE over Ubuntu). The rx led on the Arduino board blink when the message is sent but the motor is not starting whatever i do. I even tried to change the receive buffer to be above or equal 0 but still nothing. :( This is very confusing since i have configured my program to sent CS8( 8 bits per byte), B9600 (9600), No parity bit and one stop bit (same as the VB program). I use /dev/ttyUSB0 as the serial port file in C program. Does  any one have a clue what is going on? I am really desperate since this is part of a University Project in robotics. Thanks a lot! (forgive my English if they are not OK i am a foreign)

PaulS

Please post your C code. It is probably some simple like writing numbers to the serial port, instead of characters. Without the code, though, we can't tell.

By the way, you were doing great until that last sentence where you said that English is not your native language.

Post the Arduino code, too.

XeonCY

Thanks for the reply!
The arduino code is:

// motor A
int dir1PinA = 13;
int dir2PinA = 12;
int speedPinA = 10;

unsigned long time;
int speed; //This is the speed variable  for the motors
int inbyte=-1; //This is the received command



void setup()
{
 Serial.begin(9600); //setup the serial port to 9600bps
 
 //seting the pins options
 pinMode(dir1PinA, OUTPUT);
 pinMode(dir2PinA, OUTPUT);
 pinMode(speedPinA, OUTPUT);
 
 //initializing the time and the speed
 time = millis();
 speed = 0;
 
}
void loop()
{
 
 if (Serial.available()>0){ //check if something was received
 
         inbyte==Serial.read(); //store it to inbyte
          if (inbyte>-1){  //this is acknowledgment
      Serial.print("Received1");
    Serial.print( inbyte);}}
   
  else{ //if the serial is not available
   
    delay(10); //wait for 10ms and try again
     inbyte=Serial.read();
     
     if (inbyte>-1){ //acknowledgment
     
     Serial.print("Received2");
   Serial.print( inbyte);}
   }
     
     
 analogWrite(speedPinA, speed);

 // set direction
if (inbyte==49) { //if the received command is 1 in ASCII code start spinning
 Serial.print("Starting...");
   digitalWrite(dir1PinA, LOW);
   digitalWrite(dir2PinA, HIGH);
 
 } else{
    if(inbyte==50) {//if the received command is 2 in ASCII code start spinning
       digitalWrite(dir1PinA, HIGH);
       digitalWrite(dir2PinA, LOW);
       }
 
     else {
         if (inbyte==48){ //if the received command is 0 in ASCII code stop
           digitalWrite(dir1PinA,LOW);
           digitalWrite(dir2PinA, LOW);
          }
     }
 }
 
 if (millis() - time > 5000)  { //increment speed until it reaches 255 (this will be changed in the future)
   time = millis();
   speed += 20;
   if (speed > 255) {
     speed = 0;
   }
 
 }
}

-----------------------------------------------------------------------------------------
The C code is:
-----------------------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>


//PROTOTYPE DECLARATION POINT


char menu();

int open_port();


// MAIN FUNCTION
int main(){
     char msg; //the message
     int fd; //file descriptor
     int n;
     
     fd=open_port(); //this will get the file descriptor
     
     msg=menu(); //this will get the command from the user
     
     struct termios options; //setting the options termios

     tcgetattr(fd,&options); //getting the current attributes of the fd
     
     cfsetispeed(&options,B9600); //setting the speed to 9600
     cfsetospeed(&options,B9600);
     options.c_cflag &=~CSIZE; //setting the size of bits per byte
     options.c_cflag |=CS8; //setting 8bits per byte
     options.c_cflag &=~PARENB; //dissabling parity bit
     options.c_cflag &=~CSTOPB; //one stop bit


     n=write(fd,&msg,1); // sent the command
     
     close(fd); //close port


return 0;
}



//FUNCTION DECLARATION POINT


char menu(){ //this is a menu for the user to enter a value
     char val;
     
           printf("Please enter a value:\n");
           printf("0:Stop\n");
           printf("1:Counterclockwise\n");
           printf("2:Clockwise\n");
           val=getchar();
     

     return val;
}


int open_port(){ //this will open the port
     int fd;

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

     if (fd==-1)
     {printf("error on opening");
     return fd;}

     else{
           fcntl(fd, F_SETFL,0);

     printf("%d",fd);
     return fd;
     }
return fd;      
}


PaulS

In the sketch, you have this:
Code: [Select]
inbyte==Serial.read(); //store it to inbyte

This will compare the value returned by the Serial.read function to the value currently in inbyte. No action is taken if the values are equal, or not. inbyte is NOT modified.

Code: [Select]
delay(10); //wait for 10ms and try again
    inbyte=Serial.read();


If Serial.available said there was no data available, waiting 10 milliseconds will not make some appear.

Code: [Select]
if (inbyte==49) { //if the received command is 1 in ASCII code start spinning

A month from now when you look at this, you'll be scratching your head, wondering what that was all about. It's better to do this:

Code: [Select]
if(inbyte == '1') {

You could change the characters from 1, 2, and 0 sometime, to F, B, and S (for foreward, backward, and stop). It would be easy to change '1', '2', and '0' to 'F', 'B', and 'S'. It's more difficult to change 49, 50, and 48. You'd have to go look up what the ASCII equivalents are. Why not just let the compiler to that for you?

I don't see anything obviously wrong with the C code. I wonder if /dev/ttyUSB0 is the correct port to be using. Is ttyUSB0 the port that the Arduino is on? Do you have permission to write to that device?

Maybe one of the linux users could help you determine if ttyUSB0 is correct and whether you are (or can) use it (right).

XeonCY

Thanks for the recommendations! :) I have changed the code as recommended. For the C program i have searched a lot to finally discover that ttyUSB0 is the file that i am needing. I also made some tests myself by unplugging arduino and replugging it. The file disappeared and reappeared at each time. The thing with this program is that RX led on the arduino board is blinking each time it receives from the program but the motor is not spinning. I believe there is something to do with the file not setting right or at all. I even tried from the root terminal executing the program and even changing the file permissions by chmod -a+rw command. Its still very puzzling what is going on.... :-/ Any ideas?

PaulS

If the RX light flashes when the program is trying to send data to the Arduino, and only then, then, clearly, the Arduino IS receiving the data.

It would suggest that it is the Arduino that is not interpreting the data correctly. I would add some statements to echo the input. The C program would then need to be modified to read what was written back, and display it.

I'd also add some printf statements in the C program to verify that a valid character was received in menu (by the getchar function).

XeonCY

Thanks a lot for the help! I have finally made it! The motor started spinning as requested! There are some changes in the C code but i believe that the actual thing that made this work is the chmod 0666 /dev/ttyUSB0

This is the C code with some minor changes:
Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termio.h>


//PROTOTYPE DECLARATION POINT


char menu();

int open_port();

// MAIN FUNCTION
int main(){
     char msg; //the message
     int fd; //file descriptor
     int n;
     char buffer[12];

     fd=open_port(); //this will get the file descriptor
     
     msg=menu(); //this will get the command from the user
     
     struct termios options; //setting the options termios

     tcgetattr(fd,&options); //getting the current attributes of the fd
     

     options.c_iflag=IGNPAR;
     options.c_oflag=0;
     options.c_cflag= CS8 | CREAD | CLOCAL;
     options.c_lflag=0;
     cfsetispeed(&options,B9600); //setting the speed to 9600
     cfsetospeed(&options,B9600);
     tcsetattr(fd,TCSANOW,&options);

     

     
     write(fd,&msg,1); // sent the command
     int i;
     for ( i=0; i<11; i++){
           read(fd,&buffer[i],1);
     }      
     
     close(fd); //close port

     printf("%s",buffer);
return 0;
}




//FUNCTION DECLARATION POINT





char menu(){ //this is a menu for the user to enter a value
     char val;
     
           printf("Please enter a value:\n");
           printf("0:Stop\n");
           printf("1:Counterclockwise\n");
           printf("2:Clockwise\n");
           val=getchar();
           //printf("%s",val);

     return val;
}


int open_port(){ //this will open the port
     int fd;

     fd=open("/dev/ttyUSB0",O_RDWR);

     if (fd==-1)
     {printf("error on opening");
     return fd;}

     else{
           fcntl(fd, F_SETFL,0);
     printf("%d",fd);
     return fd;
     }
return fd;      
}


Thanks a lot for the help! :D
PS: I found how to correctly add the code in the forum

Go Up