$search
00001 /* 00002 * Copyright (c) 2008, Willow Garage, Inc. 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 the Willow Garage, Inc. 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 00030 #include <QApplication> 00031 #include <QTimer> 00032 00033 #include <boost/thread.hpp> 00034 #include <boost/program_options.hpp> 00035 #include <signal.h> 00036 00037 #include <OGRE/OgreHighLevelGpuProgramManager.h> 00038 #include <OGRE/OgreLogManager.h> 00039 #include <std_srvs/Empty.h> 00040 00041 #ifdef Q_OS_MAC 00042 #include <ApplicationServices/ApplicationServices.h> 00043 // Apparently OSX #defines 'check' to be an empty string somewhere. 00044 // That was fun to figure out. 00045 #undef check 00046 #endif 00047 00048 #include <ros/ros.h> 00049 00050 #include <ogre_tools/version.h> 00051 00052 #include "visualization_frame.h" 00053 #include "version.h" 00054 #include "wait_for_master_dialog.h" 00055 #include "visualizer_app.h" 00056 00057 namespace po = boost::program_options; 00058 00059 namespace rviz 00060 { 00061 00062 bool reloadShaders(std_srvs::Empty::Request&, std_srvs::Empty::Response&) 00063 { 00064 Ogre::ResourceManager::ResourceMapIterator it = Ogre::HighLevelGpuProgramManager::getSingleton().getResourceIterator(); 00065 while (it.hasMoreElements()) 00066 { 00067 Ogre::ResourcePtr resource = it.getNext(); 00068 resource->reload(); 00069 } 00070 return true; 00071 } 00072 00073 VisualizerApp::VisualizerApp() 00074 : timer_( 0 ) 00075 { 00076 } 00077 00078 void VisualizerApp::onTimer() 00079 { 00080 if( !continue_ ) 00081 { 00082 QApplication::closeAllWindows(); 00083 } 00084 } 00085 00086 bool VisualizerApp::init( int argc, char** argv ) 00087 { 00088 ROS_INFO( "rviz revision number %s", get_version().c_str() ); 00089 ROS_INFO( "ogre_tools revision number %s", ogre_tools::get_version().c_str() ); 00090 ROS_INFO( "compiled against OGRE version %d.%d.%d%s (%s)", 00091 OGRE_VERSION_MAJOR, OGRE_VERSION_MINOR, OGRE_VERSION_PATCH, 00092 OGRE_VERSION_SUFFIX, OGRE_VERSION_NAME ); 00093 00094 #ifdef Q_OS_MAC 00095 ProcessSerialNumber PSN; 00096 GetCurrentProcess(&PSN); 00097 TransformProcessType(&PSN,kProcessTransformToForegroundApplication); 00098 SetFrontProcess(&PSN); 00099 #endif 00100 00101 try 00102 { 00103 ros::init( argc, argv, "rviz", ros::init_options::AnonymousName | ros::init_options::NoSigintHandler ); 00104 00105 po::options_description options; 00106 options.add_options() 00107 ("help,h", "Produce this help message") 00108 ("splash-screen,s", po::value<std::string>(), "A custom splash-screen image to display") 00109 ("display-config,d", po::value<std::string>(), "A display config file (.vcg) to load") 00110 ("target-frame,t", po::value<std::string>(), "Set the target frame") 00111 ("fixed-frame,f", po::value<std::string>(), "Set the fixed frame") 00112 ("ogre-log,l", "Enable the Ogre.log file (output in cwd)") 00113 ("verbose,v", "Enable debug visualizations"); 00114 po::variables_map vm; 00115 std::string display_config, target_frame, fixed_frame, splash_path; 00116 bool enable_ogre_log = false; 00117 bool verbose = false; 00118 try 00119 { 00120 po::store( po::parse_command_line( argc, argv, options ), vm ); 00121 po::notify( vm ); 00122 00123 if( vm.count( "help" )) 00124 { 00125 std::cout << "rviz command line options:\n" << options; 00126 return false; 00127 } 00128 00129 if (vm.count("display-config")) 00130 { 00131 display_config = vm["display-config"].as<std::string>(); 00132 } 00133 00134 if (vm.count("splash-screen")) 00135 { 00136 splash_path = vm["splash-screen"].as<std::string>(); 00137 } 00138 00139 if (vm.count("target-frame")) 00140 { 00141 target_frame = vm["target-frame"].as<std::string>(); 00142 } 00143 00144 if (vm.count("fixed-frame")) 00145 { 00146 fixed_frame = vm["fixed-frame"].as<std::string>(); 00147 } 00148 00149 if (vm.count("ogre-log")) 00150 { 00151 enable_ogre_log = true; 00152 } 00153 00154 if (vm.count("verbose")) 00155 { 00156 verbose = true; 00157 } 00158 } 00159 catch (std::exception& e) 00160 { 00161 ROS_ERROR("Error parsing command line: %s", e.what()); 00162 return false; 00163 } 00164 00165 if( !ros::master::check() ) 00166 { 00167 WaitForMasterDialog* dialog = new WaitForMasterDialog; 00168 if( dialog->exec() != QDialog::Accepted ) 00169 { 00170 return false; 00171 } 00172 } 00173 00174 // block kill signals on all threads, since this also disables signals in threads 00175 // created by this one (the main thread) 00176 sigset_t sig_set; 00177 sigemptyset(&sig_set); 00178 sigaddset(&sig_set, SIGKILL); 00179 sigaddset(&sig_set, SIGTERM); 00180 sigaddset(&sig_set, SIGQUIT); 00181 sigaddset(&sig_set, SIGINT); 00182 pthread_sigmask(SIG_BLOCK, &sig_set, NULL); 00183 00184 // Start up our signal handler 00185 continue_ = true; 00186 signal_handler_thread_ = boost::thread(boost::bind(&VisualizerApp::signalHandler, this)); 00187 00188 nh_.reset( new ros::NodeHandle ); 00189 00190 Ogre::LogManager* log_manager = new Ogre::LogManager(); 00191 log_manager->createLog( "Ogre.log", false, false, !enable_ogre_log ); 00192 00193 frame_ = new VisualizationFrame; 00194 frame_->initialize( display_config, fixed_frame, target_frame, splash_path, verbose ); 00195 frame_->show(); 00196 00197 timer_ = new QTimer( this ); 00198 connect( timer_, SIGNAL( timeout() ), this, SLOT( onTimer() )); 00199 timer_->start( 100 ); 00200 00201 ros::NodeHandle private_nh("~"); 00202 reload_shaders_service_ = private_nh.advertiseService("reload_shaders", reloadShaders); 00203 } 00204 catch (std::exception& e) 00205 { 00206 ROS_ERROR("Caught exception while loading: %s", e.what()); 00207 return false; 00208 } 00209 00210 return true; 00211 } 00212 00213 VisualizerApp::~VisualizerApp() 00214 { 00215 if( timer_ ) 00216 { 00217 timer_->stop(); 00218 } 00219 continue_ = false; 00220 00221 delete frame_; 00222 00223 raise(SIGQUIT); 00224 00225 signal_handler_thread_.join(); 00226 } 00227 00228 void VisualizerApp::signalHandler() 00229 { 00230 sigset_t signal_set; 00231 while(continue_) 00232 { 00233 // Wait for any signals 00234 sigfillset(&signal_set); 00235 00236 #if defined(Q_OS_MAC) 00237 int sig; 00238 sigwait(&signal_set, &sig); 00239 #else 00240 struct timespec ts = {0, 100000000}; 00241 int sig = sigtimedwait(&signal_set, NULL, &ts); 00242 #endif 00243 00244 switch( sig ) 00245 { 00246 case SIGKILL: 00247 case SIGTERM: 00248 case SIGQUIT: 00249 { 00250 exit(1); 00251 } 00252 break; 00253 00254 case SIGINT: 00255 { 00256 ros::shutdown(); 00257 continue_ = false; 00258 return; 00259 } 00260 break; 00261 00262 default: 00263 break; 00264 } 00265 } 00266 } 00267 00268 } // namespace rviz