00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <cob_omni_drive_controller/UndercarriageCtrlGeomROS.h>
00019 #include <urdf/model.h>
00020 #include <angles/angles.h>
00021 #include <XmlRpcException.h>
00022
00023 #include <tf2/LinearMath/Quaternion.h>
00024 #include <tf2/LinearMath/Transform.h>
00025 #include <tf2/LinearMath/Vector3.h>
00026
00027 class MergedXmlRpcStruct : public XmlRpc::XmlRpcValue{
00028 MergedXmlRpcStruct(const XmlRpc::XmlRpcValue& a) :XmlRpc::XmlRpcValue(a){ assertStruct(); }
00029 public:
00030 MergedXmlRpcStruct(){ assertStruct(); }
00031 MergedXmlRpcStruct(const XmlRpc::XmlRpcValue& a, const MergedXmlRpcStruct &b, bool recursive= true) :XmlRpc::XmlRpcValue(a){
00032 assertStruct();
00033
00034 for(ValueStruct::const_iterator it = b._value.asStruct->begin(); it != b._value.asStruct->end(); ++it){
00035 std::pair<XmlRpc::XmlRpcValue::iterator,bool> res = _value.asStruct->insert(*it);
00036
00037 if(recursive && !res.second && res.first->second.getType() == XmlRpc::XmlRpcValue::TypeStruct && it->second.getType() == XmlRpc::XmlRpcValue::TypeStruct){
00038 res.first->second = MergedXmlRpcStruct(res.first->second, it->second);
00039 }
00040 }
00041
00042
00043 }
00044 };
00045
00046 template<typename T> T read_typed(XmlRpc::XmlRpcValue &val){
00047 return val;
00048 }
00049 template<> double read_typed(XmlRpc::XmlRpcValue &val){
00050 if(val.getType() == XmlRpc::XmlRpcValue::TypeInt) return read_typed<int>(val);
00051 return val;
00052 }
00053
00054 template<typename T> bool read_optional(T& val, const std::string &name, XmlRpc::XmlRpcValue &wheel){
00055 try{
00056 if(wheel.hasMember(name)){
00057 val = read_typed<T>(wheel[name]);
00058 return true;
00059 }
00060 }catch(XmlRpc::XmlRpcException &e){
00061 ROS_ERROR_STREAM("Could not access '" << name << "', reason: " << e.getMessage());
00062 }
00063 return false;
00064 }
00065
00066 template<typename T> bool read_with_default(T& val, const std::string &name, XmlRpc::XmlRpcValue &wheel, const T& def){
00067 if(!read_optional(val, name, wheel)){
00068 val = def;
00069 return false;
00070 }
00071 return true;
00072 }
00073
00074 template<typename T> bool read(T& val, const std::string &name, XmlRpc::XmlRpcValue &wheel){
00075 if(!read_optional(val, name, wheel)){
00076 ROS_ERROR_STREAM("Parameter not found: " << name);
00077 return false;
00078 }
00079 return true;
00080 }
00081
00082 bool parseWheelTransform(const std::string& joint_name, const std::string& parent_link_name,
00083 tf2::Transform &transform, urdf::Model* model)
00084 {
00085 urdf::Pose transform_pose;
00086 if(model)
00087 {
00088 urdf::JointConstSharedPtr joint(model->getJoint(joint_name));
00089 if (!joint)
00090 {
00091 ROS_ERROR_STREAM(joint_name
00092 << " couldn't be retrieved from model description");
00093 return false;
00094 }
00095
00096 transform_pose.position = joint->parent_to_joint_origin_transform.position;
00097 transform_pose.rotation = joint->parent_to_joint_origin_transform.rotation;
00098 while(joint->parent_link_name != parent_link_name)
00099 {
00100 urdf::LinkConstSharedPtr link_parent(model->getLink(joint->parent_link_name));
00101 if (!link_parent || !link_parent->parent_joint)
00102 {
00103 ROS_ERROR_STREAM(joint->parent_link_name
00104 << " couldn't be retrieved from model description or his parent joint");
00105 return false;
00106 }
00107 joint = link_parent->parent_joint;
00108 transform_pose.position = transform_pose.position + joint->parent_to_joint_origin_transform.position;
00109 transform_pose.rotation = transform_pose.rotation * joint->parent_to_joint_origin_transform.rotation;
00110 }
00111
00112 tf2::Transform rot(tf2::Quaternion(transform_pose.rotation.x,transform_pose.rotation.y,transform_pose.rotation.z,transform_pose.rotation.w),
00113 tf2::Vector3(0,0,0));
00114
00115 tf2::Transform trans; trans.setIdentity();
00116 trans.setOrigin(tf2::Vector3(transform_pose.position.x,transform_pose.position.y,transform_pose.position.z));
00117
00118 transform.setIdentity();
00119 transform = rot * trans;
00120 return true;
00121 }
00122 else
00123 return false;
00124 }
00125
00126 bool parseCtrlParams(CtrlParams & params, XmlRpc::XmlRpcValue &wheel, urdf::Model* model){
00127 double deg;
00128 read_with_default(deg, "steer_neutral_position", wheel, 0.0);
00129 params.dWheelNeutralPos = angles::from_degrees(deg);
00130
00131 std::string steer_name, drive_name;
00132 double max_steer_rate, max_drive_rate;
00133 read_with_default(steer_name, "steer", wheel, std::string());
00134 read_with_default(drive_name, "drive", wheel, std::string());
00135
00136 boost::shared_ptr<const urdf::Joint> steer_joint;
00137 if(model && !steer_name.empty()){
00138 steer_joint = model->getJoint(steer_name);
00139 if(steer_joint){
00140 params.dMaxSteerRateRadpS = steer_joint->limits->velocity;
00141 }
00142 }
00143 if(!read_optional(params.dMaxSteerRateRadpS, "max_steer_rate", wheel) && !steer_joint){
00144 ROS_WARN_STREAM("max_steer_rate not set - defaulting to 0.0");
00145 params.dMaxSteerRateRadpS = 0.0;
00146 }
00147 boost::shared_ptr<const urdf::Joint> drive_joint;
00148 if(model && !drive_name.empty()){
00149 drive_joint = model->getJoint(drive_name);
00150 if(drive_joint){
00151 params.dMaxDriveRateRadpS = drive_joint->limits->velocity;
00152 }
00153 }
00154 if(!read_optional(params.dMaxDriveRateRadpS, "max_drive_rate", wheel) && !drive_joint){
00155 ROS_WARN_STREAM("max_drive_rate not set - defaulting to 0.0");
00156 params.dMaxDriveRateRadpS = 0.0;
00157 }
00158
00159 ROS_WARN_STREAM("max_steer_rate: " << params.dMaxSteerRateRadpS);
00160 ROS_WARN_STREAM("max_drive_rate: " << params.dMaxDriveRateRadpS);
00161
00162 return true;
00163 }
00164
00165 bool parsePosCtrlParams(PosCtrlParams & params, XmlRpc::XmlRpcValue &wheel){
00166 if(!wheel.hasMember("steer_ctrl")){
00167 ROS_ERROR_STREAM("steer_ctrl not found");
00168 return false;
00169 }
00170 XmlRpc::XmlRpcValue &steer = wheel["steer_ctrl"];
00171
00172 return read(params.dSpring, "spring", steer)
00173 && read(params.dDamp, "damp", steer)
00174 && read(params.dVirtM, "virt_mass", steer)
00175 && read(params.dDPhiMax, "d_phi_max", steer)
00176 && read(params.dDDPhiMax, "dd_phi_max", steer);
00177 }
00178
00179 bool parseWheelGeom(WheelGeom & geom, XmlRpc::XmlRpcValue &wheel, MergedXmlRpcStruct &merged, urdf::Model* model){
00180
00181 read_with_default(geom.steer_name, "steer", wheel, std::string());
00182 read_with_default(geom.drive_name, "drive", wheel, std::string());
00183 read_with_default(geom.dSteerDriveCoupling, "steer_drive_coupling", wheel, 0.0);
00184
00185 boost::shared_ptr<const urdf::Joint> steer_joint;
00186 urdf::Vector3 steer_pos;
00187
00188 if(model && !geom.steer_name.empty()){
00189 steer_joint = model->getJoint(geom.steer_name);
00190 if(steer_joint){
00191 tf2::Transform transform;
00192 if(parseWheelTransform(geom.steer_name, model->getRoot()->name, transform, model)){
00193 steer_pos.x = transform.getOrigin().getX();
00194 steer_pos.y = transform.getOrigin().getY();
00195 steer_pos.z = transform.getOrigin().getZ();
00196 }
00197 }
00198 }
00199
00200 if(!read_optional(steer_pos.x, "x_pos", wheel) && !steer_joint){
00201 ROS_ERROR_STREAM("Could not parse x_pos");
00202 return false;
00203 }
00204
00205 if(!read_optional(steer_pos.y, "y_pos", wheel) && !steer_joint){
00206 ROS_ERROR_STREAM("Could not parse y_pos");
00207 return false;
00208 }
00209
00210 if(!read_optional(steer_pos.z, "wheel_radius", merged) && !steer_joint){
00211 ROS_ERROR_STREAM("Could not parse wheel_radius");
00212 return false;
00213 }
00214
00215 if(steer_pos.z == 0){
00216 ROS_ERROR_STREAM("wheel_radius must be non-zero");
00217 return false;
00218 }
00219
00220 ROS_DEBUG_STREAM(geom.steer_name<<" steer_pos \tx:"<<steer_pos.x<<" \ty:"<<steer_pos.y<<" \tz:"<<steer_pos.z);
00221
00222 geom.dWheelXPosMM = steer_pos.x * 1000;
00223 geom.dWheelYPosMM = steer_pos.y * 1000;
00224 geom.dRadiusWheelMM = fabs(steer_pos.z * 1000);
00225
00226 double offset = 0;
00227
00228 if(!read_optional(offset, "wheel_offset", merged)){
00229 boost::shared_ptr<const urdf::Joint> drive_joint;
00230 if(model && !geom.drive_name.empty()){
00231 drive_joint = model->getJoint(geom.drive_name);
00232 }
00233 if(drive_joint){
00234 const urdf::Vector3& pos = drive_joint->parent_to_joint_origin_transform.position;
00235 offset = sqrt(pos.x*pos.x + pos.y * pos.y);
00236 }else{
00237 ROS_ERROR_STREAM("Could not parse wheel_offset");
00238 return false;
00239 }
00240 }
00241 geom.dDistSteerAxisToDriveWheelMM = offset * 1000;
00242 return true;
00243 }
00244
00245 template<typename W> bool parseWheel(W & params, XmlRpc::XmlRpcValue &wheel, MergedXmlRpcStruct &merged, urdf::Model* model);
00246
00247 template<> bool parseWheel(UndercarriageGeom::WheelParams & params, XmlRpc::XmlRpcValue &wheel, MergedXmlRpcStruct &merged, urdf::Model* model){
00248 return parseWheelGeom(params.geom, wheel, merged, model);
00249 }
00250
00251 template<> bool parseWheel(UndercarriageDirectCtrl::WheelParams & params, XmlRpc::XmlRpcValue &wheel, MergedXmlRpcStruct &merged, urdf::Model* model){
00252 return parseWheelGeom(params.geom, wheel, merged, model) && parseCtrlParams(params.ctrl, merged, model);
00253 }
00254
00255 template<> bool parseWheel(UndercarriageCtrl::WheelParams & params, XmlRpc::XmlRpcValue &wheel, MergedXmlRpcStruct &merged, urdf::Model* model){
00256 return parseWheelGeom(params.geom, wheel, merged, model) && parseCtrlParams(params.ctrl, merged, model) && parsePosCtrlParams(params.pos_ctrl, merged);
00257 }
00258
00259 bool make_wheel_struct(XmlRpc::XmlRpcValue &wheel_list){
00260 if(wheel_list.getType() == XmlRpc::XmlRpcValue::TypeArray){
00261 XmlRpc::XmlRpcValue new_stuct;
00262 for(size_t i = 0; i < wheel_list.size(); ++i){
00263 new_stuct[boost::lexical_cast<std::string>(i)] = wheel_list[i];
00264 }
00265 wheel_list = new_stuct;
00266 }else if(wheel_list.getType() != XmlRpc::XmlRpcValue::TypeStruct){
00267 return false;
00268 }
00269
00270 return wheel_list.size() > 0;
00271 }
00272
00273 template<typename W> bool parseWheels(std::vector<W> &wheel_params, const ros::NodeHandle &nh, bool read_urdf){
00274
00275 urdf::Model model;
00276
00277 std::string description_name;
00278 bool has_model = read_urdf && nh.searchParam("robot_description", description_name) && model.initParam(description_name);
00279
00280 MergedXmlRpcStruct defaults;
00281 nh.getParam("defaults", defaults);
00282
00283
00284 wheel_params.clear();
00285
00286 XmlRpc::XmlRpcValue wheel_list;
00287 if (!nh.getParam("wheels", wheel_list)){
00288 ROS_ERROR("List of wheels not found");
00289 return false;
00290 }
00291
00292 if (!make_wheel_struct(wheel_list)){
00293 ROS_ERROR("List of wheels is invalid");
00294 return false;
00295 }
00296
00297 for(XmlRpc::XmlRpcValue::iterator it = wheel_list.begin(); it != wheel_list.end(); ++it){
00298
00299 W params;
00300 MergedXmlRpcStruct merged(it->second, defaults);
00301
00302 if(!parseWheel(params, it->second, merged, has_model?&model:0)){
00303 return false;
00304 }
00305
00306 wheel_params.push_back(params);
00307 }
00308 return !wheel_params.empty();
00309 }
00310
00311 namespace cob_omni_drive_controller{
00312
00313 bool parseWheelParams(std::vector<UndercarriageGeom::WheelParams> ¶ms, const ros::NodeHandle &nh, bool read_urdf ){
00314 return parseWheels(params, nh, read_urdf);
00315 }
00316 bool parseWheelParams(std::vector<UndercarriageDirectCtrl::WheelParams> ¶ms, const ros::NodeHandle &nh, bool read_urdf ){
00317 return parseWheels(params, nh, read_urdf);
00318 }
00319 bool parseWheelParams(std::vector<UndercarriageCtrl::WheelParams> ¶ms, const ros::NodeHandle &nh, bool read_urdf ){
00320 return parseWheels(params, nh, read_urdf);
00321 }
00322
00323
00324 }