sf30_node.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2016 Carnegie Mellon University, Guilherme Pereira
00003  * <gpereira@ufmg.br>
00004  *
00005  * For License information please see the LICENSE file in the root directory.
00006  *
00007  */
00008 
00009 // S30 Laser rangefinder node- Guilherme Pereira, May, 2016
00010 // You must set the sensor using the windows program first. The bound rate must
00011 // be 115200 and the frequency larger than 50Hz
00012 
00013 #include <errno.h>
00014 #include <fcntl.h>
00015 #include <geometry_msgs/PoseWithCovarianceStamped.h>
00016 #include <ros/ros.h>
00017 #include <sensor_msgs/LaserScan.h>
00018 #include <signal.h>
00019 #include <termios.h>
00020 #include <unistd.h>
00021 
00022 int fdes;
00023 bool exit_;
00024 
00025 void SigintHandler(int sig) {
00026   exit_ = true;
00027   close(fdes);
00028   ros::Duration(0.5).sleep();
00029   ros::shutdown();
00030 }
00031 
00032 int set_interface_attribs(int fd, int speed, int parity) {
00033   struct termios tty;
00034   memset(&tty, 0, sizeof tty);
00035   if (tcgetattr(fd, &tty) != 0) {
00036     ROS_ERROR("error %d from tcgetattr", errno);
00037     return -1;
00038   }
00039 
00040   cfsetospeed(&tty, speed);
00041   cfsetispeed(&tty, speed);
00042 
00043   tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;  // 8-bit chars
00044   // disable IGNBRK for mismatched speed tests; otherwise receive break
00045   // as \000 chars
00046   tty.c_iflag &= ~IGNBRK;  // disable break processing
00047   tty.c_lflag = 0;         // no signaling chars, no echo,
00048                            // no canonical processing
00049   tty.c_oflag = 0;         // no remapping, no delays
00050   tty.c_cc[VMIN] = 0;      // read doesn't block
00051   tty.c_cc[VTIME] = 5;     // 0.5 seconds read timeout
00052 
00053   tty.c_iflag &= ~(IXON | IXOFF | IXANY);  // shut off xon/xoff ctrl
00054 
00055   tty.c_cflag |= (CLOCAL | CREAD);    // ignore modem controls,
00056                                       // enable reading
00057   tty.c_cflag &= ~(PARENB | PARODD);  // shut off parity
00058   tty.c_cflag |= parity;
00059   tty.c_cflag &= ~CSTOPB;
00060   tty.c_cflag &= ~CRTSCTS;
00061 
00062   if (tcsetattr(fd, TCSANOW, &tty) != 0) {
00063     ROS_ERROR("error %d from tcsetattr", errno);
00064     return -1;
00065   }
00066   return 0;
00067 }
00068 
00069 void set_blocking(int fd, int should_block) {
00070   struct termios tty;
00071   memset(&tty, 0, sizeof tty);
00072   if (tcgetattr(fd, &tty) != 0) {
00073     ROS_ERROR("error %d from tggetattr", errno);
00074     return;
00075   }
00076 
00077   tty.c_cc[VMIN] = should_block ? 1 : 0;
00078   tty.c_cc[VTIME] = 5;  // 0.5 seconds read timeout
00079 
00080   if (tcsetattr(fd, TCSANOW, &tty) != 0)
00081     ROS_ERROR("error %d setting term attributes", errno);
00082 }
00083 
00084 bool isValidNumber(char a) {
00085   return ((a >= 48) && (a <= 57));
00086 }
00087 
00088 int main(int argc, char **argv) {
00089   ros::init(argc, argv, "sf30_node");
00090   ros::NodeHandle n;
00091 
00092   signal(SIGINT, SigintHandler);
00093 
00094   // load params
00095   std::string s;
00096   std::string topic_name;
00097   std::string frame_id = "sf30";
00098   bool debug_;
00099   bool publish_as_pose;
00100   int update_rate;
00101   double variance_;
00102 
00103   n.getParam("sf30_node/portname", s);
00104   n.getParam("sf30_node/debug", debug_);
00105   n.getParam("sf30_node/publish_as_pose", publish_as_pose);
00106   n.getParam("sf30_node/update_rate", update_rate);
00107   n.getParam("sf30_node/topic_name", topic_name);
00108   n.getParam("sf30_node/frame_id", frame_id);
00109   n.getParam("sf30_node/altitude_variance", variance_);
00110 
00111   ros::Rate loop_rate(update_rate);
00112   ros::Publisher pub_;
00113 
00114   if (publish_as_pose) {
00115     pub_ =
00116         n.advertise<geometry_msgs::PoseWithCovarianceStamped>(topic_name, 10);
00117   } else {
00118     pub_ = n.advertise<sensor_msgs::LaserScan>(topic_name, 10);
00119   }
00120 
00121   const char *portname = s.c_str();
00122 
00123   fdes = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
00124   if (fdes < 0) {
00125     ROS_ERROR("Error %d opening %s: %s", errno, portname, strerror(errno));
00126     return 1;
00127   }
00128 
00129   // set speed to 115200 bps, 8n1 (no parity)
00130   set_interface_attribs(fdes, B115200, 0);
00131   // set blocking
00132   set_blocking(fdes, 1);
00133 
00134   char buf[1];
00135   int nc, i;
00136   float num = 0.0;
00137   int confidence = 0;
00138   tcflush(fdes, TCIFLUSH);
00139   ros::Time last_time = ros::Time::now();
00140   exit_ = false;
00141 
00142   // Main loop
00143   while (ros::ok() && !exit_) {
00144     tcflush(fdes, TCIFLUSH);  // to get the most recent data, flush the buffer
00145 
00146     while (ros::ok() && !exit_) {  // format of the data 00.00 m\n\n
00147 
00148       nc = read(fdes, buf, 1);
00149       ROS_INFO_COND(debug_, " char: %d ", (int)buf[0]);
00150 
00151       if ((nc == 1) && (buf[0] == 'm')) {  // Look for the 'm'
00152 
00153         num = 0.0;
00154         confidence = 0;
00155 
00156         nc = read(fdes, buf, 1);  // should be a Linebreak
00157         ROS_INFO_COND(debug_, " char: %d ", (int)buf[0]);
00158         if ((nc != 1) || (buf[0] != 10 && buf[0] != 13)) {
00159           ROS_ERROR("First line break not found : %d", buf[0]);
00160           break;
00161         }
00162         nc = read(fdes, buf, 1);  // should be another Linebreak
00163         ROS_INFO_COND(debug_, " char: %d ", (int)buf[0]);
00164         if ((nc != 1) || buf[0] != 10) {
00165           ROS_ERROR("Second line break not found : %d", buf[0]);
00166           break;
00167         }
00168         i = 1;
00169         do {  // Process the number before the point.
00170           nc = read(fdes, buf, 1);
00171           ROS_INFO_COND(debug_, " char: %d ", (int)buf[0]);
00172           if ((nc == 1) && (isValidNumber(buf[0]))) {
00173             num = num * i + atof(buf);
00174             i = i * 10;
00175           } else {
00176             break;
00177           }
00178         } while (1);
00179 
00180         if ((nc != 1) || (buf[0] != '.')) {
00181           // In normal situation, only exit the loop if
00182           // find the decimal point
00183           num = 0.0;
00184           ROS_ERROR("Not decimal point: %c", buf[0]);
00185           break;
00186         }
00187 
00188         nc = read(fdes, buf, 1);  // should be the first decimal digit
00189         ROS_INFO_COND(debug_, " char: %d ", (int)buf[0]);
00190         if ((nc != 1) || (!isValidNumber(buf[0]))) {
00191           num = 0.0;
00192           ROS_ERROR("(2) Not valid number: %c", buf[0]);
00193           break;
00194         }
00195         num = num + atof(buf) / 10.0;
00196 
00197         nc = read(fdes, buf, 1);  // should be the second decimal digit
00198         ROS_INFO_COND(debug_, " char: %d ", (int)buf[0]);
00199         if ((nc != 1) || (!isValidNumber(buf[0]))) {
00200           num = 0.0;
00201           ROS_ERROR("(3) Not valid number: %c", buf[0]);
00202           break;
00203         }
00204         num = num + atof(buf) / 100.0;
00205 
00206         confidence = 1;  // If we got so far, we can thrust the number in num!
00207 
00208         break;
00209       }  // if
00210 
00211     }  // while
00212 
00213     ros::Time now = ros::Time::now();
00214     ros::Duration duration = now - last_time;
00215     last_time = now;
00216 
00217     if (publish_as_pose) {
00218       geometry_msgs::PoseWithCovarianceStamped data;
00219       data.header.frame_id = frame_id;
00220       data.header.stamp = ros::Time::now();
00221       data.pose.pose.position.z = num;
00222       data.pose.covariance[14] = variance_;
00223       pub_.publish(data);
00224     } else {
00225       sensor_msgs::LaserScan data;
00226       data.header.frame_id = "sf30";
00227       data.header.stamp = ros::Time::now();
00228       data.scan_time = duration.toSec();
00229       data.range_max = 100.0;
00230       data.ranges.push_back(num);
00231 
00232       // Confidence = 0, range = 0 cannot be thrusted
00233       data.intensities.push_back((double)confidence);
00234       pub_.publish(data);
00235     }
00236 
00237     ros::spinOnce();
00238     loop_rate.sleep();
00239   }
00240 }


sf30
Author(s): Guilherme Pereira (The AIR lab, Carnegie Mellon University)
autogenerated on Wed Jul 3 2019 19:52:42