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 #include <bondcpp/bond.h>
00036
00037 #include <ros/ros.h>
00038 #include <ros/callback_queue.h>
00039 #include <nodelet/NodeletLoad.h>
00040 #include <nodelet/NodeletList.h>
00041 #include <nodelet/NodeletUnload.h>
00042
00043 #include <boost/ptr_container/ptr_map.hpp>
00044 #include <boost/utility.hpp>
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 namespace nodelet
00068 {
00069
00070 typedef boost::shared_ptr<Nodelet> NodeletPtr;
00071
00073 class LoaderROS
00074 {
00075 public:
00076 LoaderROS(Loader* parent, const ros::NodeHandle& nh)
00077 : parent_(parent)
00078 , nh_(nh)
00079 , bond_spinner_(1, &bond_callback_queue_)
00080 {
00081 load_server_ = nh_.advertiseService("load_nodelet", &LoaderROS::serviceLoad, this);
00082 unload_server_ = nh_.advertiseService("unload_nodelet", &LoaderROS::serviceUnload, this);
00083 list_server_ = nh_.advertiseService("list", &LoaderROS::serviceList, this);
00084
00085 bond_spinner_.start();
00086 }
00087
00088 private:
00089 bool serviceLoad(nodelet::NodeletLoad::Request &req,
00090 nodelet::NodeletLoad::Response &res)
00091 {
00092
00093 M_string remappings;
00094 if (req.remap_source_args.size() != req.remap_target_args.size())
00095 {
00096 ROS_ERROR("Bad remapppings provided, target and source of different length");
00097 }
00098 else
00099 {
00100 for (size_t i = 0; i < req.remap_source_args.size(); ++i)
00101 {
00102 remappings[ros::names::resolve(req.remap_source_args[i])] = ros::names::resolve(req.remap_target_args[i]);
00103 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());
00104 }
00105 }
00106
00107 res.success = parent_->load(req.name, req.type, remappings, req.my_argv);
00108
00109
00110 if (res.success && !req.bond_id.empty())
00111 {
00112 bond::Bond* bond = new bond::Bond(nh_.getNamespace() + "/bond", req.bond_id);
00113 bond_map_.insert(req.name, bond);
00114 bond->setCallbackQueue(&bond_callback_queue_);
00115 bond->setBrokenCallback(boost::bind(&LoaderROS::unload, this, req.name));
00116 bond->start();
00117 }
00118 return res.success;
00119 }
00120
00121 bool serviceUnload(nodelet::NodeletUnload::Request &req,
00122 nodelet::NodeletUnload::Response &res)
00123 {
00124 res.success = unload(req.name);
00125 return res.success;
00126 }
00127
00128 bool unload(const std::string& name)
00129 {
00130 bool success = parent_->unload(name);
00131 if (!success)
00132 {
00133 ROS_ERROR("Failed to find nodelet with name '%s' to unload.", name.c_str());
00134 return success;
00135 }
00136
00137
00138 bond_map_.erase(name);
00139
00140 return success;
00141 }
00142
00143 bool serviceList(nodelet::NodeletList::Request &req,
00144 nodelet::NodeletList::Response &res)
00145 {
00146 res.nodelets = parent_->listLoadedNodelets();
00147 return true;
00148 }
00149
00150 Loader* parent_;
00151 ros::NodeHandle nh_;
00152 ros::ServiceServer load_server_;
00153 ros::ServiceServer unload_server_;
00154 ros::ServiceServer list_server_;
00155
00156 ros::CallbackQueue bond_callback_queue_;
00157 ros::AsyncSpinner bond_spinner_;
00158 typedef boost::ptr_map<std::string, bond::Bond> M_stringToBond;
00159 M_stringToBond bond_map_;
00160 };
00161
00162
00163 struct ManagedNodelet : boost::noncopyable
00164 {
00165 detail::CallbackQueuePtr st_queue;
00166 detail::CallbackQueuePtr mt_queue;
00167 NodeletPtr nodelet;
00168 detail::CallbackQueueManager* callback_manager;
00169
00171 ManagedNodelet(const NodeletPtr& nodelet, detail::CallbackQueueManager* cqm)
00172 : st_queue(new detail::CallbackQueue(cqm, nodelet))
00173 , mt_queue(new detail::CallbackQueue(cqm, nodelet))
00174 , nodelet(nodelet)
00175 , callback_manager(cqm)
00176 {
00177
00178
00179 callback_manager->addQueue(st_queue, false);
00180 callback_manager->addQueue(mt_queue, true);
00181 }
00182
00183 ~ManagedNodelet()
00184 {
00185 callback_manager->removeQueue(st_queue);
00186 callback_manager->removeQueue(mt_queue);
00187 }
00188 };
00189
00190 struct Loader::Impl
00191 {
00192 boost::shared_ptr<LoaderROS> services_;
00193
00194 boost::function<boost::shared_ptr<Nodelet> (const std::string& lookup_name)> create_instance_;
00195 boost::function<void ()> refresh_classes_;
00196 boost::shared_ptr<detail::CallbackQueueManager> callback_manager_;
00197
00198 typedef boost::ptr_map<std::string, ManagedNodelet> M_stringToNodelet;
00199 M_stringToNodelet nodelets_;
00200
00201 Impl()
00202 {
00203
00204 typedef pluginlib::ClassLoader<Nodelet> Loader;
00205 boost::shared_ptr<Loader> loader(new Loader("nodelet", "nodelet::Nodelet"));
00206
00207 create_instance_ = boost::bind(&Loader::createInstance, loader, _1);
00208 refresh_classes_ = boost::bind(&Loader::refreshDeclaredClasses, loader);
00209 }
00210
00211 Impl(const boost::function<boost::shared_ptr<Nodelet> (const std::string& lookup_name)>& create_instance)
00212 : create_instance_(create_instance)
00213 {
00214 }
00215
00216 void advertiseRosApi(Loader* parent, const ros::NodeHandle& server_nh)
00217 {
00218 int num_threads_param;
00219 server_nh.param("num_worker_threads", num_threads_param, 0);
00220 callback_manager_.reset(new detail::CallbackQueueManager(num_threads_param));
00221 ROS_INFO("Initializing nodelet with %d worker threads.", (int)callback_manager_->getNumWorkerThreads());
00222
00223 services_.reset(new LoaderROS(parent, server_nh));
00224 }
00225 };
00226
00228 Loader::Loader(bool provide_ros_api)
00229 : impl_(new Impl)
00230 {
00231 if (provide_ros_api)
00232 impl_->advertiseRosApi(this, ros::NodeHandle("~"));
00233 else
00234 impl_->callback_manager_.reset(new detail::CallbackQueueManager);
00235 }
00236
00237 Loader::Loader(const ros::NodeHandle& server_nh)
00238 : impl_(new Impl)
00239 {
00240 impl_->advertiseRosApi(this, server_nh);
00241 }
00242
00243 Loader::Loader(const boost::function<boost::shared_ptr<Nodelet> (const std::string& lookup_name)>& create_instance)
00244 : impl_(new Impl(create_instance))
00245 {
00246 impl_->callback_manager_.reset(new detail::CallbackQueueManager);
00247 }
00248
00249 Loader::~Loader()
00250 {
00251 }
00252
00253 bool Loader::load(const std::string &name, const std::string& type, const ros::M_string& remappings,
00254 const std::vector<std::string> & my_argv)
00255 {
00256 boost::mutex::scoped_lock lock(lock_);
00257 if (impl_->nodelets_.count(name) > 0)
00258 {
00259 ROS_ERROR("Cannot load nodelet %s for one exists with that name already", name.c_str());
00260 return false;
00261 }
00262
00263 NodeletPtr p;
00264 try
00265 {
00266 p = impl_->create_instance_(type);
00267 }
00268 catch (std::runtime_error& e)
00269 {
00270 try
00271 {
00272 impl_->refresh_classes_();
00273 p = impl_->create_instance_(type);
00274 }
00275 catch (std::runtime_error& e)
00276 {
00277 ROS_ERROR("Failed to load nodelet [%s] of type [%s]: %s", name.c_str(), type.c_str(), e.what());
00278 return false;
00279 }
00280 }
00281
00282 if (!p)
00283 {
00284 return false;
00285 }
00286 ROS_DEBUG("Done loading nodelet %s", name.c_str());
00287
00288 ManagedNodelet* mn = new ManagedNodelet(p, impl_->callback_manager_.get());
00289 impl_->nodelets_.insert(const_cast<std::string&>(name), mn);
00290 try {
00291 p->init(name, remappings, my_argv, mn->st_queue.get(), mn->mt_queue.get());
00293
00294 ROS_DEBUG("Done initing nodelet %s", name.c_str());
00295 return true;
00296 } catch(...) {
00297 Impl::M_stringToNodelet::iterator it = impl_->nodelets_.find(name);
00298 if (it != impl_->nodelets_.end())
00299 {
00300 impl_->nodelets_.erase(it);
00301 ROS_DEBUG ("Failed to initialize nodelet %s", name.c_str ());
00302 return (false);
00303 }
00304 }
00305 }
00306
00307 bool Loader::unload (const std::string & name)
00308 {
00309 boost::mutex::scoped_lock lock (lock_);
00310 Impl::M_stringToNodelet::iterator it = impl_->nodelets_.find(name);
00311 if (it != impl_->nodelets_.end())
00312 {
00313 impl_->nodelets_.erase(it);
00314 ROS_DEBUG ("Done unloading nodelet %s", name.c_str ());
00315 return (true);
00316 }
00317
00318 return (false);
00319 }
00320
00321 bool Loader::clear ()
00322 {
00323 boost::mutex::scoped_lock lock(lock_);
00324 impl_->nodelets_.clear();
00325 return true;
00326 };
00327
00328 std::vector<std::string> Loader::listLoadedNodelets()
00329 {
00330 boost::mutex::scoped_lock lock (lock_);
00331 std::vector<std::string> output;
00332 Impl::M_stringToNodelet::iterator it = impl_->nodelets_.begin();
00333 for (; it != impl_->nodelets_.end(); ++it)
00334 {
00335 output.push_back(it->first);
00336 }
00337 return output;
00338 }
00339
00340 }
00341