00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <nodelet/loader.h>
00031 #include <nodelet/nodelet.h>
00032 #include <nodelet/detail/callback_queue.h>
00033 #include <nodelet/detail/callback_queue_manager.h>
00034 #include <pluginlib/class_loader.h>
00035
00036 #include <ros/ros.h>
00037 #include <ros/callback_queue.h>
00038 #include <nodelet/NodeletLoad.h>
00039 #include <nodelet/NodeletList.h>
00040 #include <nodelet/NodeletUnload.h>
00041
00042 #include <sstream>
00043 #include <map>
00044 #include <boost/shared_ptr.hpp>
00045
00046 namespace nodelet
00047 {
00048
00049 namespace detail
00050 {
00051 class LoaderROS
00052 {
00053 public:
00054 LoaderROS(Loader* parent, const ros::NodeHandle& nh)
00055 : parent_(parent)
00056 , nh_(nh)
00057 , bond_spinner_(1, &bond_callback_queue_)
00058 {
00059 load_server_ = nh_.advertiseService("load_nodelet", &LoaderROS::serviceLoad, this);
00060 unload_server_ = nh_.advertiseService("unload_nodelet", &LoaderROS::serviceUnload, this);
00061 list_server_ = nh_.advertiseService("list", &LoaderROS::serviceList, this);
00062
00063 bond_spinner_.start();
00064 }
00065
00066 private:
00067 bool serviceLoad(nodelet::NodeletLoad::Request &req,
00068 nodelet::NodeletLoad::Response &res)
00069 {
00070
00071 M_string remappings;
00072 if (req.remap_source_args.size() != req.remap_target_args.size())
00073 {
00074 ROS_ERROR("Bad remapppings provided, target and source of different length");
00075 }
00076 else
00077 {
00078 for (size_t i = 0; i < req.remap_source_args.size(); ++i)
00079 {
00080 remappings[ros::names::resolve(req.remap_source_args[i])] = ros::names::resolve(req.remap_target_args[i]);
00081 ROS_DEBUG("%s:%s\n", ros::names::resolve(req.remap_source_args[i]).c_str(), remappings[ros::names::resolve(req.remap_source_args[i])].c_str());
00082 }
00083 }
00084
00085 boost::shared_ptr<bond::Bond> bond;
00086 if (!req.bond_id.empty())
00087 {
00088 bond.reset(new bond::Bond(nh_.getNamespace() + "/bond", req.bond_id));
00089 bond->setCallbackQueue(&bond_callback_queue_);
00090 }
00091
00092 res.success = parent_->load(req.name, req.type, remappings, req.my_argv, bond);
00093 if (bond)
00094 bond->start();
00095 return res.success;
00096 }
00097
00098 bool serviceUnload(nodelet::NodeletUnload::Request &req,
00099 nodelet::NodeletUnload::Response &res)
00100 {
00101 res.success = parent_->unload(req.name);
00102 if (!res.success)
00103 {
00104 ROS_ERROR("Failed to find nodelet with name '%s' to unload.", req.name.c_str());
00105 }
00106
00107 return res.success;
00108 }
00109
00110 bool serviceList(nodelet::NodeletList::Request &req,
00111 nodelet::NodeletList::Response &res)
00112 {
00113
00114 res.nodelets = parent_->listLoadedNodelets();
00115 return true;
00116 }
00117
00118 Loader* parent_;
00119 ros::NodeHandle nh_;
00120 ros::ServiceServer load_server_;
00121 ros::ServiceServer unload_server_;
00122 ros::ServiceServer list_server_;
00123
00124
00125 ros::CallbackQueue bond_callback_queue_;
00126 ros::AsyncSpinner bond_spinner_;
00127 };
00128 }
00129
00130 Loader::Loader(bool provide_ros_api)
00131 : loader_(new pluginlib::ClassLoader<Nodelet>("nodelet", "nodelet::Nodelet"))
00132 {
00133 constructorImplementation(provide_ros_api, ros::NodeHandle("~"));
00134 }
00135
00136 Loader::Loader(ros::NodeHandle server_nh)
00137 : loader_(new pluginlib::ClassLoader<Nodelet>("nodelet", "nodelet::Nodelet"))
00138 {
00139 constructorImplementation(true, server_nh);
00140 }
00141
00142 void Loader::constructorImplementation(bool provide_ros_api, ros::NodeHandle server_nh)
00143 {
00144 std::string lib_string = "";
00145 std::vector<std::string> libs = loader_->getDeclaredClasses();
00146 for (size_t i = 0 ; i < libs.size(); ++i)
00147 {
00148 lib_string = lib_string + std::string(", ") + libs[i];
00149 }
00150
00151 if (provide_ros_api)
00152 {
00153 services_.reset(new detail::LoaderROS(this, server_nh));
00154 ROS_DEBUG("In nodelet::Loader found the following libs: %s", lib_string.c_str());
00155 int num_threads_param;
00156 if (server_nh.getParam ("num_worker_threads", num_threads_param))
00157 {
00158 callback_manager_ = detail::CallbackQueueManagerPtr (new detail::CallbackQueueManager (num_threads_param));
00159 ROS_INFO("Initializing nodelet with %d worker threads.", num_threads_param);
00160 }
00161 }
00162 if (!callback_manager_)
00163 callback_manager_ = detail::CallbackQueueManagerPtr (new detail::CallbackQueueManager);
00164 }
00165
00166 Loader::~Loader()
00167 {
00168 services_.reset();
00169
00170
00171
00172
00173
00174
00175 callback_manager_->stop();
00176 nodelets_.clear();
00177 callback_manager_.reset();
00178 }
00179
00180 bool Loader::load(const std::string &name, const std::string& type, const ros::M_string& remappings, const std::vector<std::string> & my_argv, boost::shared_ptr<bond::Bond> bond)
00181 {
00182 boost::mutex::scoped_lock lock (lock_);
00183 if (nodelets_.count(name) > 0)
00184 {
00185 ROS_ERROR("Cannot load nodelet %s for one exists with that name already", name.c_str());
00186 return false;
00187 }
00188
00189
00190 try
00191 {
00192 NodeletPtr p(loader_->createClassInstance(type));
00193 if (!p)
00194 {
00195 return false;
00196 }
00197
00198 nodelets_[name] = p;
00199 ROS_DEBUG("Done loading nodelet %s", name.c_str());
00200
00202 p->st_callback_queue_.reset(new detail::CallbackQueue(callback_manager_.get(), p));
00203 p->mt_callback_queue_.reset(new detail::CallbackQueue(callback_manager_.get(), p));
00204 p->init(name, remappings, my_argv, callback_manager_.get(), bond);
00205
00206 if (bond)
00207 bond->setBrokenCallback(boost::bind(&Loader::unload, this, name));
00208
00209 ROS_DEBUG("Done initing nodelet %s", name.c_str());
00210 return true;
00211 }
00212 catch (pluginlib::PluginlibException& e)
00213 {
00214 ROS_ERROR("Failed to load nodelet [%s] of type [%s]: %s", name.c_str(), type.c_str(), e.what());
00215 }
00216
00217 return false;
00218 }
00219
00220 bool Loader::unload (const std::string & name)
00221 {
00222 boost::mutex::scoped_lock lock (lock_);
00223 M_stringToNodelet::iterator it = nodelets_.find (name);
00224 if (it != nodelets_.end ())
00225 {
00226 it->second->disable();
00227 nodelets_.erase (it);
00228 ROS_DEBUG ("Done unloading nodelet %s", name.c_str ());
00229 return (true);
00230 }
00231
00232 return (false);
00233 }
00234
00236 bool Loader::clear ()
00237 {
00240 boost::mutex::scoped_lock lock (lock_);
00241 nodelets_.clear ();
00242 return (true);
00243 };
00244
00246 std::vector<std::string> Loader::listLoadedNodelets()
00247 {
00248 boost::mutex::scoped_lock lock (lock_);
00249 std::vector<std::string> output;
00250 std::map< std::string, boost::shared_ptr<Nodelet> >::iterator it = nodelets_.begin();
00251 for (; it != nodelets_.end(); ++it)
00252 {
00253 output.push_back(it->first);
00254 }
00255 return output;
00256 }
00257
00258 }
00259