laser_tilt_controller_filter.h
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2009, Willow Garage, Inc.
00006 *  All rights reserved.
00007 *
00008 *  Redistribution and use in source and binary forms, with or without
00009 *  modification, are permitted provided that the following conditions
00010 *  are met:
00011 *
00012 *   * Redistributions of source code must retain the above copyright
00013 *     notice, this list of conditions and the following disclaimer.
00014 *   * Redistributions in binary form must reproduce the above
00015 *     copyright notice, this list of conditions and the following
00016 *     disclaimer in the documentation and/or other materials provided
00017 *     with the distribution.
00018 *   * Neither the name of Willow Garage, Inc. nor the names of its
00019 *     contributors may be used to endorse or promote products derived
00020 *     from this software without specific prior written permission.
00021 *
00022 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 *  POSSIBILITY OF SUCH DAMAGE.
00034 *
00035 * Author: Eitan Marder-Eppstein
00036 *********************************************************************/
00037 
00038 #include <XmlRpc.h>
00039 #include <sensor_msgs/LaserScan.h>
00040 #include <filters/filter_base.h>
00041 #include <pr2_msgs/LaserScannerSignal.h>
00042 #include <boost/thread/mutex.hpp>
00043 
00044 namespace laser_tilt_controller_filter {
00045   
00050   class LaserTiltControllerFilter : public filters::FilterBase<sensor_msgs::LaserScan>
00051   {
00052     public:
00053       LaserTiltControllerFilter(): signal_received_(false){}
00054 
00055       bool loadFilterSignals(){
00056         XmlRpc::XmlRpcValue filter_sections;
00057 
00058         if(!filters::FilterBase<sensor_msgs::LaserScan>::getParam("filter_sections", filter_sections)){
00059           //its ok to have an empty filter sections list... but we'll just return
00060           return true;
00061         }
00062 
00063         if(!(filter_sections.getType() == XmlRpc::XmlRpcValue::TypeArray)){
00064           ROS_ERROR("The filter_sections must be a list of integers");
00065           return false;
00066         }
00067 
00068         //loop through the XmlRpc list
00069         for(int i = 0; i < filter_sections.size(); ++i){
00070           XmlRpc::XmlRpcValue section = filter_sections[i];
00071 
00072           //check to make sure that integer values are being used
00073           if(!(section.getType() == XmlRpc::XmlRpcValue::TypeInt)){
00074             ROS_ERROR("The tilt_profile_times must be a list of integers");
00075             return false;
00076           }
00077 
00078           double section_int = int(section);
00079 
00080           //push the time back onto our vector
00081           filter_signals_.push_back(section_int);
00082         }
00083 
00084         return true;
00085       }
00086 
00087       bool loadTiltProfileTiming(){
00088         XmlRpc::XmlRpcValue tilt_profile_times;
00089         if(!filters::FilterBase<sensor_msgs::LaserScan>::getParam("tilt_profile_times", tilt_profile_times)){
00090           ROS_ERROR("No tilt_profile_times were given");
00091           return false;
00092         }
00093 
00094         if(!(tilt_profile_times.getType() == XmlRpc::XmlRpcValue::TypeArray)){
00095           ROS_ERROR("The tilt_profile_times must be a list of doubles");
00096           return false;
00097         }
00098 
00099         if(tilt_profile_times.size() < 2){
00100           ROS_ERROR("The tilt_profile_times list must contain at least two values... a start and an end");
00101           return false;
00102         }
00103 
00104         //loop through the XmlRpc list
00105         for(int i = 0; i < tilt_profile_times.size(); ++i){
00106           XmlRpc::XmlRpcValue time_xml = tilt_profile_times[i];
00107 
00108           //check to make sure that integer/double values are being used
00109           if(!(time_xml.getType() == XmlRpc::XmlRpcValue::TypeInt || time_xml.getType() == XmlRpc::XmlRpcValue::TypeDouble)){
00110             ROS_ERROR("The tilt_profile_times must be a list of doubles");
00111             return false;
00112           }
00113 
00114           double time_dbl = time_xml.getType() == XmlRpc::XmlRpcValue::TypeInt ? (int)(time_xml) : (double)(time_xml);
00115 
00116           //push the time back onto our vector
00117           tilt_profile_times_.push_back(time_dbl);
00118         }
00119 
00120         return true;
00121       }
00122 
00123       bool configure(){
00124         ROS_DEBUG("Filtering initialized");
00125         bool success = loadTiltProfileTiming() && loadFilterSignals();
00126 
00127         ros::NodeHandle n;
00128         signal_sub_ = n.subscribe("laser_tilt_controller/laser_scanner_signal", 1, &LaserTiltControllerFilter::signalCb, this);
00129         return success;
00130       }
00131 
00132       void signalCb(const pr2_msgs::LaserScannerSignal::ConstPtr& signal){
00133         boost::mutex::scoped_lock lock(mutex_);
00134         //we'll sync the timer to the signal for the beginning of the profile to make sure we don't drift
00135         if(signal->signal == 0){
00136           timer_zero_ = signal->header.stamp;
00137           signal_received_ = true;
00138         }
00139       }
00140 
00141       bool update(const sensor_msgs::LaserScan& scan_in, sensor_msgs::LaserScan& scan_out){
00142         ROS_DEBUG("Signal filter running, current timer %.4f, signal_received: %d", timer_zero_.toSec(), signal_received_);
00143         //make sure that we've received at least one scanner signal before throwing out scans
00144         if(!signal_received_){
00145           scan_out = scan_in;
00146           return true;
00147         }
00148 
00149         boost::mutex::scoped_lock lock(mutex_);
00150         double time_diff = (scan_in.header.stamp - timer_zero_).toSec() + tilt_profile_times_.front();
00151 
00152         //make sure to put the time within the period of the profile
00153         ROS_DEBUG("time_diff: %.4f, periold: %.4f", time_diff, tilt_profile_times_.back());
00154         double period_time = fmod(time_diff, tilt_profile_times_.back());
00155 
00156         int profile_section = 0;
00157         //get the period in which the scan falls
00158         for(unsigned int i = 0; i < tilt_profile_times_.size() - 1; ++i){
00159           ROS_DEBUG("Checking period_time: %.4f against tilt_profile time: %.4f and next %.4f", 
00160               period_time, tilt_profile_times_[i], tilt_profile_times_[i+1]);
00161           if(period_time >= tilt_profile_times_[i] && period_time < tilt_profile_times_[i + 1]){
00162             profile_section = i;
00163           }
00164         }
00165 
00166         ROS_DEBUG("Profile section: %d, time: %.4f", profile_section, scan_in.header.stamp.toSec());
00167 
00168         //check if our current tilt signal is one that should be filtered
00169         for(unsigned int i = 0; i < filter_signals_.size(); ++i){
00170           if(filter_signals_[i] == profile_section){
00171             sensor_msgs::LaserScan empty_scan;
00172             empty_scan.header = scan_in.header;
00173             scan_out = empty_scan;
00174             ROS_DEBUG("Filtering out scan");
00175             return true;
00176           }
00177         }
00178 
00179         //if we made it here, then the tilt signal does not need to be
00180         //filtered, so we'll just send the scan on
00181         scan_out = scan_in;
00182         return true;
00183       }
00184 
00185       ~LaserTiltControllerFilter() {}
00186 
00187     private:
00188       std::vector<int> filter_signals_;
00189       std::vector<double> tilt_profile_times_;
00190       ros::Time timer_zero_;
00191       boost::mutex mutex_;
00192       bool signal_received_;
00193       ros::Subscriber signal_sub_;
00194   };
00195 
00196 };


laser_tilt_controller_filter
Author(s): Eitan Marder-Eppstein
autogenerated on Thu Aug 27 2015 14:29:22