00001 /********************************************************************* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2008, Willow Garage, Inc. 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of the Willow Garage nor the names of its 00018 * contributors may be used to endorse or promote products derived 00019 * from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 *********************************************************************/ 00034 00035 #include <cstdio> 00036 #include <ros/ros.h> 00037 #include<ros/time.h> 00038 00039 // Services 00040 #include "laser_assembler/AssembleScans2.h" 00041 00042 // Messages 00043 #include "sensor_msgs/PointCloud2.h" 00044 #include"dynamixel_msgs/JointState.h" 00045 #include"std_msgs/Time.h" 00046 00047 /* This is a modified periodic_snapshotter.cpp file that acts both as a timer and subscriber, depending on the value of the 00048 assembled_cloud_mode parameter. It defaults to subscriber. The node calls a service from the point_cloud2_assembler node 00049 from the laser_assembler package to create the compiled point cloud and then publishes the result. 00050 Timer: 00051 As a timer, the node performs its function every 5 seconds. To use this function, the assembled_cloud_mode parameter must 00052 be set to time. 00053 Subscriber: 00054 As a subscriber, the node subscribes to start and end times published while tilting the motor and sends those as necessary 00055 to the compilation service to put all of the point clouds together. One cloud is published for each complete sweep 00056 (i.e. -90 -> +90 -> -90). This is the default setting of the node.*/ 00057 00058 using namespace laser_assembler; 00059 00060 //global variables 00061 ros::Time start; 00062 ros::Time end; 00063 ros::Time init; 00064 int go = 0; 00065 std::string assembled_cloud_mode; 00066 double scan_time; 00067 00068 //call back for start time, saves in global variable 00069 void startTime(const std_msgs::Time &msg) { 00070 start = msg.data; 00071 } 00072 00073 //callback for end time, saves in global variable and updates go to start compilation 00074 void endTime(const std_msgs::Time &msg) { 00075 end = msg.data; 00076 go = 1; 00077 } 00078 00079 //compilation class created by combine_clouds with modifications to remove timer and work with motor times 00080 class PeriodicSnapshotter { 00081 00082 public: 00083 00084 PeriodicSnapshotter() { 00085 // Create a publisher for the clouds that we assemble 00086 pub_ = n_.advertise<sensor_msgs::PointCloud2> ("assembled_cloud", 1); 00087 00088 // Create the service client for calling the assembler 00089 client_ = n_.serviceClient<AssembleScans2>("assemble_scans2"); 00090 00091 // Start the timer that will trigger the processing loop (timerCallback) 00092 timer_ = n_.createTimer(ros::Duration(scan_time), &PeriodicSnapshotter::timerCallback, this); 00093 00094 // Need to track if we've called the timerCallback at least once 00095 first_time_ = true; 00096 } 00097 00098 void compile() { 00099 // Populate our service request based on motor times 00100 AssembleScans2 srv; 00101 srv.request.begin = start; 00102 srv.request.end = end; 00103 00104 // Make the service call 00105 if (client_.call(srv)) { 00106 //ROS_INFO_STREAM("Published Cloud") ; 00107 pub_.publish(srv.response.cloud); 00108 } 00109 else { 00110 //ROS_ERROR("Error making service call\n") ; 00111 } 00112 } 00113 00114 void timerCallback(const ros::TimerEvent& e) { 00115 // We don't want to build a cloud the first callback, since we we 00116 // don't have a start and end time yet 00117 if (first_time_) { 00118 first_time_ = false; 00119 00120 // Populate our service request based on our timer callback times 00121 AssembleScans2 srv; 00122 srv.request.begin = init; 00123 srv.request.end = e.current_real; 00124 00125 // Make the service call 00126 if (client_.call(srv)) { 00127 //ROS_INFO("Published Cloud"); 00128 pub_.publish(srv.response.cloud); 00129 } 00130 00131 else { 00132 //ROS_ERROR("Error making service call\n") ; 00133 } 00134 00135 return; 00136 } 00137 00138 // Populate our service request based on our timer callback times 00139 AssembleScans2 srv; 00140 srv.request.begin = e.last_real; 00141 srv.request.end = e.current_real; 00142 00143 // Make the service call 00144 if (client_.call(srv)) { 00145 //ROS_INFO("Published Cloud") ; 00146 pub_.publish(srv.response.cloud); 00147 } 00148 00149 else { 00150 //ROS_ERROR("Error making service call\n") ; 00151 } 00152 00153 //ROS_ERROR_STREAM(scan_time); 00154 } 00155 00156 private: 00157 ros::NodeHandle n_; 00158 ros::Publisher pub_; 00159 ros::ServiceClient client_; 00160 ros::Timer timer_; 00161 bool first_time_; 00162 } ; 00163 00164 //main 00165 int main(int argc, char **argv) 00166 { 00167 //initialize and wait for necessary services, etc. 00168 ros::init(argc, argv, "Cloud_Compiler"); 00169 ros::NodeHandle n; 00170 //ROS_INFO("Waiting for [build_cloud] to be advertised"); 00171 00172 //parameter for timer vs. subscriber and length of timer 00173 n.param<std::string>("assembled_cloud_mode", assembled_cloud_mode, "subscriber"); 00174 n.param<double>("scan_time", scan_time, 5); 00175 00176 //Wait for build cloud service to init 00177 ros::service::waitForService("build_cloud"); 00178 //ROS_INFO_STREAM("Found build_cloud! Starting the Cloud Compiler"); 00179 00180 //SUBSCRIBER intialization 00181 if (assembled_cloud_mode == "subscriber") 00182 { 00183 //Wait for dynamixel servo to init by waiting for /state topic 00184 ros::topic::waitForMessage<dynamixel_msgs::JointState>("/tilt_controller/state", ros::Duration(20)); 00185 00186 //subscribes to start and end time published by tilting motor 00187 ros::Subscriber sub_1=n.subscribe("/time/start_time", 1, &startTime); 00188 ros::Subscriber sub_2=n.subscribe("/time/end_time", 1, &endTime); 00189 } 00190 00191 PeriodicSnapshotter snapshotter; 00192 init = ros::Time::now(); 00193 00194 //SUBSCRIBER MAIN LOOP 00195 if (assembled_cloud_mode == "subscriber") 00196 { 00197 while(ros::ok()) 00198 { 00199 //when an end time comes in (which only occurs after start time is updated) run the compiler 00200 if(go==1) 00201 { 00202 snapshotter.compile(); 00203 go = 0; 00204 } 00205 00206 //wait for messages when not compiling 00207 else 00208 { 00209 ros::spinOnce(); 00210 } 00211 00212 //pause to save computing power 00213 ros::Duration(0.01).sleep(); 00214 } 00215 } 00216 00217 //TIMER main loop 00218 else if (assembled_cloud_mode == "time") 00219 { 00220 //wait for timer to begin service call 00221 ros::spin(); 00222 } 00223 00224 return 0; 00225 00226 }