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
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #ifndef _GAZEBO_ROS_CONTROL___DEFAULT_ROBOT_HW_SIM_H_
00042 #define _GAZEBO_ROS_CONTROL___DEFAULT_ROBOT_HW_SIM_H_
00043
00044
00045 #include <control_toolbox/pid.h>
00046 #include <hardware_interface/joint_command_interface.h>
00047 #include <hardware_interface/robot_hw.h>
00048 #include <joint_limits_interface/joint_limits.h>
00049 #include <joint_limits_interface/joint_limits_interface.h>
00050 #include <joint_limits_interface/joint_limits_rosparam.h>
00051 #include <joint_limits_interface/joint_limits_urdf.h>
00052
00053
00054 #include <gazebo/common/common.hh>
00055 #include <gazebo/physics/physics.hh>
00056 #include <gazebo/gazebo.hh>
00057
00058
00059 #include <ros/ros.h>
00060 #include <angles/angles.h>
00061 #include <pluginlib/class_list_macros.h>
00062
00063
00064 #include <gazebo_ros_control/robot_hw_sim.h>
00065
00066
00067 #include <urdf/model.h>
00068
00069 namespace
00070 {
00071
00072 double clamp(const double val, const double min_val, const double max_val)
00073 {
00074 return std::min(std::max(val, min_val), max_val);
00075 }
00076
00077 }
00078
00079 namespace gazebo_ros_control
00080 {
00081
00082 class DefaultRobotHWSim : public gazebo_ros_control::RobotHWSim
00083 {
00084 public:
00085
00086 bool initSim(
00087 const std::string& robot_namespace,
00088 ros::NodeHandle model_nh,
00089 gazebo::physics::ModelPtr parent_model,
00090 const urdf::Model *const urdf_model,
00091 std::vector<transmission_interface::TransmissionInfo> transmissions)
00092 {
00093
00094
00095 const ros::NodeHandle joint_limit_nh(model_nh, robot_namespace);
00096
00097
00098 n_dof_ = transmissions.size();
00099 joint_names_.resize(n_dof_);
00100 joint_types_.resize(n_dof_);
00101 joint_lower_limits_.resize(n_dof_);
00102 joint_upper_limits_.resize(n_dof_);
00103 joint_effort_limits_.resize(n_dof_);
00104 joint_control_methods_.resize(n_dof_);
00105 pid_controllers_.resize(n_dof_);
00106 joint_position_.resize(n_dof_);
00107 joint_velocity_.resize(n_dof_);
00108 joint_effort_.resize(n_dof_);
00109 joint_effort_command_.resize(n_dof_);
00110 joint_position_command_.resize(n_dof_);
00111 joint_velocity_command_.resize(n_dof_);
00112
00113
00114 for(unsigned int j=0; j < n_dof_; j++)
00115 {
00116
00117 if(transmissions[j].joints_.size() == 0)
00118 {
00119 ROS_WARN_STREAM_NAMED("default_robot_hw_sim","Transmission " << transmissions[j].name_
00120 << " has no associated joints.");
00121 continue;
00122 }
00123 else if(transmissions[j].joints_.size() > 1)
00124 {
00125 ROS_WARN_STREAM_NAMED("default_robot_hw_sim","Transmission " << transmissions[j].name_
00126 << " has more than one joint. Currently the default robot hardware simulation "
00127 << " interface only supports one.");
00128 continue;
00129 }
00130
00131
00132 if(transmissions[j].actuators_.size() == 0)
00133 {
00134 ROS_WARN_STREAM_NAMED("default_robot_hw_sim","Transmission " << transmissions[j].name_
00135 << " has no associated actuators.");
00136 continue;
00137 }
00138 else if(transmissions[j].actuators_.size() > 1)
00139 {
00140 ROS_WARN_STREAM_NAMED("default_robot_hw_sim","Transmission " << transmissions[j].name_
00141 << " has more than one actuator. Currently the default robot hardware simulation "
00142 << " interface only supports one.");
00143 continue;
00144 }
00145
00146
00147 joint_names_[j] = transmissions[j].joints_[0].name_;
00148 joint_position_[j] = 1.0;
00149 joint_velocity_[j] = 0.0;
00150 joint_effort_[j] = 1.0;
00151 joint_effort_command_[j] = 0.0;
00152 joint_position_command_[j] = 0.0;
00153 joint_velocity_command_[j] = 0.0;
00154
00155 #if ROS_VERSION_MINOR > 10 || ROS_VERSION_MAJOR > 1
00156 const std::string &hardware_interface =
00157 transmissions[j].actuators_[0].hardware_interfaces_[0];
00158 #else
00159 const std::string &hardware_interface =
00160 transmissions[j].actuators_[0].hardware_interface_;
00161 #endif
00162
00163
00164 ROS_DEBUG_STREAM_NAMED("default_robot_hw_sim","Loading joint '" << joint_names_[j]
00165 << "' of type '" << hardware_interface << "'");
00166
00167
00168 js_interface_.registerHandle(hardware_interface::JointStateHandle(
00169 joint_names_[j], &joint_position_[j], &joint_velocity_[j], &joint_effort_[j]));
00170
00171
00172 hardware_interface::JointHandle joint_handle;
00173 if(hardware_interface == "EffortJointInterface")
00174 {
00175
00176 joint_control_methods_[j] = EFFORT;
00177 joint_handle = hardware_interface::JointHandle(js_interface_.getHandle(joint_names_[j]),
00178 &joint_effort_command_[j]);
00179 ej_interface_.registerHandle(joint_handle);
00180 }
00181 else if(hardware_interface == "PositionJointInterface")
00182 {
00183
00184 joint_control_methods_[j] = POSITION;
00185 joint_handle = hardware_interface::JointHandle(js_interface_.getHandle(joint_names_[j]),
00186 &joint_position_command_[j]);
00187 pj_interface_.registerHandle(joint_handle);
00188 }
00189 else if(hardware_interface == "VelocityJointInterface")
00190 {
00191
00192 joint_control_methods_[j] = VELOCITY;
00193 joint_handle = hardware_interface::JointHandle(js_interface_.getHandle(joint_names_[j]),
00194 &joint_velocity_command_[j]);
00195 vj_interface_.registerHandle(joint_handle);
00196 }
00197 else
00198 {
00199 ROS_FATAL_STREAM_NAMED("default_robot_hw_sim","No matching hardware interface found for '"
00200 << hardware_interface );
00201 return false;
00202 }
00203
00204
00205
00206
00207 gazebo::physics::JointPtr joint = parent_model->GetJoint(joint_names_[j]);
00208 if (!joint)
00209 {
00210 ROS_ERROR_STREAM("This robot has a joint named \"" << joint_names_[j]
00211 << "\" which is not in the gazebo model.");
00212 return false;
00213 }
00214 sim_joints_.push_back(joint);
00215
00216 registerJointLimits(joint_names_[j], joint_handle, joint_control_methods_[j],
00217 joint_limit_nh, urdf_model,
00218 &joint_types_[j], &joint_lower_limits_[j], &joint_upper_limits_[j],
00219 &joint_effort_limits_[j]);
00220 if (joint_control_methods_[j] != EFFORT)
00221 {
00222
00223
00224 const ros::NodeHandle nh(model_nh, robot_namespace + "/gazebo_ros_control/pid_gains/" +
00225 joint_names_[j]);
00226 if (pid_controllers_[j].init(nh))
00227 {
00228 switch (joint_control_methods_[j])
00229 {
00230 case POSITION:
00231 joint_control_methods_[j] = POSITION_PID;
00232 break;
00233 case VELOCITY:
00234 joint_control_methods_[j] = VELOCITY_PID;
00235 break;
00236 }
00237 }
00238 else
00239 {
00240
00241
00242
00243 joint->SetMaxForce(0, joint_effort_limits_[j]);
00244 }
00245 }
00246 }
00247
00248
00249 registerInterface(&js_interface_);
00250 registerInterface(&ej_interface_);
00251 registerInterface(&pj_interface_);
00252 registerInterface(&vj_interface_);
00253
00254 return true;
00255 }
00256
00257 void readSim(ros::Time time, ros::Duration period)
00258 {
00259 for(unsigned int j=0; j < n_dof_; j++)
00260 {
00261
00262 if (joint_types_[j] == urdf::Joint::PRISMATIC)
00263 {
00264 joint_position_[j] = sim_joints_[j]->GetAngle(0).Radian();
00265 }
00266 else
00267 {
00268 joint_position_[j] += angles::shortest_angular_distance(joint_position_[j],
00269 sim_joints_[j]->GetAngle(0).Radian());
00270 }
00271 joint_velocity_[j] = sim_joints_[j]->GetVelocity(0);
00272 joint_effort_[j] = sim_joints_[j]->GetForce((unsigned int)(0));
00273 }
00274 }
00275
00276 void writeSim(ros::Time time, ros::Duration period)
00277 {
00278 ej_sat_interface_.enforceLimits(period);
00279 ej_limits_interface_.enforceLimits(period);
00280 pj_sat_interface_.enforceLimits(period);
00281 pj_limits_interface_.enforceLimits(period);
00282 vj_sat_interface_.enforceLimits(period);
00283 vj_limits_interface_.enforceLimits(period);
00284
00285 for(unsigned int j=0; j < n_dof_; j++)
00286 {
00287 switch (joint_control_methods_[j])
00288 {
00289 case EFFORT:
00290 {
00291 const double effort = joint_effort_command_[j];
00292 sim_joints_[j]->SetForce(0, effort);
00293 }
00294 break;
00295
00296 case POSITION:
00297 #if GAZEBO_MAJOR_VERSION >= 4
00298 sim_joints_[j]->SetPosition(0, joint_position_command_[j]);
00299 #else
00300 sim_joints_[j]->SetAngle(0, joint_position_command_[j]);
00301 #endif
00302 break;
00303
00304 case POSITION_PID:
00305 {
00306 double error;
00307 switch (joint_types_[j])
00308 {
00309 case urdf::Joint::REVOLUTE:
00310 angles::shortest_angular_distance_with_limits(joint_position_[j],
00311 joint_position_command_[j],
00312 joint_lower_limits_[j],
00313 joint_upper_limits_[j],
00314 error);
00315 break;
00316 case urdf::Joint::CONTINUOUS:
00317 error = angles::shortest_angular_distance(joint_position_[j],
00318 joint_position_command_[j]);
00319 break;
00320 default:
00321 error = joint_position_command_[j] - joint_position_[j];
00322 }
00323
00324 const double effort_limit = joint_effort_limits_[j];
00325 const double effort = clamp(pid_controllers_[j].computeCommand(error, period),
00326 -effort_limit, effort_limit);
00327 sim_joints_[j]->SetForce(0, effort);
00328 }
00329 break;
00330
00331 case VELOCITY:
00332 sim_joints_[j]->SetVelocity(0, joint_velocity_command_[j]);
00333 break;
00334
00335 case VELOCITY_PID:
00336 const double error = joint_velocity_command_[j] - joint_velocity_[j];
00337 const double effort_limit = joint_effort_limits_[j];
00338 const double effort = clamp(pid_controllers_[j].computeCommand(error, period),
00339 -effort_limit, effort_limit);
00340 sim_joints_[j]->SetForce(0, effort);
00341 break;
00342 }
00343 }
00344 }
00345
00346 private:
00347
00348 enum ControlMethod {EFFORT, POSITION, POSITION_PID, VELOCITY, VELOCITY_PID};
00349
00350
00351
00352
00353 void registerJointLimits(const std::string& joint_name,
00354 const hardware_interface::JointHandle& joint_handle,
00355 const ControlMethod ctrl_method,
00356 const ros::NodeHandle& joint_limit_nh,
00357 const urdf::Model *const urdf_model,
00358 int *const joint_type, double *const lower_limit,
00359 double *const upper_limit, double *const effort_limit)
00360 {
00361 *joint_type = urdf::Joint::UNKNOWN;
00362 *lower_limit = -std::numeric_limits<double>::max();
00363 *upper_limit = std::numeric_limits<double>::max();
00364 *effort_limit = std::numeric_limits<double>::max();
00365
00366 joint_limits_interface::JointLimits limits;
00367 bool has_limits = false;
00368 joint_limits_interface::SoftJointLimits soft_limits;
00369 bool has_soft_limits = false;
00370
00371 if (urdf_model != NULL)
00372 {
00373 const boost::shared_ptr<const urdf::Joint> urdf_joint = urdf_model->getJoint(joint_name);
00374 if (urdf_joint != NULL)
00375 {
00376 *joint_type = urdf_joint->type;
00377
00378 if (joint_limits_interface::getJointLimits(urdf_joint, limits))
00379 has_limits = true;
00380 if (joint_limits_interface::getSoftJointLimits(urdf_joint, soft_limits))
00381 has_soft_limits = true;
00382 }
00383 }
00384
00385 if (joint_limits_interface::getJointLimits(joint_name, joint_limit_nh, limits))
00386 has_limits = true;
00387
00388 if (!has_limits)
00389 return;
00390
00391 if (*joint_type == urdf::Joint::UNKNOWN)
00392 {
00393
00394
00395 if (limits.has_position_limits)
00396 {
00397 *joint_type = urdf::Joint::REVOLUTE;
00398 }
00399 else
00400 {
00401 if (limits.angle_wraparound)
00402 *joint_type = urdf::Joint::CONTINUOUS;
00403 else
00404 *joint_type = urdf::Joint::PRISMATIC;
00405 }
00406 }
00407
00408 if (limits.has_position_limits)
00409 {
00410 *lower_limit = limits.min_position;
00411 *upper_limit = limits.max_position;
00412 }
00413 if (limits.has_effort_limits)
00414 *effort_limit = limits.max_effort;
00415
00416 if (has_soft_limits)
00417 {
00418 switch (ctrl_method)
00419 {
00420 case EFFORT:
00421 {
00422 const joint_limits_interface::EffortJointSoftLimitsHandle
00423 limits_handle(joint_handle, limits, soft_limits);
00424 ej_limits_interface_.registerHandle(limits_handle);
00425 }
00426 break;
00427 case POSITION:
00428 {
00429 const joint_limits_interface::PositionJointSoftLimitsHandle
00430 limits_handle(joint_handle, limits, soft_limits);
00431 pj_limits_interface_.registerHandle(limits_handle);
00432 }
00433 break;
00434 case VELOCITY:
00435 {
00436 const joint_limits_interface::VelocityJointSoftLimitsHandle
00437 limits_handle(joint_handle, limits, soft_limits);
00438 vj_limits_interface_.registerHandle(limits_handle);
00439 }
00440 break;
00441 }
00442 }
00443 else
00444 {
00445 switch (ctrl_method)
00446 {
00447 case EFFORT:
00448 {
00449 const joint_limits_interface::EffortJointSaturationHandle
00450 sat_handle(joint_handle, limits);
00451 ej_sat_interface_.registerHandle(sat_handle);
00452 }
00453 break;
00454 case POSITION:
00455 {
00456 const joint_limits_interface::PositionJointSaturationHandle
00457 sat_handle(joint_handle, limits);
00458 pj_sat_interface_.registerHandle(sat_handle);
00459 }
00460 break;
00461 case VELOCITY:
00462 {
00463 const joint_limits_interface::VelocityJointSaturationHandle
00464 sat_handle(joint_handle, limits);
00465 vj_sat_interface_.registerHandle(sat_handle);
00466 }
00467 break;
00468 }
00469 }
00470 }
00471
00472 unsigned int n_dof_;
00473
00474 hardware_interface::JointStateInterface js_interface_;
00475 hardware_interface::EffortJointInterface ej_interface_;
00476 hardware_interface::PositionJointInterface pj_interface_;
00477 hardware_interface::VelocityJointInterface vj_interface_;
00478
00479 joint_limits_interface::EffortJointSaturationInterface ej_sat_interface_;
00480 joint_limits_interface::EffortJointSoftLimitsInterface ej_limits_interface_;
00481 joint_limits_interface::PositionJointSaturationInterface pj_sat_interface_;
00482 joint_limits_interface::PositionJointSoftLimitsInterface pj_limits_interface_;
00483 joint_limits_interface::VelocityJointSaturationInterface vj_sat_interface_;
00484 joint_limits_interface::VelocityJointSoftLimitsInterface vj_limits_interface_;
00485
00486 std::vector<std::string> joint_names_;
00487 std::vector<int> joint_types_;
00488 std::vector<double> joint_lower_limits_;
00489 std::vector<double> joint_upper_limits_;
00490 std::vector<double> joint_effort_limits_;
00491 std::vector<ControlMethod> joint_control_methods_;
00492 std::vector<control_toolbox::Pid> pid_controllers_;
00493 std::vector<double> joint_position_;
00494 std::vector<double> joint_velocity_;
00495 std::vector<double> joint_effort_;
00496 std::vector<double> joint_effort_command_;
00497 std::vector<double> joint_position_command_;
00498 std::vector<double> joint_velocity_command_;
00499
00500 std::vector<gazebo::physics::JointPtr> sim_joints_;
00501 };
00502
00503 typedef boost::shared_ptr<DefaultRobotHWSim> DefaultRobotHWSimPtr;
00504
00505 }
00506
00507 PLUGINLIB_EXPORT_CLASS(gazebo_ros_control::DefaultRobotHWSim, gazebo_ros_control::RobotHWSim)
00508
00509 #endif // #ifndef __GAZEBO_ROS_CONTROL_PLUGIN_DEFAULT_ROBOT_HW_SIM_H_