$search
00001 #include <rtt/RTT.hpp> 00002 #include <rtt/plugin/ServicePlugin.hpp> 00003 #include <rtt/marsh/PropertyBagIntrospector.hpp> 00004 00005 #include <ros/ros.h> 00006 #include <stack> 00007 00008 using namespace RTT; 00009 using namespace std; 00010 00011 class RosParam: public RTT::Service 00012 { 00013 public: 00014 RosParam(TaskContext* owner) : 00015 Service("rosparam", owner) 00016 { 00017 addOperation("storeProperties", &RosParam::storeProperties, this) .doc( 00018 "Stores all properties of this component to the ros param server"); 00019 addOperation("refreshProperties", &RosParam::refreshProperties, this).doc( 00020 "Refreshes all properties of this component from the ros param server"); 00021 addOperation("storeProperty", &RosParam::storeProperty, this) .doc( 00022 "Stores one property of this component to the ros param server").arg( 00023 "param_name", "Name of the property.").arg("private", 00024 "true if parameter should be put in private namespace").arg( 00025 "relative", 00026 "true if parameter should be put in the relative (component name) namespace"); 00027 addOperation("refreshProperty", &RosParam::refreshProperty, this) .doc( 00028 "Refreshes one property of this component from the ros param server").arg( 00029 "param_name", "Name of the property.").arg("private", 00030 "true if parameter should be found the private namespace").arg( 00031 "relative", 00032 "true if parameter should be found in the relative (component name) namespace"); 00033 this->doc("Store component properties on the ROS parameter server or refresh them using values on the ROS parameter server"); 00034 } 00035 private: 00036 00037 std::stack<XmlRpc::XmlRpcValue> value_stack; 00038 00039 bool storeProperties() 00040 { 00041 Property<PropertyBag> bag(getOwner()->getName(), ""); 00042 // decompose prop into primitive property types. 00043 marsh::PropertyBagIntrospector pbi(bag.value()); 00044 pbi.introspect(*this->getOwner()->properties()); 00045 if (PropertyToXmlRpcValue(&bag)) 00046 { 00047 bool retval = true; 00048 assert(!value_stack.empty()); 00049 try 00050 { 00051 ros::param::set(string("~") + bag.getName(), value_stack.top()); 00052 } catch (ros::InvalidNameException ex) 00053 { 00054 log(Error) << ex.what() << endlog(); 00055 retval = false; 00056 } 00057 value_stack.pop(); 00058 assert(value_stack.empty()); 00059 return retval; 00060 } 00061 return false; 00062 } 00063 bool storeProperty(const string& prop_name, bool priv, bool rel) 00064 { 00065 base::PropertyBase* base = this->getOwner()->properties()->getProperty( 00066 prop_name); 00067 if (base == NULL) 00068 { 00069 log(Error) << this->getOwner()->getName() 00070 << " does not have a Property with name " << prop_name 00071 << endlog(); 00072 return false; 00073 } 00074 string param_name; 00075 if (priv) 00076 param_name = "~"; 00077 if (rel) 00078 param_name += this->getOwner()->getName() + string("/"); 00079 param_name += base->getName(); 00080 if (PropertyToXmlRpcValue(base)) 00081 { 00082 bool retval = true; 00083 assert(!value_stack.empty()); 00084 try 00085 { 00086 ros::param::set(param_name, value_stack.top()); 00087 } catch (ros::InvalidNameException ex) 00088 { 00089 log(Error) << ex.what() << endlog(); 00090 retval = false; 00091 } 00092 value_stack.pop(); 00093 assert(value_stack.empty()); 00094 return retval; 00095 00096 } 00097 else 00098 { 00099 //check if base can be decomposed into a PropertyBag, if so we need to decompose it. 00100 PropertyBag bag; 00101 bag.add(base); 00102 // decompose prop into primitive property types. 00103 PropertyBag decomposed_bag; 00104 marsh::PropertyBagIntrospector pbi(decomposed_bag); 00105 pbi.introspect(bag); 00106 if (PropertyToXmlRpcValue(decomposed_bag.getProperty( 00107 base->getName()))) 00108 { 00109 bool retval = true; 00110 assert(!value_stack.empty()); 00111 try 00112 { 00113 ros::param::set(param_name, value_stack.top()); 00114 } catch (ros::InvalidNameException ex) 00115 { 00116 log(Error) << ex.what() << endlog(); 00117 retval = false; 00118 } 00119 value_stack.pop(); 00120 assert(value_stack.empty()); 00121 return retval; 00122 } 00123 return false; 00124 } 00125 return false; 00126 } 00127 00128 bool PropertyToXmlRpcValue(base::PropertyBase* prop) 00129 { 00130 return PropertyToXmlRpcValue<bool> ( 00131 dynamic_cast<Property<bool>*> (prop)) || PropertyToXmlRpcValue< 00132 int> (dynamic_cast<Property<int>*> (prop)) 00133 || PropertyToXmlRpcValue<double> ( 00134 dynamic_cast<Property<double>*> (prop)) 00135 || PropertyToXmlRpcValue<string> (dynamic_cast<Property< 00136 std::string>*> (prop)) || PropertyToXmlRpcValue( 00137 dynamic_cast<Property<PropertyBag>*> (prop)); 00138 } 00139 00140 template<class T> 00141 bool PropertyToXmlRpcValue(Property<T>* prop) 00142 { 00143 if (!prop) 00144 return false; 00145 00146 value_stack.push(XmlRpc::XmlRpcValue(prop->rvalue())); 00147 return true; 00148 } 00149 00150 bool PropertyToXmlRpcValue(Property<PropertyBag>* prop) 00151 { 00152 if (!prop) 00153 return false; 00154 PropertyBag& bag = prop->value(); 00155 XmlRpc::XmlRpcValue dict; 00156 for (size_t i = 0; i < bag.size(); i++) 00157 { 00158 if (PropertyToXmlRpcValue(bag.getItem(i))) 00159 { 00160 if (!bag.getItem(i)->getName().empty() && bag.getType() 00161 != "array") 00162 dict[bag.getItem(i)->getName()] = value_stack.top(); 00163 else 00164 dict[i] = value_stack.top(); 00165 value_stack.pop(); 00166 } 00167 } 00168 if (bag.size() == 0) 00169 log(Warning) << "Exporting empty property bag " << prop->getName() 00170 << endlog(); 00171 value_stack.push(dict); 00172 return true; 00173 } 00174 00175 bool refreshProperties() 00176 { 00177 XmlRpc::XmlRpcValue rpcval; 00178 try 00179 { 00180 if (!ros::param::get(string("~") + this->getOwner()->getName(), 00181 rpcval)) 00182 { 00183 log(Error) 00184 << "The parameter server does not have a Property with name " 00185 << this->getOwner()->getName() << endlog(); 00186 return false; 00187 } 00188 } catch (ros::InvalidNameException ex) 00189 { 00190 log(Error) << ex.what() << endlog(); 00191 return false; 00192 } 00193 Property<PropertyBag> bag(getOwner()->getName(), ""); 00194 // decompose prop into primitive property types. 00195 marsh::PropertyBagIntrospector pbi(bag.value()); 00196 pbi.introspect(*this->getOwner()->properties()); 00197 for (PropertyBag::iterator it = bag.value().begin(); it 00198 != bag.value().end(); ++it) 00199 { 00200 if (rpcval.hasMember((*it)->getName())) 00201 { 00202 if (!XmlRpcValueToProperty(rpcval[(*it)->getName()], (*it))) 00203 log(Warning) << "Could not update Property " 00204 << (*it)->getName() << endlog(); 00205 base::PropertyBase* base = 00206 this->getOwner()->properties()->getProperty( 00207 (*it)->getName()); 00208 if (!base->getTypeInfo()->composeType((*it)->getDataSource(), 00209 base->getDataSource())) 00210 log(Warning)<<"Could not compose "<<base->getName()<<endlog(); 00211 } 00212 else 00213 log(Warning) << "Could not find Property " << (*it)->getName() 00214 << endlog(); 00215 } 00216 return true; 00217 } 00218 00219 bool refreshProperty(const string& prop_name, bool priv, bool rel) 00220 { 00221 base::PropertyBase* base = this->getOwner()->properties()->getProperty( 00222 prop_name); 00223 if (base == NULL) 00224 { 00225 log(Error) << this->getOwner()->getName() 00226 << " does not have a Property with name " << prop_name 00227 << endlog(); 00228 return false; 00229 } 00230 string param_name; 00231 if (priv) 00232 param_name = "~"; 00233 if (rel) 00234 param_name += this->getOwner()->getName() + string("/"); 00235 param_name += base->getName(); 00236 XmlRpc::XmlRpcValue rpcval; 00237 try 00238 { 00239 if (!ros::param::get(param_name, rpcval)) 00240 { 00241 log(Error) 00242 << "The parameter server does not have a Property with name " 00243 << param_name << endlog(); 00244 return false; 00245 } 00246 } catch (ros::InvalidNameException ex) 00247 { 00248 log(Error) << ex.what() << endlog(); 00249 return false; 00250 } 00251 PropertyBag bag; 00252 bag.add(base); 00253 // decompose prop into primitive property types. 00254 PropertyBag decomposed_bag; 00255 marsh::PropertyBagIntrospector pbi(decomposed_bag); 00256 pbi.introspect(bag); 00257 if (!XmlRpcValueToProperty(rpcval, decomposed_bag.getProperty( 00258 base->getName()))) 00259 return false; 00260 if (base->getTypeInfo()->composeType(decomposed_bag.getProperty( 00261 base->getName())->getDataSource(), base->getDataSource())) 00262 return true; 00263 return false; 00264 } 00265 00266 bool XmlRpcValueToProperty(XmlRpc::XmlRpcValue &val, 00267 base::PropertyBase* prop) 00268 { 00269 switch (val.getType()) 00270 { 00271 case XmlRpc::XmlRpcValue::TypeBoolean: 00272 { 00273 Property<bool> tmp(""); 00274 tmp.set(val); 00275 if (prop->refresh(&tmp)) 00276 return true; 00277 return false; 00278 } 00279 case XmlRpc::XmlRpcValue::TypeDouble: 00280 { 00281 Property<double> tmp(""); 00282 tmp.set(val); 00283 if (prop->refresh(&tmp)) 00284 return true; 00285 return false; 00286 } 00287 case XmlRpc::XmlRpcValue::TypeInt: 00288 { 00289 Property<int> tmp(""); 00290 tmp.set(val); 00291 if (prop->refresh(&tmp)) 00292 return true; 00293 return false; 00294 } 00295 case XmlRpc::XmlRpcValue::TypeString: 00296 { 00297 Property<std::string> tmp(""); 00298 tmp.set(val); 00299 if (prop->refresh(&tmp)) 00300 return true; 00301 return false; 00302 } 00303 case XmlRpc::XmlRpcValue::TypeArray: 00304 { 00305 Property<PropertyBag> bag(""); 00306 bag = prop; 00307 if (!bag.ready()) 00308 return false; 00309 if (val.size() != (int) bag.value().size()) 00310 return false; 00311 for (int i = 0; i < val.size(); i++) 00312 { 00313 if (!XmlRpcValueToProperty(val[i], bag.value().getItem(i))) 00314 return false; 00315 } 00316 //is this necessary? 00317 if (prop->getTypeInfo()->composeType(bag.getDataSource(), 00318 prop->getDataSource())) 00319 return true; 00320 return false; 00321 } 00322 case XmlRpc::XmlRpcValue::TypeStruct: 00323 { 00324 Property<PropertyBag> bag(""); 00325 bag = prop; 00326 if (!bag.ready()) 00327 return false; 00328 if (bag.value().empty()) 00329 { 00330 log(Warning) << "Could not update " << prop->getName() 00331 << endlog(); 00332 return false; 00333 } 00334 for (PropertyBag::iterator it = bag.value().begin(); it 00335 != bag.value().end(); ++it) 00336 { 00337 if (val.hasMember((*it)->getName())) 00338 { 00339 if (!XmlRpcValueToProperty(val[(*it)->getName()], 00340 bag.value().getProperty((*it)->getName()))) 00341 log(Warning) << "Could not convert " 00342 << (*it)->getName() << " from XmlRpcValue" 00343 << endlog(); 00344 } 00345 else 00346 log(Warning) << "Could not find " << (*it)->getName() 00347 << " in " << prop->getName() << endlog(); 00348 } 00349 //is this necessary? 00350 if (prop->getTypeInfo()->composeType(bag.getDataSource(), 00351 prop->getDataSource())) 00352 return true; 00353 return false; 00354 } 00355 default: 00356 { 00357 log(Warning) << "Cannot handle the type of " << prop->getName() 00358 << endlog(); 00359 return false; 00360 } 00361 } 00362 } 00363 00364 }; 00365 00366 00367 ORO_SERVICE_NAMED_PLUGIN(RosParam, "rosparam")