input.cc
Go to the documentation of this file.
00001 // Copyright (C) 2007, 2009, 2010, 2015 Austin Robot Technology, Patrick Beeson, Jack O'Quin
00002 // All rights reserved.
00003 //
00004 // Software License Agreement (BSD License 2.0)
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions
00008 // are met:
00009 //
00010 //  * Redistributions of source code must retain the above copyright
00011 //    notice, this list of conditions and the following disclaimer.
00012 //  * Redistributions in binary form must reproduce the above
00013 //    copyright notice, this list of conditions and the following
00014 //    disclaimer in the documentation and/or other materials provided
00015 //    with the distribution.
00016 //  * Neither the name of {copyright_holder} nor the names of its
00017 //    contributors may be used to endorse or promote products derived
00018 //    from this software without specific prior written permission.
00019 //
00020 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 // POSSIBILITY OF SUCH DAMAGE.
00032 
00047 #include <unistd.h>
00048 #include <string>
00049 #include <sstream>
00050 #include <sys/socket.h>
00051 #include <arpa/inet.h>
00052 #include <poll.h>
00053 #include <errno.h>
00054 #include <fcntl.h>
00055 #include <sys/file.h>
00056 #include <velodyne_driver/input.h>
00057 #include <velodyne_driver/time_conversion.hpp>
00058 
00059 namespace velodyne_driver
00060 {
00061   static const size_t packet_size =
00062     sizeof(velodyne_msgs::VelodynePacket().data);
00063 
00065   // Input base class implementation
00067 
00073   Input::Input(ros::NodeHandle private_nh, uint16_t port):
00074     private_nh_(private_nh),
00075     port_(port)
00076   {
00077     private_nh.param("device_ip", devip_str_, std::string(""));
00078     private_nh.param("gps_time", gps_time_, false);
00079     if (!devip_str_.empty())
00080       ROS_INFO_STREAM("Only accepting packets from IP address: "
00081                       << devip_str_);
00082   }
00083 
00085   // InputSocket class implementation
00087 
00093   InputSocket::InputSocket(ros::NodeHandle private_nh, uint16_t port):
00094     Input(private_nh, port)
00095   {
00096     sockfd_ = -1;
00097     
00098     if (!devip_str_.empty()) {
00099       inet_aton(devip_str_.c_str(),&devip_);
00100     }    
00101 
00102     // connect to Velodyne UDP port
00103     ROS_INFO_STREAM("Opening UDP socket: port " << port);
00104     sockfd_ = socket(PF_INET, SOCK_DGRAM, 0);
00105     if (sockfd_ == -1)
00106       {
00107         perror("socket");               // TODO: ROS_ERROR errno
00108         return;
00109       }
00110   
00111     sockaddr_in my_addr;                     // my address information
00112     memset(&my_addr, 0, sizeof(my_addr));    // initialize to zeros
00113     my_addr.sin_family = AF_INET;            // host byte order
00114     my_addr.sin_port = htons(port);          // port in network byte order
00115     my_addr.sin_addr.s_addr = INADDR_ANY;    // automatically fill in my IP
00116   
00117     if (bind(sockfd_, (sockaddr *)&my_addr, sizeof(sockaddr)) == -1)
00118       {
00119         perror("bind");                 // TODO: ROS_ERROR errno
00120         return;
00121       }
00122   
00123     if (fcntl(sockfd_,F_SETFL, O_NONBLOCK|FASYNC) < 0)
00124       {
00125         perror("non-block");
00126         return;
00127       }
00128 
00129     ROS_DEBUG("Velodyne socket fd is %d\n", sockfd_);
00130   }
00131 
00133   InputSocket::~InputSocket(void)
00134   {
00135     (void) close(sockfd_);
00136   }
00137 
00139   int InputSocket::getPacket(velodyne_msgs::VelodynePacket *pkt, const double time_offset)
00140   {
00141     double time1 = ros::Time::now().toSec();
00142 
00143     struct pollfd fds[1];
00144     fds[0].fd = sockfd_;
00145     fds[0].events = POLLIN;
00146     static const int POLL_TIMEOUT = 1000; // one second (in msec)
00147 
00148     sockaddr_in sender_address;
00149     socklen_t sender_address_len = sizeof(sender_address);
00150 
00151     while (true)
00152       {
00153         // Unfortunately, the Linux kernel recvfrom() implementation
00154         // uses a non-interruptible sleep() when waiting for data,
00155         // which would cause this method to hang if the device is not
00156         // providing data.  We poll() the device first to make sure
00157         // the recvfrom() will not block.
00158         //
00159         // Note, however, that there is a known Linux kernel bug:
00160         //
00161         //   Under Linux, select() may report a socket file descriptor
00162         //   as "ready for reading", while nevertheless a subsequent
00163         //   read blocks.  This could for example happen when data has
00164         //   arrived but upon examination has wrong checksum and is
00165         //   discarded.  There may be other circumstances in which a
00166         //   file descriptor is spuriously reported as ready.  Thus it
00167         //   may be safer to use O_NONBLOCK on sockets that should not
00168         //   block.
00169 
00170         // poll() until input available
00171         do
00172           {
00173             int retval = poll(fds, 1, POLL_TIMEOUT);
00174             if (retval < 0)             // poll() error?
00175               {
00176                 if (errno != EINTR)
00177                   ROS_ERROR("poll() error: %s", strerror(errno));
00178                 return -1;
00179               }
00180             if (retval == 0)            // poll() timeout?
00181               {
00182                 ROS_WARN("Velodyne poll() timeout");
00183                 return -1;
00184               }
00185             if ((fds[0].revents & POLLERR)
00186                 || (fds[0].revents & POLLHUP)
00187                 || (fds[0].revents & POLLNVAL)) // device error?
00188               {
00189                 ROS_ERROR("poll() reports Velodyne error");
00190                 return -1;
00191               }
00192           } while ((fds[0].revents & POLLIN) == 0);
00193 
00194         // Receive packets that should now be available from the
00195         // socket using a blocking read.
00196         ssize_t nbytes = recvfrom(sockfd_, &pkt->data[0],
00197                                   packet_size,  0,
00198                                   (sockaddr*) &sender_address,
00199                                   &sender_address_len);
00200 
00201         if (nbytes < 0)
00202           {
00203             if (errno != EWOULDBLOCK)
00204               {
00205                 perror("recvfail");
00206                 ROS_INFO("recvfail");
00207                 return -1;
00208               }
00209           }
00210         else if ((size_t) nbytes == packet_size)
00211           {
00212             // read successful,
00213             // if packet is not from the lidar scanner we selected by IP,
00214             // continue otherwise we are done
00215             if(devip_str_ != ""
00216                && sender_address.sin_addr.s_addr != devip_.s_addr)
00217               continue;
00218             else
00219               break; //done
00220           }
00221 
00222         ROS_DEBUG_STREAM("incomplete Velodyne packet read: "
00223                          << nbytes << " bytes");
00224       }
00225 
00226     if (!gps_time_) {
00227       // Average the times at which we begin and end reading.  Use that to
00228       // estimate when the scan occurred. Add the time offset.
00229       double time2 = ros::Time::now().toSec();
00230       pkt->stamp = ros::Time((time2 + time1) / 2.0 + time_offset);
00231     } else {
00232       // time for each packet is a 4 byte uint located starting at offset 1200 in
00233       // the data packet
00234       pkt->stamp = rosTimeFromGpsTimestamp(&(pkt->data[1200]));
00235     }
00236 
00237     return 0;
00238   }
00239 
00241   // InputPCAP class implementation
00243 
00251   InputPCAP::InputPCAP(ros::NodeHandle private_nh, uint16_t port,
00252                        double packet_rate, std::string filename,
00253                        bool read_once, bool read_fast, double repeat_delay):
00254     Input(private_nh, port),
00255     packet_rate_(packet_rate),
00256     filename_(filename)
00257   {
00258     pcap_ = NULL;  
00259     empty_ = true;
00260 
00261     // get parameters using private node handle
00262     private_nh.param("read_once", read_once_, false);
00263     private_nh.param("read_fast", read_fast_, false);
00264     private_nh.param("repeat_delay", repeat_delay_, 0.0);
00265 
00266     if (read_once_)
00267       ROS_INFO("Read input file only once.");
00268     if (read_fast_)
00269       ROS_INFO("Read input file as quickly as possible.");
00270     if (repeat_delay_ > 0.0)
00271       ROS_INFO("Delay %.3f seconds before repeating input file.",
00272                repeat_delay_);
00273 
00274     // Open the PCAP dump file
00275     ROS_INFO("Opening PCAP file \"%s\"", filename_.c_str());
00276     if ((pcap_ = pcap_open_offline(filename_.c_str(), errbuf_) ) == NULL)
00277       {
00278         ROS_FATAL("Error opening Velodyne socket dump file.");
00279         return;
00280       }
00281 
00282     std::stringstream filter;
00283     if( devip_str_ != "" )              // using specific IP?
00284       {
00285         filter << "src host " << devip_str_ << " && ";
00286       }
00287     filter << "udp dst port " << port;
00288     pcap_compile(pcap_, &pcap_packet_filter_,
00289                  filter.str().c_str(), 1, PCAP_NETMASK_UNKNOWN);
00290   }
00291 
00293   InputPCAP::~InputPCAP(void)
00294   {
00295     pcap_close(pcap_);
00296   }
00297 
00299   int InputPCAP::getPacket(velodyne_msgs::VelodynePacket *pkt, const double time_offset)
00300   {
00301     struct pcap_pkthdr *header;
00302     const u_char *pkt_data;
00303 
00304     while (true)
00305       {
00306         int res;
00307         if ((res = pcap_next_ex(pcap_, &header, &pkt_data)) >= 0)
00308           {
00309             // Skip packets not for the correct port and from the
00310             // selected IP address.
00311             if (0 == pcap_offline_filter(&pcap_packet_filter_,
00312                                           header, pkt_data))
00313               continue;
00314 
00315             // Keep the reader from blowing through the file.
00316             if (read_fast_ == false)
00317               packet_rate_.sleep();
00318             
00319             memcpy(&pkt->data[0], pkt_data+42, packet_size);
00320             pkt->stamp = ros::Time::now(); // time_offset not considered here, as no synchronization required
00321             empty_ = false;
00322             return 0;                   // success
00323           }
00324 
00325         if (empty_)                 // no data in file?
00326           {
00327             ROS_WARN("Error %d reading Velodyne packet: %s", 
00328                      res, pcap_geterr(pcap_));
00329             return -1;
00330           }
00331 
00332         if (read_once_)
00333           {
00334             ROS_INFO("end of file reached -- done reading.");
00335             return -1;
00336           }
00337         
00338         if (repeat_delay_ > 0.0)
00339           {
00340             ROS_INFO("end of file reached -- delaying %.3f seconds.",
00341                      repeat_delay_);
00342             usleep(rint(repeat_delay_ * 1000000.0));
00343           }
00344 
00345         ROS_DEBUG("replaying Velodyne dump file");
00346 
00347         // I can't figure out how to rewind the file, because it
00348         // starts with some kind of header.  So, close the file
00349         // and reopen it with pcap.
00350         pcap_close(pcap_);
00351         pcap_ = pcap_open_offline(filename_.c_str(), errbuf_);
00352         empty_ = true;              // maybe the file disappeared?
00353       } // loop back and try again
00354   }
00355 
00356 } // velodyne namespace


velodyne_driver
Author(s): Jack O'Quin, Patrick Beeson, Michael Quinlan, Yaxin Liu
autogenerated on Wed Jul 3 2019 19:32:21