nodelet.cpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2010, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage, Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Id$
35  *
36  */
37 
45 #include <signal.h>
46 
47 #include <ros/ros.h>
48 #include <ros/xmlrpc_manager.h>
49 #include <bondcpp/bond.h>
50 #include "nodelet/loader.h"
51 #include "nodelet/NodeletList.h"
52 #include "nodelet/NodeletLoad.h"
53 #include "nodelet/NodeletUnload.h"
54 
55 #ifndef _WIN32
56 # include <uuid/uuid.h>
57 #else
58 # include <rpc.h>
59 #endif
60 
61 std::string genId()
62 {
63 #ifndef _WIN32
64  uuid_t uuid;
65  uuid_generate_random(uuid);
66  char uuid_str[40];
67  uuid_unparse(uuid, uuid_str);
68  return std::string(uuid_str);
69 #else
70  UUID uuid;
71  UuidCreate(&uuid);
72  RPC_CSTR str;
73  UuidToStringA(&uuid, &str);
74  std::string return_string(reinterpret_cast<char *>(str));
75  RpcStringFreeA(&str);
76  return return_string;
77 #endif
78 }
79 
81 {
82  private:
83  std::string command_;
84  std::string type_;
85  std::string name_;
86  std::string default_name_;
87  std::string manager_;
88  std::vector<std::string> local_args_;
90 
91  public:
93  bool
94  parseArgs(int argc, char** argv)
95  {
96  std::vector<std::string> non_ros_args;
97  ros::removeROSArgs (argc, argv, non_ros_args);
98  size_t used_args = 0;
99 
100  if (non_ros_args.size() > 1)
101  command_ = non_ros_args[1];
102  else
103  return false;
104 
105  if (command_ == "load" && non_ros_args.size() > 3)
106  {
107  type_ = non_ros_args[2];
108  manager_ = non_ros_args[3];
109  used_args = 4;
110 
111  if (non_ros_args.size() > used_args)
112  {
113  if (non_ros_args[used_args] == "--no-bond")
114  {
115  is_bond_enabled_ = false;
116  ++used_args;
117  }
118  }
119  }
120 
121  else if (command_ == "unload" && non_ros_args.size() > 3)
122  {
123  type_ = "nodelet_unloader";
124  name_ = non_ros_args[2];
125  manager_ = non_ros_args[3];
126  used_args = 4;
127  }
128  else if (command_ == "standalone" && non_ros_args.size() > 2)
129  {
130  type_ = non_ros_args[2];
131  printf("type is %s\n", type_.c_str());
132  used_args = 3;
133  }
134 
135  if (command_ == "manager")
136  used_args = 2;
137 
138  for (size_t i = used_args; i < non_ros_args.size(); i++)
139  local_args_.push_back(non_ros_args[i]);
140 
141 
142  if (used_args > 0) return true;
143  else return false;
144 
145  };
146 
147 
148  std::string getCommand () const { return (command_); }
149  std::string getType () const { return (type_); }
150  std::string getName () const { return (name_); }
151  std::string getManager() const { return (manager_); }
152  bool isBondEnabled() const { return is_bond_enabled_; }
153 
154  std::vector<std::string> getMyArgv () const {return local_args_;};
155  std::string getDefaultName()
156  {
157  std::string s = type_;
158  replace(s.begin(), s.end(), '/', '_');
159  return s;
160  };
161 
162 };
163 
164 
166 {
167  public:
169 
170  bool
171  unloadNodelet (const std::string &name, const std::string &manager)
172  {
173  ROS_INFO_STREAM ("Unloading nodelet " << name << " from manager " << manager);
174 
175  std::string service_name = manager + "/unload_nodelet";
176  // Check if the service exists and is available
177  if (!ros::service::exists (service_name, true))
178  {
179  // Probably the manager has shut down already, which is fine
180  ROS_WARN("Couldn't find service %s, perhaps the manager is already shut down",
181  service_name.c_str());
182  return (false);
183  }
184 
185  ros::ServiceClient client = n_.serviceClient<nodelet::NodeletUnload> (service_name);
186  //client.waitForExistence ();
187 
188  // Call the service
189  nodelet::NodeletUnload srv;
190  srv.request.name = name;
191  if (!client.call (srv))
192  {
193  // Maybe service shut down in the meantime, which isn't an error
194  if (ros::service::exists(service_name, false))
195  ROS_FATAL_STREAM("Failed to unload nodelet '" << name << "` from manager `" << manager << "'");
196  return (false);
197  }
198  return (true);
199  }
200 
202 
203  bool
204  loadNodelet (const std::string &name, const std::string &type,
205  const std::string &manager, const std::vector<std::string> &args,
206  const std::string &bond_id)
207  {
209  std::vector<std::string> sources (remappings.size ()), targets (remappings.size ());
210  ROS_INFO_STREAM ("Loading nodelet " << name << " of type " << type << " to manager " << manager << " with the following remappings:");
211  int i = 0;
212  for (ros::M_string::iterator it = remappings.begin (); it != remappings.end (); ++it, ++i)
213  {
214  sources[i] = (*it).first;
215  targets[i] = (*it).second;
216  ROS_INFO_STREAM (sources[i] << " -> " << targets[i]);
217  }
218 
219  // Get and set the parameters
221  std::string node_name = ros::this_node::getName ();
222  n_.getParam (node_name, param);
223  n_.setParam (name, param);
224 
225  std::string service_name = std::string (manager) + "/load_nodelet";
226 
227  // Wait until the service is advertised
228  bool srv_exists = false;
229  int timeout_sec = 10;
230  int timeout_count = 0;
231  ROS_DEBUG ("Waiting for service %s to be available...", service_name.c_str ());
232  ros::ServiceClient client = n_.serviceClient<nodelet::NodeletLoad> (service_name);
233  while (!srv_exists) {
234  if (timeout_count > 0) {
235  ROS_WARN ("Waiting for service %s to be available for %d seconds...", service_name.c_str (), timeout_count * timeout_sec);
236  }
237  srv_exists = client.waitForExistence (ros::Duration (timeout_sec));
238  if (!srv_exists) {
239  timeout_count += 1;
240  }
241  }
242 
243  // Call the service
244  nodelet::NodeletLoad srv;
245  srv.request.name = std::string (name);
246  srv.request.type = std::string (type);
247  srv.request.remap_source_args = sources;
248  srv.request.remap_target_args = targets;
249  srv.request.my_argv = args;
250  srv.request.bond_id = bond_id;
251  if (!client.call (srv))
252  {
253  ROS_FATAL_STREAM("Failed to load nodelet '" << name << "` of type `" << type << "` to manager `" << manager << "'");
254  return false;
255  }
256  return true;
257  }
258  private:
260 };
261 
262 void print_usage(int argc, char** argv)
263 {
264  printf("Your usage: \n");
265  for (int i = 0; i < argc; i++)
266  printf("%s ", argv[i]);
267  printf("\nnodelet usage:\n");
268  printf("nodelet load pkg/Type manager [--no-bond] - Launch a nodelet of type pkg/Type on manager manager\n");
269  printf("nodelet standalone pkg/Type - Launch a nodelet of type pkg/Type in a standalone node\n");
270  printf("nodelet unload name manager - Unload a nodelet by name from manager\n");
271  printf("nodelet manager - Launch a nodelet manager node\n");
272 
273 };
274 
275 sig_atomic_t volatile request_shutdown = 0;
276 
278 {
279  request_shutdown = 1;
280 }
281 
282 // Shutdown can be triggered externally by an XML-RPC call, this is how "rosnode kill"
283 // works. When shutting down a "nodelet load" we always want to unload the nodelet
284 // before shutting down our ROS comm channels, so we override the default roscpp
285 // handler for a "shutdown" XML-RPC call.
287 {
288  int num_params = 0;
289  if (params.getType() == XmlRpc::XmlRpcValue::TypeArray)
290  num_params = params.size();
291  if (num_params > 1)
292  {
293  std::string reason = params[1];
294  ROS_WARN("Shutdown request received. Reason: [%s]", reason.c_str());
295  request_shutdown = 1;
296  }
297 
298  result = ros::xmlrpc::responseInt(1, "", 0);
299 }
300 
301 /* ---[ */
302 int
303  main (int argc, char** argv)
304 {
305  NodeletArgumentParsing arg_parser;
306 
307  if (!arg_parser.parseArgs(argc, argv))
308  {
309  print_usage(argc, argv);
310  return (-1);
311  }
312  std::string command = arg_parser.getCommand();
313 
314 
315  if (command == "manager")
316  {
317  ros::init (argc, argv, "manager");
318  nodelet::Loader n;
319  ros::spin ();
320  }
321  else if (command == "standalone")
322  {
323  ros::init (argc, argv, arg_parser.getDefaultName());
324 
325  ros::NodeHandle nh;
326  nodelet::Loader n(false);
327  ros::M_string remappings; //Remappings are already applied by ROS no need to generate them.
328  std::string nodelet_name = ros::this_node::getName ();
329  std::string nodelet_type = arg_parser.getType();
330  if(!n.load(nodelet_name, nodelet_type, remappings, arg_parser.getMyArgv()))
331  return -1;
332 
333  ROS_DEBUG("Successfully loaded nodelet of type '%s' into name '%s'\n", nodelet_name.c_str(), nodelet_name.c_str());
334 
335  ros::spin();
336  }
337  else if (command == "load")
338  {
339  // NoSimTime option reduces CPU load when running with Gazebo with a fast clock topic.
341  NodeletInterface ni;
342  ros::NodeHandle nh;
343  std::string name = ros::this_node::getName ();
344  std::string type = arg_parser.getType();
345  std::string manager = arg_parser.getManager();
346  std::string bond_id;
347  if (arg_parser.isBondEnabled())
348  bond_id = name + "_" + genId();
349  bond::Bond bond(manager + "/bond", bond_id);
350  if (!ni.loadNodelet(name, type, manager, arg_parser.getMyArgv(), bond_id))
351  return -1;
352 
353  // Override default exit handlers for roscpp
354  signal(SIGINT, nodeletLoaderSigIntHandler);
355  ros::XMLRPCManager::instance()->unbind("shutdown");
356  ros::XMLRPCManager::instance()->bind("shutdown", shutdownCallback);
357 
358  if (arg_parser.isBondEnabled())
359  bond.start();
360  // Spin our own loop
361  ros::AsyncSpinner spinner(1);
362  spinner.start();
363  while (!request_shutdown)
364  {
365  if (arg_parser.isBondEnabled() && bond.isBroken())
366  {
367  ROS_INFO("Bond broken, exiting");
368  goto shutdown;
369  }
370 #ifndef _WIN32
371  usleep(100000);
372 #else
373  Sleep(100);
374 #endif
375  }
376  // Attempt to unload the nodelet before shutting down ROS
377  ni.unloadNodelet(name, manager);
378  if (arg_parser.isBondEnabled())
379  bond.breakBond();
380  shutdown:
381  ros::shutdown();
382  }
383  else if (command == "unload")
384  {
385  ros::init (argc, argv, arg_parser.getDefaultName ());
386  std::string name = arg_parser.getName ();
387  std::string manager = arg_parser.getManager();
388  NodeletInterface ni;
389  if (!ni.unloadNodelet(name, manager))
390  return -1;
391  }
392  else
393  {
394  ros::init(argc, argv, "nodelet");
395  ROS_ERROR("Command %s unknown", command.c_str());
396  return -1;
397  }
398 
399  return (0);
400 }
401 /* ]--- */
XmlRpc::XmlRpcValue::size
int size() const
NodeletArgumentParsing::command_
std::string command_
Definition: nodelet.cpp:83
ros::NodeHandle::setParam
void setParam(const std::string &key, bool b) const
ros::ServiceClient::waitForExistence
bool waitForExistence(ros::Duration timeout=ros::Duration(-1))
main
int main(int argc, char **argv)
Definition: nodelet.cpp:303
genId
std::string genId()
Definition: nodelet.cpp:61
ros::service::exists
ROSCPP_DECL bool exists(const std::string &service_name, bool print_failure_reason)
ros::init
ROSCPP_DECL void init(const M_string &remappings, const std::string &name, uint32_t options=0)
ros::xmlrpc::responseInt
ROSCPP_DECL XmlRpc::XmlRpcValue responseInt(int code, const std::string &msg, int response)
ros::AsyncSpinner::start
void start()
s
XmlRpcServer s
ros::NodeHandle::getParam
bool getParam(const std::string &key, bool &b) const
ROS_FATAL_STREAM
#define ROS_FATAL_STREAM(args)
ros.h
command
ROSLIB_DECL std::string command(const std::string &cmd)
ros::AsyncSpinner
ros::NodeHandle::serviceClient
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
ros::shutdown
ROSCPP_DECL void shutdown()
NodeletArgumentParsing::isBondEnabled
bool isBondEnabled() const
Definition: nodelet.cpp:152
nodelet::Loader
A class which will construct and sequentially call Nodelets according to xml This is the primary way ...
Definition: loader.h:62
NodeletArgumentParsing::name_
std::string name_
Definition: nodelet.cpp:85
nodelet::Loader::load
bool load(const std::string &name, const std::string &type, const M_string &remappings, const V_string &my_argv)
Load a nodelet.
Definition: loader.cpp:265
bond.h
xmlrpc_manager.h
NodeletArgumentParsing::local_args_
std::vector< std::string > local_args_
Definition: nodelet.cpp:88
shutdown
ROSCONSOLE_DECL void shutdown()
NodeletArgumentParsing::getMyArgv
std::vector< std::string > getMyArgv() const
Definition: nodelet.cpp:154
bond::Bond
print_usage
void print_usage(int argc, char **argv)
Definition: nodelet.cpp:262
ROS_DEBUG
#define ROS_DEBUG(...)
NodeletInterface::n_
ros::NodeHandle n_
Definition: nodelet.cpp:259
NodeletArgumentParsing::manager_
std::string manager_
Definition: nodelet.cpp:87
ros::names::getRemappings
const ROSCPP_DECL M_string & getRemappings()
ros::ServiceClient
ROS_WARN
#define ROS_WARN(...)
ros::XMLRPCManager::instance
static const XMLRPCManagerPtr & instance()
bond
ROS_INFO_STREAM
#define ROS_INFO_STREAM(args)
request_shutdown
sig_atomic_t volatile request_shutdown
Definition: nodelet.cpp:275
XmlRpc::XmlRpcValue::getType
const Type & getType() const
NodeletInterface
Definition: nodelet.cpp:165
NodeletArgumentParsing::NodeletArgumentParsing
NodeletArgumentParsing()
Definition: nodelet.cpp:92
NodeletArgumentParsing::type_
std::string type_
Definition: nodelet.cpp:84
XmlRpc::XmlRpcValue::TypeArray
TypeArray
nodeletLoaderSigIntHandler
void nodeletLoaderSigIntHandler(int)
Definition: nodelet.cpp:277
ros::this_node::getName
const ROSCPP_DECL std::string & getName()
NodeletArgumentParsing
Definition: nodelet.cpp:80
NodeletArgumentParsing::getDefaultName
std::string getDefaultName()
Definition: nodelet.cpp:155
NodeletArgumentParsing::is_bond_enabled_
bool is_bond_enabled_
Definition: nodelet.cpp:89
NodeletArgumentParsing::getManager
std::string getManager() const
Definition: nodelet.cpp:151
ROS_ERROR
#define ROS_ERROR(...)
ros::ServiceClient::call
bool call(const MReq &req, MRes &resp, const std::string &service_md5sum)
loader.h
ros::init_options::NoSimTime
NoSimTime
param
T param(const std::string &param_name, const T &default_val)
NodeletArgumentParsing::getType
std::string getType() const
Definition: nodelet.cpp:149
ros::spin
ROSCPP_DECL void spin()
NodeletInterface::unloadNodelet
bool unloadNodelet(const std::string &name, const std::string &manager)
Unload the nodelet.
Definition: nodelet.cpp:171
NodeletInterface::loadNodelet
bool loadNodelet(const std::string &name, const std::string &type, const std::string &manager, const std::vector< std::string > &args, const std::string &bond_id)
Load the nodelet.
Definition: nodelet.cpp:204
NodeletArgumentParsing::getCommand
std::string getCommand() const
Definition: nodelet.cpp:148
ros::removeROSArgs
ROSCPP_DECL void removeROSArgs(int argc, const char *const *argv, V_string &args_out)
ROS_INFO
#define ROS_INFO(...)
NodeletArgumentParsing::default_name_
std::string default_name_
Definition: nodelet.cpp:86
ros::Duration
shutdownCallback
void shutdownCallback(XmlRpc::XmlRpcValue &params, XmlRpc::XmlRpcValue &result)
Definition: nodelet.cpp:286
ros::init_options::NoSigintHandler
NoSigintHandler
XmlRpc::XmlRpcValue
ros::NodeHandle
NodeletArgumentParsing::getName
std::string getName() const
Definition: nodelet.cpp:150
NodeletArgumentParsing::parseArgs
bool parseArgs(int argc, char **argv)
Definition: nodelet.cpp:94
ros::M_string
std::map< std::string, std::string > M_string


nodelet
Author(s): Tully Foote, Radu Bogdan Rusu, Michael Carroll
autogenerated on Mon May 12 2025 02:38:31