Rosanswers logo

I wanted the ROS pc to communicate over the UART with a microcontroller on mobile robot, I canot use ros serial as on the controller I canot use C++ code, so I have used a wrapper code for serial port in linux following the example code from this link: https://code.google.com/p/team-diana/source/browse/ros_workspace/fuerte/Serial/src/r2Serial.cpp?r=b3ad5adc6b1e885620b615c5f56ccf929cfbcdc2

My code is as follows:

#define DEFAULT_BAUDRATE 115200
#define DEFAULT_SERIALPORT "/dev/ttyUSB0"

//Global data
FILE *fpSerial = NULL;   //serial port file pointer
ros::Publisher ucResponseMsg;
ros::Subscriber ucCommandMsg;
int ucIndex;          //ucontroller index number

int FileDesc;

unsigned char crc_sum=0;

//Initialize serial port, return file descriptor
FILE *serialInit(char * port, int baud)
  int BAUD = 0;
  int fd = -1;
  struct termios newtio, oldtio;
  FILE *fp = NULL;

 //Open the serial port as a file descriptor for low level configuration
 // read/write, not controlling terminal for process,
  fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);

  ROS_INFO("FileDesc : %d",fd);

 if ( fd<0 )
    ROS_ERROR("serialInit: Could not open serial device %s",port);
   return fp;

  // save current serial port settings

  // clear the struct for new port settings
  bzero(&newtio, sizeof(newtio));

  //Look up appropriate baud rate constant
  switch (baud)
     case 38400:
        BAUD = B38400;
     case 19200:
        BAUD  = B19200;
    case 115200:
        BAUD  = B115200;
     case 9600:
       BAUD  = B9600;
     case 4800:
        BAUD  = B4800;
     case 2400:
        BAUD  = B2400;
     case 1800:
        BAUD  = B1800;
     case 1200:
        BAUD  = B1200;
  }  //end of switch baud_rate

  if (cfsetispeed(&newtio, BAUD) < 0 || cfsetospeed(&newtio, BAUD) < 0)
    ROS_ERROR("serialInit: Failed to set serial baud rate: %d", baud);
    return NULL;

  // set baud rate, (8bit,noparity, 1 stopbit), local control, enable receiving characters.
  newtio.c_cflag  = BAUD | CRTSCTS | CS8 | CLOCAL | CREAD;

  // ignore bytes with parity errors
  newtio.c_iflag =  IGNPAR;

  // raw output
  newtio.c_oflag = 0;

  // set input mode to non - canonical
  newtio.c_lflag = 0;

  // inter-charcter timer 
  newtio.c_cc[VTIME] = 0;

  // blocking read (blocks the read until the no.of charcters are read
  newtio.c_cc[VMIN] = 0;

  // clean the line and activate the settings for the port
  tcflush(fd, TCIFLUSH);
  tcsetattr (fd, TCSANOW,&newtio);

  //Open file as a standard I/O stream
  fp = fdopen(fd, "r+");

 if (!fp) {
    ROS_ERROR("serialInit: Failed to open serial stream %s", port);
    fp = NULL;

ROS_INFO("FileStandard I/O stream: %d",fp);

  return fp;
} //serialInit

//Process ROS command message, send to uController
void ucCommandCallback(const geometry_msgs::TwistConstPtr& cmd_vel)
  unsigned char msg[14];
  float test1,test2;
  unsigned long i;

 // build the message packet to be sent
 msg = packet to be sent;
 msg[13] = crc_sum;

   for (i=0;i<14;i++)
     fprintf(fpSerial, "%c", msg[i]);

tcflush(FileDesc, TCOFLUSH); 

} //ucCommandCallback

//Receive command responses from robot uController
//and publish as a ROS message
void *rcvThread(void *arg)
  int rcvBufSize = 200;
  char ucResponse[10];//[rcvBufSize];   //response string from uController
  char *bufPos;
  std_msgs::String msg;
  std::stringstream ss;
  int BufPos,i;
  unsigned char crc_rx_sum =0;

  while (ros::ok()) {

     BufPos = fread((void*)ucResponse,1,10,fpSerial);

for (i=0;i<10;i++)
 ROS_INFO("T: %x ",(unsigned char)ucResponse[i]);
 ROS_INFO("NT: %x ",ucResponse[i]);

          msg.data = ucResponse;

  return NULL;
} //rcvThread

int main(int argc, char **argv)
  char port[20];    //port name
  int baud;     //baud rate 

  char topicSubscribe[20];
  char topicPublish[20];

  pthread_t rcvThrID;   //receive thread ID
  int err;

  //Initialize ROS
  ros::init(argc, argv, "r2SerialDriver");
  ros::NodeHandle rosNode;
  ROS_INFO("r2Serial starting");

  //Open and initialize the serial port to the uController
  if (argc > 1) {
    if(sscanf(argv[1],"%d", &ucIndex)==1) {
      sprintf(topicSubscribe, "uc%dCommand",ucIndex);
      sprintf(topicPublish, "uc%dResponse",ucIndex);
    else {
      ROS_ERROR("ucontroller index parameter invalid");
      return 1;
  else {
    strcpy(topicSubscribe, "uc0Command");
    strcpy(topicPublish, "uc0Response");

  strcpy(port, DEFAULT_SERIALPORT);
  if (argc > 2)
     strcpy(port, argv[2]);

  if (argc > 3) {
    if(sscanf(argv[3],"%d", &baud)!=1) {
      ROS_ERROR("ucontroller baud rate parameter invalid");
      return 1;

  ROS_INFO("connection initializing (%s) at %d baud", port, baud);

   fpSerial = serialInit(port, baud);

 if (!fpSerial )
    ROS_ERROR("unable to create a new serial port");
    return 1;
  ROS_INFO("serial connection successful");

  //Subscribe to ROS messages
  ucCommandMsg = rosNode.subscribe("cmd_vel" /*topicSubscribe*/, 100, ucCommandCallback);

  //Setup to publish ROS messages
  ucResponseMsg = rosNode.advertise<std_msgs::String>(topicPublish, 100);

  //Create receive thread
  err = pthread_create(&rcvThrID, NULL, rcvThread, NULL);

  if (err != 0) {
    ROS_ERROR("unable to create receive thread");
    return 1;

  //Process ROS messages and send serial commands to uController

  ROS_INFO("r2Serial stopping");
  return 0;

The problems are:

communication is not reliable, I get many broken packets in between (the communication is asynchronous), what might be the problem..?

and while receiving the data from the micro controller, I will keep on continuously receiving the same last received data even the controller stops sending the data, what might be the problem for this behavior any internal buffer's need to be cleared..?

or Is there any serial port library I can readily use (with example)

many thanks in advance.

Originally posted by sumanth on ROS Answers with karma: 86 on 2014-08-19

Post score: 0


1 Answer 1


Rosanswers logo

Not sure that this has anything to do with the ROS component of this program. It seems like it is just an issue with your serial implementation. I don't have time to dig into your code, but my serial library is available in ROS and is known to work in many existing robots, so you might try that:


Originally posted by William with karma: 17335 on 2014-08-19

This answer was ACCEPTED on the original site

Post score: 2

Original comments

Comment by sumanth on 2014-08-20:
Oh that's great, How can I use this library in ROS. Do I need to create a package with some dependencies and copy the library into that or how is it done exactly.?

Comment by sumanth on 2014-08-20:
I have used the library as it is with out changing anything, then I tried to run the serial_example.cc it is running fine. I have modified the code of the example (added some ROS publisher's subscribers), but it gives "Invoking "make failed". Do I need to change CMakeLists.txt

Comment by William on 2014-08-20:
It is a ROS package itself, you can just install it with sudo apt-get install ros-indigo-serial. Then you can write a new ROS package with a new ROS node which uses it (see the example for how to use it).

Comment by sumanth on 2014-08-20:
Thanks a lot william . I have tried to use the library and the communication is working fine, there is some problem in transmitting the data from ROS to micro controller (The data gets drifted), this I guess is a problem on uC side. I will check this part.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.