ddynamic_reconfigure.cpp
Go to the documentation of this file.
1 #ifdef __clang__
2 #pragma clang diagnostic push
3 #pragma ide diagnostic ignored "OCDFAInspection"
4 #pragma clang diagnostic ignored "-Wunknown-pragmas"
5 #pragma ide diagnostic ignored "modernize-loop-convert"
6 #pragma ide diagnostic ignored "modernize-use-auto"
7 #endif
8 //
9 // Created by Noam Dori on 18/06/18.
10 //
12 #include <boost/foreach.hpp>
13 
14 using namespace boost;
15 namespace ddynamic_reconfigure {
16 
17  DDynamicReconfigure::DDynamicReconfigure(ros::NodeHandle &nh) {
18  nh_ = nh;
19  };
20 
21  void DDynamicReconfigure::add(DDPtr param) {
22  params_[param->getName()] = param;
23  };
24 
25  void DDynamicReconfigure::add(DDParam *param) {
26  add(DDPtr(param));
27  };
28 
29  void DDynamicReconfigure::remove(DDPtr param) {
30  remove(param->getName());
31  };
32 
33  void DDynamicReconfigure::remove(DDParam *param) {
34  remove(param->getName());
35  };
36 
37  void DDynamicReconfigure::remove(string param_name) {
38  params_.erase(param_name);
39  };
40 
41  void DDynamicReconfigure::start() {
42  ConfigDescription conf_desc = makeDescription(); // registers defaults and max/min descriptions.
43  Config conf = makeConfig(); // the actual config file in C++ form.
44 
45  function<bool(Reconfigure::Request& req, Reconfigure::Response& rsp)> callback = bind(&internalCallback,this,_1,_2);
46  // publishes Config and ConfigDescription.
47  set_service_ = nh_.advertiseService("set_parameters", callback); // this allows changes to the parameters
48 
49  // this makes the parameter descriptions
50  desc_pub_ = nh_.advertise<ConfigDescription>("parameter_descriptions", 1, true);
51  desc_pub_.publish(conf_desc);
52 
53  // this creates the type/level of everything
54  update_pub_ = nh_.advertise<Config>("parameter_updates", 1, true);
55  update_pub_.publish(conf);
56  }
57 
58  Config DDynamicReconfigure::makeConfig() {
59  Config conf;
60  GroupState group_state; // I dunno, but its important?
61 
62  // action 3 - prepping the GroupState msg for all params
63  group_state.name = "Default";
64  group_state.state = (unsigned char)true;
65 
66  // action 4 - prepping the Config msg for all params
67  conf.groups.push_back(group_state);
68  for(DDMap::const_iterator it = params_.begin(); it != params_.end(); it++) {it->second->prepConfig(conf);}
69  return conf;
70  }
71 
72  ConfigDescription DDynamicReconfigure::makeDescription() {
73  ConfigDescription conf_desc;
74  Group group; // registers level, type, description.
75 
76  // action 1 - prepping the Group msg for all params
77  group.name = "default";
78  for(DDMap::const_iterator it = params_.begin(); it != params_.end(); it++) {it->second->prepGroup(group);}
79 
80  // action 2 - prepping the ConfigDescription msg for all params
81  for(DDMap::const_iterator it = params_.begin(); it != params_.end(); it++) {it->second->prepConfigDescription(conf_desc);}
82  conf_desc.groups.push_back(group);
83  return conf_desc;
84  };
85 
86  void DDynamicReconfigure::start(DDFunc callback) {
87  start();
88  setCallback(callback);
89  };
90 
91  void DDynamicReconfigure::start(void(*callback)(const DDMap&,int)) {
92  DDFunc f(callback);
93  start(f);
94  };
95 
96  // this is also available in the header file (linking template functions is problematic.
97  // template <class T> void DDynamicReconfigure::start(void(T::*callback)(const DDMap&,int), T *obj) {
98  // DDFunc f = bind(callback,obj,_1);
99  // start();
100  // }
101 
102  void DDynamicReconfigure::setCallback(DDFunc callback) {
103  callback_ = make_shared<function<void(const DDMap&,int)> >(callback);
104  };
105 
106  void defaultCallback(const DDMap&,int) {};
107 
108  void DDynamicReconfigure::clearCallback() {
109  callback_ = make_shared<DDFunc>(&defaultCallback);
110  };
111 
112  // Private function: internal callback used by the service to call our lovely callback.
113  bool DDynamicReconfigure::internalCallback(DDynamicReconfigure *obj, Reconfigure::Request& req, Reconfigure::Response& rsp) {
114  ROS_DEBUG_STREAM("Called config callback of ddynamic_reconfigure");
115 
116  int level = obj->getUpdates(req, obj->params_);
117 
118  if (obj->callback_) {
119  try {
120  (*obj->callback_)(obj->params_,level);
121  } catch (std::exception &e) {
122  ROS_WARN("Reconfigure callback failed with exception %s: ", e.what());
123  } catch (...) {
124  ROS_WARN("Reconfigure callback failed with unprintable exception.");
125  }
126  }
127 
128  obj->update_pub_.publish(obj->makeConfig()); // updates the config
129 
130  return true;
131  }
132 
133  int DDynamicReconfigure::getUpdates(const Reconfigure::Request &req, DDMap &config) {
134  int level = 0;
135  // the ugly part of the code, since ROS does not provide a nice generic message. Oh well...
136  BOOST_FOREACH(const IntParameter i,req.config.ints) {
137  int new_level = reassign(config, i.name, i.value);
138  if(new_level == -1) {
139  ROS_ERROR_STREAM("Variable [" << i.name << "] is not registered");
140  } else {
141  level |= new_level;
142  }
143  }
144  BOOST_FOREACH(const DoubleParameter i,req.config.doubles) {
145  int new_level = reassign(config, i.name, i.value);
146  if(new_level == -1) {
147  ROS_ERROR_STREAM("Variable [" << i.name << "] is not registered");
148  } else {
149  level |= new_level;
150  }
151  }
152  BOOST_FOREACH(const BoolParameter i,req.config.bools) {
153  int new_level = reassign(config, i.name, (bool)i.value);
154  if(new_level == -1) {
155  ROS_ERROR_STREAM("Variable [" << i.name << "] is not registered");
156  } else {
157  level |= new_level;
158  }
159  }
160  BOOST_FOREACH(const StrParameter i,req.config.strs) {
161  int new_level = reassign(config, i.name, i.value);
162  if(new_level == -1) {
163  ROS_ERROR_STREAM("Variable [" << i.name << "] is not registered");
164  } else {
165  level |= new_level;
166  }
167  }
168  return level;
169  }
170 
171  template <class T>
172  int DDynamicReconfigure::reassign(DDMap& map, const string &name, T value) {
173  Value val(value); // abusing C++ against generic types here.
174  if(map.find(name) != map.end() && map[name]->sameType(val)) {
175  DDPtr old = map[name]; // this is the old map which might be updated.
176  if(old->sameValue(val)) { return 0;} else {
177  old->setValue(val);
178  return old->getLevel();
179  }
180  } else {
181  return -1;
182  }
183  }
184 
185  Value DDynamicReconfigure::get(const char *name) {
186  return ddynamic_reconfigure::get(params_,name);
187  }
188 
189  DDPtr DDynamicReconfigure::at(const char *name) {
190  return ddynamic_reconfigure::at(params_,name);
191  }
192 
193  ostream &operator<<(ostream &os, const DDynamicReconfigure &dd) {
194  os << "{" << *dd.params_.begin()->second;
195  for(DDMap::const_iterator it = ++dd.params_.begin(); it != dd.params_.end(); it++) {
196  os << "," << *it->second;
197  }
198  os << "}";
199  return os;
200  }
201 
202  DDPtr at(const DDMap& map, const char *name) {
203  DDMap::const_iterator it = map.find(name);
204  if(it == map.end()) {
205  return DDPtr(); // null pointer
206  } else { return it->second;}
207  }
208 
209  Value get(const DDMap& map, const char *name) {
210  DDMap::const_iterator it = map.find(name);
211  if(it == map.end()) {
212  return Value("\000");
213  } else { return it->second->getValue();}
214  }
215 }
216 #ifdef __clang__
217 #pragma clang diagnostic pop
218 #endif
ROSCPP_DECL void start()
void publish(const boost::shared_ptr< M > &message) const
boost::function< void(const DDMap &, int)> DDFunc
f
int getUpdates(const Reconfigure::Request &req, DDMap &config)
gets the updates and assigns them to DDMap
void callback(const DDMap &map, int)
Definition: dd_server.cpp:26
map< string, DDPtr > DDMap
The DDynamicReconfigure class is the main class responsible for keeping track of parameters basic pro...
Config makeConfig()
makes the config update for publishing
DDMap params_
a map of all contained parameters.
#define ROS_WARN(...)
virtual string getName() const =0
gets the name of the parameter, that is, the ID used in the program when requesting it...
DDPtr at(const DDMap &map, const char *name)
a tool people who use this API can use to find the param given within the param map.
The DDParam class is the abstraction of all parameter types, and is the template for creating them...
Definition: dd_param.h:48
ostream & operator<<(ostream &os, const DDynamicReconfigure &dd)
#define ROS_DEBUG_STREAM(args)
The Value class is used to wrap all basic data-types (bool,int,double,string) in something generic...
Definition: dd_value.h:29
Value get(const DDMap &map, const char *name)
a tool people who use this API can use to find the value given within the param map.
#define ROS_ERROR_STREAM(args)
void defaultCallback(const DDMap &, int)
boost::shared_ptr< DDFunc > callback_
the use defined callback to call when parameters are updated.
boost::shared_ptr< DDParam > DDPtr
Definition: dd_param.h:17


ddynamic_reconfigure
Author(s): Noam Dori
autogenerated on Thu May 16 2019 02:46:37