sick_tim_common.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013, Osnabrück University
00003  * All rights reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  * 
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of Osnabrück University nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  * 
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  *  Created on: 24.05.2012
00030  *
00031  *      Authors:
00032  *         Jochen Sprickerhof <jochen@sprickerhof.de>
00033  *         Martin Günther <mguenthe@uos.de>
00034  *
00035  * Based on the TiM communication example by SICK AG.
00036  *
00037  */
00038 
00039 #include <sick_tim/sick_tim_common.h>
00040 
00041 namespace sick_tim
00042 {
00043 
00044 SickTimCommon::SickTimCommon(AbstractParser* parser) :
00045     diagnosticPub_(NULL), expectedFrequency_(15.0), parser_(parser)
00046     // FIXME All Tims have 15Hz?
00047 {
00048   dynamic_reconfigure::Server<sick_tim::SickTimConfig>::CallbackType f;
00049   f = boost::bind(&sick_tim::SickTimCommon::update_config, this, _1, _2);
00050   dynamic_reconfigure_server_.setCallback(f);
00051 
00052   // datagram publisher (only for debug)
00053   ros::NodeHandle pn("~");
00054   pn.param<bool>("publish_datagram", publish_datagram_, false);
00055   if (publish_datagram_)
00056     datagram_pub_ = nh_.advertise<std_msgs::String>("datagram", 1000);
00057 
00058   // scan publisher
00059   pub_ = nh_.advertise<sensor_msgs::LaserScan>("scan", 1000);
00060 
00061   diagnostics_.setHardwareID("none");   // set from device after connection
00062   diagnosticPub_ = new diagnostic_updater::DiagnosedPublisher<sensor_msgs::LaserScan>(pub_, diagnostics_,
00063           // frequency should be target +- 10%.
00064           diagnostic_updater::FrequencyStatusParam(&expectedFrequency_, &expectedFrequency_, 0.1, 10),
00065           // timestamp delta can be from 0.0 to 1.3x what it ideally is.
00066           diagnostic_updater::TimeStampStatusParam(-1, 1.3 * 1.0/expectedFrequency_));
00067   ROS_ASSERT(diagnosticPub_ != NULL);
00068 }
00069 
00070 int SickTimCommon::stop_scanner()
00071 {
00072   /*
00073    * Stop streaming measurements
00074    */
00075   const char requestScanData0[] = {"\x02sEN LMDscandata 0\x03\0"};
00076   int result = sendSOPASCommand(requestScanData0, NULL);
00077   if (result != 0)
00078     // use printf because we cannot use ROS_ERROR from the destructor
00079     printf("\nSOPAS - Error stopping streaming scan data!\n");
00080   else
00081     printf("\nSOPAS - Stopped streaming scan data.\n");
00082 
00083   return result;
00084 }
00085 
00086 SickTimCommon::~SickTimCommon()
00087 {
00088   delete diagnosticPub_;
00089 
00090   printf("sick_tim driver exiting.\n");
00091 }
00092 
00093 
00094 int SickTimCommon::init()
00095 {
00096   int result = init_device();
00097   if(result != 0) {
00098       ROS_FATAL("Failed to init device: %d", result);
00099       return result;
00100   }
00101   result = init_scanner();
00102   if(result != 0) {
00103       ROS_FATAL("Failed to init scanner: %d", result);
00104   }
00105   return result;
00106 }
00107 
00108 int SickTimCommon::init_scanner()
00109 {
00110   /*
00111    * Read the SOPAS variable 'DeviceIdent' by index.
00112    */
00113   const char requestDeviceIdent[] = "\x02sRI0\x03\0";
00114   std::vector<unsigned char> identReply;
00115   int result = sendSOPASCommand(requestDeviceIdent, &identReply);
00116   if (result != 0)
00117   {
00118     ROS_ERROR("SOPAS - Error reading variable 'DeviceIdent'.");
00119     diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error reading variable 'DeviceIdent'.");
00120   }
00121 
00122   /*
00123    * Read the SOPAS variable 'SerialNumber' by name.
00124    */
00125   const char requestSerialNumber[] = "\x02sRN SerialNumber\x03\0";
00126   std::vector<unsigned char> serialReply;
00127   result = sendSOPASCommand(requestSerialNumber, &serialReply);
00128   if (result != 0)
00129   {
00130     ROS_ERROR("SOPAS - Error reading variable 'SerialNumber'.");
00131     diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error reading variable 'SerialNumber'.");
00132   }
00133 
00134   // set hardware ID based on DeviceIdent and SerialNumber
00135   identReply.push_back(0);  // add \0 to convert to string
00136   serialReply.push_back(0);
00137   std::string identStr;
00138   for(std::vector<unsigned char>::iterator it = identReply.begin(); it != identReply.end(); it++) {
00139       if(*it > 13)  // filter control characters for display
00140         identStr.push_back(*it);
00141   }
00142   std::string serialStr;
00143   for(std::vector<unsigned char>::iterator it = serialReply.begin(); it != serialReply.end(); it++) {
00144       if(*it > 13)
00145         serialStr.push_back(*it);
00146   }
00147   diagnostics_.setHardwareID(identStr + " " + serialStr);
00148 
00149   /*
00150    * Read the SOPAS variable 'FirmwareVersion' by name.
00151    */
00152   const char requestFirmwareVersion[] = {"\x02sRN FirmwareVersion\x03\0"};
00153   result = sendSOPASCommand(requestFirmwareVersion, NULL);
00154   if (result != 0)
00155   {
00156     ROS_ERROR("SOPAS - Error reading variable 'FirmwareVersion'.");
00157     diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error reading variable 'FirmwareVersion'.");
00158   }
00159 
00160   /*
00161    * Start streaming 'LMDscandata'.
00162    */
00163   const char requestScanData[] = {"\x02sEN LMDscandata 1\x03\0"};
00164   result = sendSOPASCommand(requestScanData, NULL);
00165   if (result != 0)
00166   {
00167     ROS_ERROR("SOPAS - Error starting to stream 'LMDscandata'.");
00168     diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "SOPAS - Error starting to stream 'LMDscandata'.");
00169     return EXIT_FAILURE;
00170   }
00171 
00172   return EXIT_SUCCESS;
00173 }
00174 
00175 int SickTimCommon::loopOnce()
00176 {
00177   diagnostics_.update();
00178 
00179   unsigned char receiveBuffer[65536];
00180   int actual_length = 0;
00181   static unsigned int iteration_count = 0;
00182 
00183   int result = get_datagram(receiveBuffer, 65536, &actual_length);
00184   if (result != 0)
00185   {
00186       ROS_ERROR("Read Error when getting datagram: %i.", result);
00187       diagnostics_.broadcast(diagnostic_msgs::DiagnosticStatus::ERROR, "Read Error when getting datagram.");
00188       return EXIT_FAILURE; // return failure to exit node
00189   }
00190   if(actual_length <= 0)
00191       return EXIT_SUCCESS; // return success to continue looping
00192 
00193   // ----- if requested, skip frames
00194   if (iteration_count++ % (config_.skip + 1) != 0)
00195     return EXIT_SUCCESS;
00196 
00197   if (publish_datagram_)
00198   {
00199     std_msgs::String datagram_msg;
00200     datagram_msg.data = std::string(reinterpret_cast<char*>(receiveBuffer));
00201     datagram_pub_.publish(datagram_msg);
00202   }
00203 
00204   sensor_msgs::LaserScan msg;
00205 
00206   /*
00207    * datagrams are enclosed in <STX> (0x02), <ETX> (0x03) pairs
00208    */
00209   char* buffer_pos = (char*)receiveBuffer;
00210   char *dstart, *dend;
00211   while( (dstart = strchr(buffer_pos, 0x02)) && (dend = strchr(dstart + 1, 0x03)) )
00212   {
00213     size_t dlength = dend - dstart;
00214     *dend = '\0';
00215     dstart++;
00216     int success = parser_->parse_datagram(dstart, dlength, config_, msg);
00217     if (success == EXIT_SUCCESS)
00218       diagnosticPub_->publish(msg);
00219     buffer_pos = dend + 1;
00220   }
00221 
00222   return EXIT_SUCCESS; // return success to continue looping
00223 }
00224 
00225 void SickTimCommon::check_angle_range(SickTimConfig &conf)
00226 {
00227   if (conf.min_ang > conf.max_ang)
00228   {
00229     ROS_WARN("Minimum angle must be greater than maximum angle. Adjusting min_ang.");
00230     conf.min_ang = conf.max_ang;
00231   }
00232 }
00233 
00234 void SickTimCommon::update_config(sick_tim::SickTimConfig &new_config, uint32_t level)
00235 {
00236   check_angle_range(new_config);
00237   config_ = new_config;
00238 }
00239 
00240 } /* namespace sick_tim */


sick_tim
Author(s): Jochen Sprickerhof , Martin Günther
autogenerated on Thu Aug 27 2015 15:14:34