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 #ifndef SWRI_ROSCPP_DYNAMIC_PARAMETERS_H_
00031 #define SWRI_ROSCPP_DYNAMIC_PARAMETERS_H_
00032
00033 #include <map>
00034 #include <string>
00035
00036 #include <boost/thread/mutex.hpp>
00037
00038 #include <ros/console.h>
00039 #include <ros/node_handle.h>
00040
00041 #include <dynamic_reconfigure/Config.h>
00042 #include <dynamic_reconfigure/ConfigDescription.h>
00043 #include <dynamic_reconfigure/GroupState.h>
00044 #include <dynamic_reconfigure/Reconfigure.h>
00045
00046 namespace swri
00047 {
00048 struct DynamicValue
00049 {
00050 enum Type
00051 {
00052 Bool = 0,
00053 Float = 1,
00054 Double = 2,
00055 Int = 3,
00056 String = 4
00057 };
00058
00059 Type type;
00060 std::string name;
00061 std::string description;
00062
00063
00064 boost::shared_ptr<float> flt;
00065 boost::shared_ptr<double> dbl;
00066 boost::shared_ptr<std::string> str;
00067 boost::shared_ptr<int> integer;
00068 boost::shared_ptr<bool> boolean;
00069
00070
00071 union
00072 {
00073 double d;
00074 bool b;
00075 int i;
00076 } Default;
00077 union
00078 {
00079 double d;
00080 int i;
00081 } Min;
00082 union
00083 {
00084 double d;
00085 int i;
00086 } Max;
00087 std::string default_string;
00088 };
00089
00090 template <class T>
00091 struct TypedParam
00092 {
00093 boost::shared_ptr<T> data;
00094 boost::shared_ptr<boost::mutex> mutex;
00095
00096 inline
00097 T operator* ()
00098 {
00099 return *data;
00100 }
00101
00102 T get()
00103 {
00104 mutex->lock();
00105 T d = *data;
00106 mutex->unlock();
00107
00108 return d;
00109 }
00110 };
00111
00112 typedef TypedParam<double> DoubleParam;
00113 typedef TypedParam<float> FloatParam;
00114 typedef TypedParam<int> IntParam;
00115 typedef TypedParam<bool> BoolParam;
00116 typedef TypedParam<std::string> StringParam;
00117
00118
00119 class DynamicParameters
00120 {
00121 ros::Publisher descr_pub_;
00122 ros::Publisher update_pub_;
00123 ros::ServiceServer set_service_;
00124 ros::NodeHandle nh_;
00125
00126 std::map<std::string, DynamicValue> values_;
00127
00128 boost::function<void(DynamicParameters&)> on_change_;
00129
00130
00131 boost::shared_ptr<boost::mutex> mutex_;
00132
00133 bool setConfigCallback(dynamic_reconfigure::Reconfigure::Request &req,
00134 dynamic_reconfigure::Reconfigure::Response &rsp)
00135 {
00136 ROS_DEBUG("Got configuration change request");
00137
00138 boost::mutex::scoped_lock lock(*mutex_);
00139
00140
00141 for (int i = 0; i < req.config.doubles.size(); i++)
00142 {
00143 dynamic_reconfigure::DoubleParameter param = req.config.doubles[i];
00144 std::map<std::string, DynamicValue>::iterator iter = values_.find(param.name);
00145 if (iter == values_.end())
00146 {
00147 ROS_ERROR("Could not find parameter '%s'", param.name.c_str());
00148 continue;
00149 }
00150
00151 if (iter->second.type != DynamicValue::Double && iter->second.type != DynamicValue::Float)
00152 {
00153 ROS_ERROR("Value '%s' was not a double type.", param.name.c_str());
00154 continue;
00155 }
00156
00157 if (iter->second.type == DynamicValue::Double)
00158 {
00159 *iter->second.dbl = param.value;
00160 }
00161
00162 if (iter->second.type == DynamicValue::Float)
00163 {
00164 *iter->second.flt = (float)param.value;
00165 }
00166 }
00167
00168 for (int i = 0; i < req.config.ints.size(); i++)
00169 {
00170 dynamic_reconfigure::IntParameter param = req.config.ints[i];
00171 std::map<std::string, DynamicValue>::iterator iter = values_.find(param.name);
00172 if (iter == values_.end())
00173 {
00174 ROS_ERROR("Could not find parameter '%s'", param.name.c_str());
00175 continue;
00176 }
00177
00178 if (iter->second.type != DynamicValue::Int)
00179 {
00180 ROS_ERROR("Value '%s' was not a int type.", param.name.c_str());
00181 continue;
00182 }
00183
00184 *iter->second.integer = param.value;
00185 }
00186
00187 for (int i = 0; i < req.config.bools.size(); i++)
00188 {
00189 dynamic_reconfigure::BoolParameter param = req.config.bools[i];
00190 std::map<std::string, DynamicValue>::iterator iter = values_.find(param.name);
00191 if (iter == values_.end())
00192 {
00193 ROS_ERROR("Could not find parameter '%s'", param.name.c_str());
00194 continue;
00195 }
00196
00197 if (iter->second.type != DynamicValue::Bool)
00198 {
00199 ROS_ERROR("Value '%s' was not a bool type.", param.name.c_str());
00200 continue;
00201 }
00202
00203 *iter->second.boolean = param.value;
00204 }
00205
00206 for (int i = 0; i < req.config.strs.size(); i++)
00207 {
00208 dynamic_reconfigure::StrParameter param = req.config.strs[i];
00209 std::map<std::string, DynamicValue>::iterator iter = values_.find(param.name);
00210 if (iter == values_.end())
00211 {
00212 ROS_ERROR("Could not find parameter '%s'", param.name.c_str());
00213 continue;
00214 }
00215
00216 if (iter->second.type != DynamicValue::String)
00217 {
00218 ROS_ERROR("Value '%s' was not a string type.", param.name.c_str());
00219 continue;
00220 }
00221
00222 *iter->second.str = param.value;
00223 }
00224
00225 updateCurrent(rsp.config);
00226
00227 if (on_change_)
00228 {
00229 on_change_(*this);
00230 }
00231
00232 return true;
00233 }
00234
00235
00236 void updateCurrent(dynamic_reconfigure::Config& config)
00237 {
00238 for (std::map<std::string, DynamicValue>::iterator value = values_.begin(); value != values_.end(); value++)
00239 {
00240 if (value->second.type == DynamicValue::Double)
00241 {
00242 dynamic_reconfigure::DoubleParameter param;
00243 param.name = value->first;
00244 param.value = *value->second.dbl;
00245 config.doubles.push_back(param);
00246 }
00247 else if (value->second.type == DynamicValue::Float)
00248 {
00249 dynamic_reconfigure::DoubleParameter param;
00250 param.name = value->first;
00251 param.value = *value->second.flt;
00252 config.doubles.push_back(param);
00253 }
00254 else if (value->second.type == DynamicValue::Int)
00255 {
00256 dynamic_reconfigure::IntParameter param;
00257 param.name = value->first;
00258 param.value = *value->second.integer;
00259 config.ints.push_back(param);
00260 }
00261 else if (value->second.type == DynamicValue::Bool)
00262 {
00263 dynamic_reconfigure::BoolParameter param;
00264 param.name = value->first;
00265 param.value = *value->second.boolean;
00266 config.bools.push_back(param);
00267 }
00268 else if (value->second.type == DynamicValue::String)
00269 {
00270 dynamic_reconfigure::StrParameter param;
00271 param.name = value->first;
00272 param.value = *value->second.str;
00273 config.strs.push_back(param);
00274 }
00275 }
00276
00277 dynamic_reconfigure::GroupState gs;
00278 gs.name = "Default";
00279 gs.state = true;
00280 gs.id = 0;
00281 gs.parent = 0;
00282 config.groups.push_back(gs);
00283 update_pub_.publish(config);
00284 }
00285
00286 public:
00287
00288 DynamicParameters() : mutex_(new boost::mutex)
00289 {
00290
00291 }
00292
00293
00294 void initialize(ros::NodeHandle& pnh)
00295 {
00296 boost::mutex::scoped_lock lock(*mutex_);
00297 nh_ = pnh;
00298
00299 descr_pub_ = nh_.advertise<dynamic_reconfigure::ConfigDescription>("parameter_descriptions", 1, true);
00300 update_pub_ = nh_.advertise<dynamic_reconfigure::Config>("parameter_updates", 1, true);
00301 }
00302
00303
00304 void finalize()
00305 {
00306 boost::mutex::scoped_lock lock(*mutex_);
00307
00308
00309 dynamic_reconfigure::ConfigDescription rdesc;
00310 dynamic_reconfigure::Group group;
00311 group.name = "Default";
00312 group.type = "";
00313 group.id = 0;
00314 group.parent = 0;
00315
00316 dynamic_reconfigure::GroupState gs;
00317 gs.name = "Default";
00318 gs.state = true;
00319 gs.id = 0;
00320 gs.parent = 0;
00321 for (std::map<std::string, DynamicValue>::iterator param = values_.begin(); param != values_.end(); param++)
00322 {
00323 std::string type;
00324 if (param->second.type == DynamicValue::Bool)
00325 {
00326 type = "bool";
00327
00328 dynamic_reconfigure::BoolParameter desc;
00329 desc.name = param->first;
00330 desc.value = true;
00331 rdesc.max.bools.push_back(desc);
00332 desc.value = false;
00333 rdesc.min.bools.push_back(desc);
00334 desc.value = param->second.Default.b;
00335 rdesc.dflt.bools.push_back(desc);
00336 }
00337 else if (param->second.type == DynamicValue::Float)
00338 {
00339 type = "double";
00340
00341 dynamic_reconfigure::DoubleParameter desc;
00342 desc.name = param->first;
00343 desc.value = param->second.Max.d;
00344 rdesc.max.doubles.push_back(desc);
00345 desc.value = param->second.Min.d;
00346 rdesc.min.doubles.push_back(desc);
00347 desc.value = param->second.Default.d;
00348 rdesc.dflt.doubles.push_back(desc);
00349 }
00350 else if (param->second.type == DynamicValue::Double)
00351 {
00352 type = "double";
00353
00354 dynamic_reconfigure::DoubleParameter desc;
00355 desc.name = param->first;
00356 desc.value = param->second.Max.d;
00357 rdesc.max.doubles.push_back(desc);
00358 desc.value = param->second.Min.d;
00359 rdesc.min.doubles.push_back(desc);
00360 desc.value = param->second.Default.d;
00361 rdesc.dflt.doubles.push_back(desc);
00362 }
00363 else if (param->second.type == DynamicValue::Int)
00364 {
00365 type = "int";
00366
00367 dynamic_reconfigure::IntParameter desc;
00368 desc.name = param->first;
00369 desc.value = param->second.Max.i;
00370 rdesc.max.ints.push_back(desc);
00371 desc.value = param->second.Min.i;
00372 rdesc.min.ints.push_back(desc);
00373 desc.value = param->second.Default.i;
00374 rdesc.dflt.ints.push_back(desc);
00375 }
00376 else if (param->second.type == DynamicValue::String)
00377 {
00378 type = "string";
00379 dynamic_reconfigure::StrParameter desc;
00380 desc.name = param->first;
00381 desc.value = "";
00382 rdesc.max.strs.push_back(desc);
00383 desc.value = "";
00384 rdesc.min.strs.push_back(desc);
00385 desc.value = param->second.default_string;
00386 rdesc.dflt.strs.push_back(desc);
00387 }
00388
00389 dynamic_reconfigure::ParamDescription desc;
00390 desc.name = param->first;
00391 desc.type = type;
00392 desc.level = 0;
00393 desc.description = param->second.description;
00394 desc.edit_method = "";
00395 group.parameters.push_back(desc);
00396 }
00397 rdesc.max.groups.push_back(gs);
00398 rdesc.min.groups.push_back(gs);
00399 rdesc.dflt.groups.push_back(gs);
00400 rdesc.groups.push_back(group);
00401 descr_pub_.publish(rdesc);
00402
00403 dynamic_reconfigure::Config config;
00404 updateCurrent(config);
00405
00406 set_service_ = nh_.advertiseService("set_parameters",
00407 &DynamicParameters::setConfigCallback, this);
00408 }
00409
00410 void setCallback(boost::function<void(DynamicParameters&)> fun)
00411 {
00412 on_change_ = fun;
00413 }
00414
00415
00416 double getDouble(const std::string& name)
00417 {
00418 std::map<std::string, DynamicValue>::iterator iter = values_.find(name);
00419 if (iter == values_.end())
00420 {
00421 ROS_ERROR("Tried to get nonexistant param %s", name.c_str());
00422 return 0.0;
00423 }
00424 if (iter->second.type != DynamicValue::Double)
00425 {
00426 ROS_ERROR("Tried to load parameter %s with the wrong type: double.", name.c_str());
00427 return 0.0;
00428 }
00429
00430 return *iter->second.dbl;
00431 }
00432
00433
00434 float getFloat(const std::string& name)
00435 {
00436 std::map<std::string, DynamicValue>::iterator iter = values_.find(name);
00437 if (iter == values_.end())
00438 {
00439 ROS_ERROR("Tried to get nonexistant param %s", name.c_str());
00440 return 0.0f;
00441 }
00442 if (iter->second.type != DynamicValue::Float)
00443 {
00444 ROS_ERROR("Tried to load parameter %s with the wrong type: float.", name.c_str());
00445 return 0.0f;
00446 }
00447
00448 return *iter->second.flt;
00449 }
00450
00451 int getInt(const std::string& name)
00452 {
00453 std::map<std::string, DynamicValue>::iterator iter = values_.find(name);
00454 if (iter == values_.end())
00455 {
00456 ROS_ERROR("Tried to get nonexistant param %s", name.c_str());
00457 return 0.0f;
00458 }
00459 if (iter->second.type != DynamicValue::Int)
00460 {
00461 ROS_ERROR("Tried to load parameter %s with the wrong type: int.", name.c_str());
00462 return 0.0f;
00463 }
00464
00465 return *iter->second.integer;
00466 }
00467
00468
00469 bool getBool(const std::string& name)
00470 {
00471 std::map<std::string, DynamicValue>::iterator iter = values_.find(name);
00472 if (iter == values_.end())
00473 {
00474 ROS_ERROR("Tried to get nonexistant param %s", name.c_str());
00475 return false;
00476 }
00477 if (iter->second.type != DynamicValue::Bool)
00478 {
00479 ROS_ERROR("Tried to load parameter %s with the wrong type: bool.", name.c_str());
00480 return false;
00481 }
00482
00483 return *iter->second.boolean;
00484 }
00485
00486
00487 std::string getString(const std::string& name)
00488 {
00489 std::map<std::string, DynamicValue>::iterator iter = values_.find(name);
00490 if (iter == values_.end())
00491 {
00492 ROS_ERROR("Tried to get nonexistant param %s", name.c_str());
00493 return "";
00494 }
00495 if (iter->second.type != DynamicValue::String)
00496 {
00497 ROS_ERROR("Tried to load parameter %s with the wrong type: string.", name.c_str());
00498 return "";
00499 }
00500
00501 return *iter->second.str;
00502 }
00503
00504
00505 inline
00506 boost::mutex& mutex()
00507 {
00508 return *mutex_;
00509 }
00510
00511 inline
00512 boost::mutex::scoped_lock lock_guard()
00513 {
00514 return boost::mutex::scoped_lock(*mutex_);
00515 }
00516
00517
00518 inline
00519 void get(const std::string &name,
00520 float &variable,
00521 const float default_value,
00522 const std::string description = "None.",
00523 const float min = -100,
00524 const float max = 100)
00525 {
00526 DynamicValue value;
00527 value.type = DynamicValue::Float;
00528 value.description = description;
00529 value.Min.d = min;
00530 value.Max.d = max;
00531 value.Default.d = default_value;
00532 value.flt = boost::shared_ptr<float>(new float);
00533 values_[name] = value;
00534
00535 std::string resolved_name = nh_.resolveName(name);
00536
00537 nh_.param(name, *value.flt, default_value);
00538 variable = *value.flt;
00539 ROS_INFO("Read dynamic parameter %s = %f", name.c_str(), variable);
00540 }
00541
00542 inline
00543 void get(const std::string &name,
00544 FloatParam &variable,
00545 const float default_value,
00546 const std::string description = "None.",
00547 const float min = -100,
00548 const float max = 100)
00549 {
00550 DynamicValue value;
00551 value.type = DynamicValue::Float;
00552 value.description = description;
00553 value.Min.d = min;
00554 value.Max.d = max;
00555 value.Default.d = default_value;
00556 value.flt = boost::shared_ptr<float>(new float);
00557 values_[name] = value;
00558
00559 variable.data = value.flt;
00560 variable.mutex = mutex_;
00561
00562 std::string resolved_name = nh_.resolveName(name);
00563
00564 nh_.param(name, *value.flt, default_value);
00565 ROS_INFO("Read dynamic parameter %s = %f", name.c_str(), *variable);
00566 }
00567
00568
00569 inline
00570 void get(const std::string &name,
00571 double &variable,
00572 const double default_value,
00573 const std::string description = "None.",
00574 const double min = -100,
00575 const double max = 100)
00576 {
00577 DynamicValue value;
00578 value.type = DynamicValue::Double;
00579 value.description = description;
00580 value.Min.d = min;
00581 value.Max.d = max;
00582 value.Default.d = default_value;
00583 value.dbl = boost::shared_ptr<double>(new double);
00584 values_[name] = value;
00585
00586 std::string resolved_name = nh_.resolveName(name);
00587
00588 nh_.param(name, *value.dbl, default_value);
00589 variable = *value.dbl;
00590 ROS_INFO("Read dynamic parameter %s = %lf", name.c_str(), variable);
00591 }
00592
00593 inline
00594 void get(const std::string &name,
00595 DoubleParam &variable,
00596 const double default_value,
00597 const std::string description = "None.",
00598 const double min = -100,
00599 const double max = 100)
00600 {
00601 DynamicValue value;
00602 value.type = DynamicValue::Double;
00603 value.description = description;
00604 value.Min.d = min;
00605 value.Max.d = max;
00606 value.Default.d = default_value;
00607 value.dbl = boost::shared_ptr<double>(new double);
00608 values_[name] = value;
00609
00610 variable.data = value.dbl;
00611 variable.mutex = mutex_;
00612
00613 std::string resolved_name = nh_.resolveName(name);
00614
00615 nh_.param(name, *value.dbl, default_value);
00616 ROS_INFO("Read dynamic parameter %s = %lf", name.c_str(), *variable);
00617 }
00618
00619 inline
00620 void get(const std::string &name,
00621 int &variable,
00622 const int default_value,
00623 const std::string description = "None.",
00624 const int min = -100,
00625 const int max = 100)
00626 {
00627 DynamicValue value;
00628 value.type = DynamicValue::Int;
00629 value.description = description;
00630 value.Min.i = min;
00631 value.Max.i = max;
00632 value.Default.i = default_value;
00633 value.integer = boost::shared_ptr<int>(new int);
00634 values_[name] = value;
00635
00636 std::string resolved_name = nh_.resolveName(name);
00637
00638 nh_.param(name, *value.integer, default_value);
00639 variable = *value.integer;
00640 ROS_INFO("Read dynamic parameter %s = %i", name.c_str(), variable);
00641 }
00642
00643 inline
00644 void get(const std::string &name,
00645 IntParam &variable,
00646 const int default_value,
00647 const std::string description = "None.",
00648 const int min = -100,
00649 const int max = 100)
00650 {
00651 DynamicValue value;
00652 value.type = DynamicValue::Int;
00653 value.description = description;
00654 value.Min.i = min;
00655 value.Max.i = max;
00656 value.Default.i = default_value;
00657 value.integer = boost::shared_ptr<int>(new int);
00658 values_[name] = value;
00659
00660 variable.data = value.integer;
00661 variable.mutex = mutex_;
00662
00663 std::string resolved_name = nh_.resolveName(name);
00664
00665 nh_.param(name, *value.integer, default_value);
00666 ROS_INFO("Read dynamic parameter %s = %i", name.c_str(), *variable);
00667 }
00668
00669
00670 inline
00671 void get(const std::string &name,
00672 bool &variable,
00673 const bool default_value,
00674 const std::string description = "None.")
00675 {
00676 DynamicValue value;
00677 value.type = DynamicValue::Bool;
00678 value.description = description;
00679 value.Default.b = default_value;
00680 value.boolean = boost::shared_ptr<bool>(new bool);
00681 values_[name] = value;
00682
00683 std::string resolved_name = nh_.resolveName(name);
00684
00685 nh_.param(name, *value.boolean, default_value);
00686 variable = *value.boolean;
00687 ROS_INFO("Read dynamic parameter %s = %s", name.c_str(), variable ? "true" : "false");
00688 }
00689
00690 inline
00691 void get(const std::string &name,
00692 BoolParam &variable,
00693 const bool default_value,
00694 const std::string description = "None.")
00695 {
00696 DynamicValue value;
00697 value.type = DynamicValue::Bool;
00698 value.description = description;
00699 value.Default.b = default_value;
00700 value.boolean = boost::shared_ptr<bool>(new bool);
00701 values_[name] = value;
00702
00703 variable.data = value.boolean;
00704 variable.mutex = mutex_;
00705
00706 std::string resolved_name = nh_.resolveName(name);
00707
00708 nh_.param(name, *value.boolean, default_value);
00709 ROS_INFO("Read dynamic parameter %s = %s", name.c_str(), *variable ? "true" : "false");
00710 }
00711
00712
00713 inline
00714 void get(const std::string &name,
00715 std::string &variable,
00716 const std::string default_value,
00717 const std::string description = "None.")
00718 {
00719 DynamicValue value;
00720 value.type = DynamicValue::Bool;
00721 value.description = description;
00722 value.default_string = default_value;
00723 value.str = boost::shared_ptr<std::string>(new std::string());
00724 values_[name] = value;
00725
00726 std::string resolved_name = nh_.resolveName(name);
00727
00728 nh_.param(name, *value.str, default_value);
00729 variable = *value.str;
00730 ROS_INFO("Read dynamic parameter %s = %s", name.c_str(), variable.c_str());
00731 }
00732
00733 inline
00734 void get(const std::string &name,
00735 StringParam &variable,
00736 const std::string default_value,
00737 const std::string description = "None.")
00738 {
00739 DynamicValue value;
00740 value.type = DynamicValue::Bool;
00741 value.description = description;
00742 value.default_string = default_value;
00743 value.str = boost::shared_ptr<std::string>(new std::string());
00744 values_[name] = value;
00745
00746 variable.data = value.str;
00747 variable.mutex = mutex_;
00748
00749 std::string resolved_name = nh_.resolveName(name);
00750
00751 nh_.param(name, *value.str, default_value);
00752 ROS_INFO("Read dynamic parameter %s = %s", name.c_str(), (*variable).c_str());
00753 }
00754 };
00755 }
00756 #endif // SWRI_ROSCPP_DYNAMIC_PARAMETERS_H_