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
00027
00028 #include <cassert>
00029 #include <boost/foreach.hpp>
00030
00031 #include <gazebo/sensors/SensorManager.hh>
00032
00033 #include <urdf_parser/urdf_parser.h>
00034 #include <pluginlib/class_list_macros.h>
00035 #include <angles/angles.h>
00036 #include <Eigen/Core>
00037 #include <Eigen/Geometry>
00038
00039 #include <joint_limits_interface/joint_limits_urdf.h>
00040 #include <transmission_interface/transmission_interface_loader.h>
00041
00042 #include <pal_hardware_gazebo/pal_hardware_gazebo.h>
00043
00044 typedef Eigen::Vector3d eVector3;
00045 typedef Eigen::Isometry3d eMatrixHom;
00046 typedef Eigen::Matrix3d eMatrixRot;
00047 typedef Eigen::Quaternion<double> eQuaternion;
00048
00049 using std::vector;
00050 using std::string;
00051
00052 namespace xh
00053 {
00054
00055 class XmlrpcHelperException : public ros::Exception
00056 {
00057 public:
00058 XmlrpcHelperException(const std::string& what)
00059 : ros::Exception(what) {}
00060 };
00061
00062 typedef XmlRpc::XmlRpcValue Struct;
00063 typedef XmlRpc::XmlRpcValue Array;
00064
00065 template <class T>
00066 void fetchParam(ros::NodeHandle nh, const std::string& param_name, T& output)
00067 {
00068 XmlRpc::XmlRpcValue val;
00069 bool ok = false;
00070 try
00071 {
00072 ok = nh.getParam(param_name, val);
00073 }
00074 catch(const ros::InvalidNameException& e) {}
00075
00076 if (!ok)
00077 {
00078 std::ostringstream err_msg;
00079 err_msg << "could not load parameter '" << param_name << "'. (namespace: "
00080 << nh.getNamespace() << ")";
00081 throw XmlrpcHelperException(err_msg.str());
00082 }
00083
00084 output = static_cast<T>(val);
00085 }
00086
00087 }
00088
00089 inline std::vector<std::string> getIds(const ros::NodeHandle &nh, const std::string& key)
00090 {
00091 using std::vector;
00092 using std::string;
00093
00094 xh::Struct xh_st;
00095 try {xh::fetchParam(nh, key, xh_st);}
00096 catch (const xh::XmlrpcHelperException&)
00097 {
00098 ROS_DEBUG_STREAM("Requested data found in the parameter server (namespace " <<
00099 nh.getNamespace() + "/" + key << ").");
00100 return vector<string>();
00101 }
00102
00103 vector<string> out;
00104 for (xh::Struct::iterator it = xh_st.begin(); it != xh_st.end(); ++it)
00105 {
00106 out.push_back(it->first);
00107 }
00108 return out;
00109 }
00110
00111
00112 void convert(const urdf::Vector3 &in, eVector3 &out){
00113 out = eVector3(in.x, in.y, in.z);
00114 }
00115
00116 void convert(const urdf::Rotation &in, eMatrixRot &out){
00117 out = eQuaternion(in.w, in.x, in.y, in.z);
00118 }
00119
00120 inline eMatrixHom createMatrix( eMatrixRot const& rot, eVector3 const& trans)
00121 {
00122 eMatrixHom temp;
00123 temp.setIdentity();
00124 temp = (rot);
00125 temp.translation() = trans;
00126 return temp;
00127 }
00128
00129 void convert(const urdf::Pose &in, eMatrixHom &out){
00130 eVector3 r;
00131 convert(in.position, r);
00132 eMatrixRot E;
00133 convert(in.rotation, E);
00134 out = createMatrix(E, r);
00135 }
00136
00137 template<typename T>
00138 Eigen::Matrix<T, 3, 3> skew(const Eigen::Matrix<T, 3, 1>& vec)
00139 {
00140 return (Eigen::Matrix<T, 3, 3>() << T(0), -vec(2), vec(1),
00141 vec(2), T(0), -vec(0),
00142 -vec(1), vec(0), T(0)).finished();
00143 }
00144
00145
00146 namespace gazebo_ros_control
00147 {
00148
00149 using namespace hardware_interface;
00150
00151 bool PalHardwareGazebo::parseForceTorqueSensors(ros::NodeHandle &nh,
00152 gazebo::physics::ModelPtr model,
00153 const urdf::Model* const urdf_model){
00154 using std::vector;
00155 using std::string;
00156
00157 const string ft_ns = "force_torque";
00158 vector<string> ft_ids = getIds(nh, ft_ns);
00159 ros::NodeHandle ft_nh(nh, ft_ns);
00160 typedef vector<string>::const_iterator Iterator;
00161 for (Iterator it = ft_ids.begin(); it != ft_ids.end(); ++it){
00162 std::string sensor_name = *it;
00163 std::string sensor_joint_name;
00164 std::string sensor_frame_id;
00165 ros::NodeHandle ft_sensor_nh(ft_nh, sensor_name);
00166 xh::fetchParam(ft_sensor_nh, "frame", sensor_frame_id);
00167 xh::fetchParam(ft_sensor_nh, "sensor_joint", sensor_joint_name);
00168
00169 ForceTorqueSensorDefinitionPtr ft(new ForceTorqueSensorDefinition(sensor_name,
00170 sensor_joint_name,
00171 sensor_frame_id));
00172
00173 ft->gazebo_joint = model->GetJoint(ft->sensorJointName);
00174
00175
00176 boost::shared_ptr<const urdf::Link> urdf_sensor_link;
00177 boost::shared_ptr<const urdf::Joint> urdf_sensor_joint;
00178 urdf_sensor_link = urdf_model->getLink(ft->sensorFrame);
00179 urdf_sensor_joint = urdf_model->getJoint(sensor_joint_name);
00180
00181 if(!urdf_sensor_link){
00182 ROS_ERROR_STREAM("Problem finding link: "<<ft->sensorFrame<<" to attach FT sensor in robot model");
00183 return false;
00184 }
00185
00186 if(!urdf_sensor_joint){
00187 ROS_ERROR_STREAM("Problem finding joint: "<<ft->sensorJointName<<" to attach FT sensor in robot model");
00188 return false;
00189 }
00190
00191
00192 bool parentFound = false;
00193 eMatrixHom sensorTransform;
00194 sensorTransform.setIdentity();
00195
00196
00197 if(urdf_sensor_link->name == urdf_sensor_joint->child_link_name){
00198 parentFound = true;
00199 }
00200
00201 while(!parentFound){
00202 std::cerr<<" "<<urdf_sensor_link->name<<" - "<<urdf_sensor_joint->child_link_name<<std::endl;
00203
00204 urdf::Pose tf_urdf = urdf_sensor_link->parent_joint->parent_to_joint_origin_transform;
00205 eMatrixHom tf_eigen;
00206 convert(tf_urdf, tf_eigen);
00207 sensorTransform = tf_eigen*sensorTransform;
00208
00209 urdf_sensor_link = urdf_sensor_link->getParent();
00210
00211 if(urdf_sensor_joint->child_link_name == urdf_sensor_link->name){
00212 parentFound = true;
00213 }
00214
00215 }
00216
00217 if(!parentFound){
00218 ROS_ERROR_STREAM("No frame found for force torque sensor");
00219 }
00220
00221
00222
00223
00224 ft->sensorTransform = sensorTransform;
00225
00226 if (!ft->gazebo_joint){
00227 ROS_ERROR_STREAM("Could not find joint '" << ft->sensorJointName << "' to which a force-torque sensor is attached.");
00228 return false;
00229 }
00230
00231 forceTorqueSensorDefinitions_.push_back(ft);
00232 ROS_INFO_STREAM("Parsed fake FT sensor: "<<sensor_name<<" in frame: "<<sensor_frame_id);
00233 }
00234 return true;
00235 }
00236
00237 bool PalHardwareGazebo::parseIMUSensors(ros::NodeHandle &nh,
00238 gazebo::physics::ModelPtr model,
00239 const urdf::Model* const urdf_model){
00240 using std::vector;
00241 using std::string;
00242
00243 const string imu_ns = "imu";
00244 vector<string> imu_ids = getIds(nh, imu_ns);
00245 ros::NodeHandle imu_nh(nh, imu_ns);
00246 typedef vector<string>::const_iterator Iterator;
00247 for (Iterator it = imu_ids.begin(); it != imu_ids.end(); ++it){
00248 std::string sensor_name = *it;
00249 std::string sensor_frame_id;
00250 ros::NodeHandle imu_sensor_nh(imu_nh, sensor_name);
00251 xh::fetchParam(imu_sensor_nh, "frame", sensor_frame_id);
00252
00253 boost::shared_ptr<gazebo::sensors::ImuSensor> imu_sensor;
00254 imu_sensor = boost::dynamic_pointer_cast<gazebo::sensors::ImuSensor>
00255 (gazebo::sensors::SensorManager::Instance()->GetSensor("imu_sensor"));
00256 if (!imu_sensor){
00257 ROS_ERROR_STREAM("Could not find base IMU sensor.");
00258 return false;
00259 }
00260
00261 ImuSensorDefinitionPtr imu(new ImuSensorDefinition(sensor_name, sensor_frame_id));
00262 imu->gazebo_imu_sensor = imu_sensor;
00263 imuSensorDefinitions_.push_back(imu);
00264 ROS_INFO_STREAM("Parsed imu sensor: "<<sensor_name<<" in frame: "<<sensor_frame_id);
00265 }
00266 return true;
00267 }
00268
00269 PalHardwareGazebo::PalHardwareGazebo()
00270 : DefaultRobotHWSim()
00271 {}
00272
00273 bool PalHardwareGazebo::initSim(const std::string& robot_ns,
00274 ros::NodeHandle nh, gazebo::physics::ModelPtr model,
00275 const urdf::Model* const urdf_model,
00276 std::vector<transmission_interface::TransmissionInfo> transmissions)
00277 {
00278
00279 ROS_INFO_STREAM("Loading PAL HARWARE GAZEBO");
00280
00281
00282
00283 registerInterface(&js_interface_);
00284 registerInterface(&ej_interface_);
00285 registerInterface(&pj_interface_);
00286 registerInterface(&vj_interface_);
00287
00288
00289 DefaultRobotHWSim::transmission_infos_ = transmissions;
00290
00291
00292 namespace ti = transmission_interface;
00293 BOOST_FOREACH(const ti::TransmissionInfo& tr_info, transmission_infos_)
00294 {
00295 BOOST_FOREACH(const ti::JointInfo& joint_info, tr_info.joints_)
00296 {
00297 BOOST_FOREACH(const std::string& iface_type, joint_info.hardware_interfaces_)
00298 {
00299
00300 RwResPtr res;
00301
00302
00303 if (iface_type == "hardware_interface/JointStateInterface")
00304 {
00305 res.reset(new internal::JointState());
00306 }
00307 else if (iface_type == "hardware_interface/PositionJointInterface")
00308 {
00309 res.reset(new internal::PositionJoint());
00310 }
00311 else if (iface_type == "hardware_interface/VelocityJointInterface")
00312 {
00313 res.reset(new internal::VelocityJoint());
00314 }
00315 else if (iface_type == "hardware_interface/EffortJointInterface")
00316 {
00317 res.reset(new internal::EffortJoint());
00318 }
00319
00320
00321 if (res)
00322 {
00323 try
00324 {
00325 res->init(joint_info.name_,
00326 nh,
00327 model,
00328 urdf_model,
00329 this);
00330 rw_resources_.push_back(res);
00331 ROS_DEBUG_STREAM("Registered joint '" << joint_info.name_ << "' in hardware interface '" <<
00332 iface_type << "'.");
00333 }
00334 catch (const internal::ExistingResourceException&) {}
00335 catch (const std::runtime_error& ex)
00336 {
00337 ROS_ERROR_STREAM("Failed to initialize gazebo_ros_control plugin.\n" <<
00338 ex.what());
00339 return false;
00340 }
00341 catch(...)
00342 {
00343 ROS_ERROR_STREAM("Failed to initialize gazebo_ros_control plugin.\n" <<
00344 "Could not add resource '" << joint_info.name_ << "' to hardware interface '" <<
00345 iface_type << "'.");
00346 return false;
00347 }
00348 }
00349
00350 }
00351 }
00352 }
00353
00354
00355 e_stop_active_ = false;
00356
00357
00358 mode_switch_enabled_ = true;
00359 nh.getParam("gazebo_ros_control/enable_joint_mode_switching", mode_switch_enabled_);
00360 const std::string enabled_str = mode_switch_enabled_ ? "enabled" : "disabled";
00361 ROS_INFO_STREAM("Joint mode switching is " << enabled_str);
00362
00363
00364 initActiveWriteResources();
00365
00366 parseForceTorqueSensors(nh, model, urdf_model);
00367
00368 for(size_t i=0; i<forceTorqueSensorDefinitions_.size(); ++i){
00369 ForceTorqueSensorDefinitionPtr &ft = forceTorqueSensorDefinitions_[i];
00370 ft_sensor_interface_.registerHandle(ForceTorqueSensorHandle(ft->sensorName,
00371 ft->sensorFrame,
00372 &ft->force[0],
00373 &ft->torque[0]));
00374 }
00375
00376 registerInterface(&ft_sensor_interface_);
00377 ROS_DEBUG_STREAM("Registered force-torque sensors.");
00378
00379
00380 parseIMUSensors(nh, model, urdf_model);
00381
00382 for(size_t i=0; i<imuSensorDefinitions_.size(); ++i){
00383 ImuSensorDefinitionPtr &imu = imuSensorDefinitions_[i];
00384
00385 ImuSensorHandle::Data data;
00386 data.name = imu->sensorName;
00387 data.frame_id = imu->sensorFrame;
00388 data.orientation = &imu->orientation[0];
00389 data.linear_acceleration = &imu->linear_acceleration[0];
00390 data.angular_velocity = &imu->base_ang_vel[0];
00391 imu_sensor_interface_.registerHandle(ImuSensorHandle(data));
00392 }
00393
00394 registerInterface(&imu_sensor_interface_);
00395 ROS_DEBUG_STREAM("Registered IMU sensor.");
00396
00397 return true;
00398 }
00399
00400 void PalHardwareGazebo::readSim(ros::Time time, ros::Duration period)
00401 {
00402
00403 BOOST_FOREACH(RwResPtr res, rw_resources_)
00404 {
00405 res->read(time, period, e_stop_active_);
00406 }
00407
00408
00409 for(size_t i = 0; i < forceTorqueSensorDefinitions_.size(); ++i){
00410 ForceTorqueSensorDefinitionPtr &ft = forceTorqueSensorDefinitions_[i];
00411 gazebo::physics::JointWrench ft_wrench = ft->gazebo_joint->GetForceTorque(0u);
00412
00413 ft->force[0] = ft_wrench.body2Force.x;
00414 ft->force[1] = ft_wrench.body2Force.y;
00415 ft->force[2] = ft_wrench.body2Force.z;
00416 ft->torque[0] = ft_wrench.body2Torque.x;
00417 ft->torque[1] = ft_wrench.body2Torque.y;
00418 ft->torque[2] = ft_wrench.body2Torque.z;
00419
00420
00421 Eigen::MatrixXd transform(6, 6);
00422 transform.setZero();
00423 transform.block(0, 0, 3, 3) = Eigen::Matrix3d::Identity();
00424 transform.block(3, 3, 3, 3) = ft->sensorTransform.rotation().transpose();
00425 eVector3 r = ft->sensorTransform.translation();
00426 transform.block(3, 0, 3, 3) = skew(r)*ft->sensorTransform.rotation().transpose();
00427
00428 Eigen::VectorXd wrench(6);
00429 wrench<<ft->torque[0], ft->torque[1], ft->torque[2],
00430 ft->force[0], ft->force[1], ft->force[2];
00431 Eigen::VectorXd transformedWrench(6);
00432
00433 transformedWrench = transform*wrench;
00434
00435 ft->torque[0] = transformedWrench(0);
00436 ft->torque[1] = transformedWrench(1);
00437 ft->torque[2] = transformedWrench(2);
00438 ft->force[0] = transformedWrench(3);
00439 ft->force[1] = transformedWrench(4);
00440 ft->force[2] = transformedWrench(5);
00441 }
00442
00443
00444 for(size_t i = 0; i < imuSensorDefinitions_.size(); ++i){
00445 ImuSensorDefinitionPtr &imu = imuSensorDefinitions_[i];
00446
00447 gazebo::math::Quaternion imu_quat = imu->gazebo_imu_sensor->GetOrientation();
00448 imu->orientation[0] = imu_quat.x;
00449 imu->orientation[1] = imu_quat.y;
00450 imu->orientation[2] = imu_quat.z;
00451 imu->orientation[3] = imu_quat.w;
00452
00453 gazebo::math::Vector3 imu_ang_vel = imu->gazebo_imu_sensor->GetAngularVelocity();
00454 imu->base_ang_vel[0] = imu_ang_vel.x;
00455 imu->base_ang_vel[1] = imu_ang_vel.y;
00456 imu->base_ang_vel[2] = imu_ang_vel.z;
00457
00458 gazebo::math::Vector3 imu_lin_acc = imu->gazebo_imu_sensor->GetLinearAcceleration();
00459 imu->linear_acceleration[0] = imu_lin_acc.x;
00460 imu->linear_acceleration[1] = imu_lin_acc.y;
00461 imu->linear_acceleration[2] = imu_lin_acc.z;
00462 }
00463
00464 }
00465
00466 void PalHardwareGazebo::writeSim(ros::Time time, ros::Duration period)
00467 {
00468 boost::unique_lock<boost::mutex> lock(mutex_);
00469 BOOST_FOREACH(RwResPtr res, active_w_resources_rt_)
00470 {
00471 res->write(time, period, e_stop_active_);
00472 }
00473
00474 }
00475
00476 }
00477
00478 PLUGINLIB_EXPORT_CLASS(gazebo_ros_control::PalHardwareGazebo, gazebo_ros_control::RobotHWSim)