armadillo2_sim_interface.cpp
Go to the documentation of this file.
1 
3 namespace
4 {
5 
6  double clamp(const double val, const double min_val, const double max_val)
7  {
8  return std::min(std::max(val, min_val), max_val);
9  }
10 
11 }
12 
13 namespace gazebo_ros_control
14 {
15 
16 
18  const std::string& robot_namespace,
19  ros::NodeHandle model_nh,
20  gazebo::physics::ModelPtr parent_model,
21  const urdf::Model *const urdf_model,
22  std::vector<transmission_interface::TransmissionInfo> transmissions)
23  {
24  // getJointLimits() searches joint_limit_nh for joint limit parameters. The format of each
25  // parameter's name is "joint_limits/<joint name>". An example is "joint_limits/axle_joint".
26  const ros::NodeHandle joint_limit_nh(model_nh, robot_namespace);
27 
28  // Resize vectors to our DOF
29  n_dof_ = transmissions.size();
30  joint_names_.resize(n_dof_);
31  joint_types_.resize(n_dof_);
36  pid_controllers_.resize(n_dof_);
37  joint_position_.resize(n_dof_);
38  joint_velocity_.resize(n_dof_);
39  joint_effort_.resize(n_dof_);
43 
44  // Initialize values
45  for(unsigned int j=0; j < n_dof_; j++)
46  {
47  // Check that this transmission has one joint
48  if(transmissions[j].joints_.size() == 0)
49  {
50  ROS_WARN_STREAM_NAMED("default_robot_hw_sim","Transmission " << transmissions[j].name_
51  << " has no associated joints.");
52  continue;
53  }
54  else if(transmissions[j].joints_.size() > 1)
55  {
56  ROS_WARN_STREAM_NAMED("default_robot_hw_sim","Transmission " << transmissions[j].name_
57  << " has more than one joint. Currently the default robot hardware simulation "
58  << " interface only supports one.");
59  continue;
60  }
61 
62  std::vector<std::string> joint_interfaces = transmissions[j].joints_[0].hardware_interfaces_;
63  if (joint_interfaces.empty() &&
64  !(transmissions[j].actuators_.empty()) &&
65  !(transmissions[j].actuators_[0].hardware_interfaces_.empty()))
66  {
67  // TODO: Deprecate HW interface specification in actuators in ROS J
68  joint_interfaces = transmissions[j].actuators_[0].hardware_interfaces_;
69  ROS_WARN_STREAM_NAMED("default_robot_hw_sim", "The <hardware_interface> element of tranmission " <<
70  transmissions[j].name_ << " should be nested inside the <joint> element, not <actuator>. " <<
71  "The transmission will be properly loaded, but please update " <<
72  "your robot model to remain compatible with future versions of the plugin.");
73  }
74  if (joint_interfaces.empty())
75  {
76  ROS_WARN_STREAM_NAMED("default_robot_hw_sim", "Joint " << transmissions[j].joints_[0].name_ <<
77  " of transmission " << transmissions[j].name_ << " does not specify any hardware interface. " <<
78  "Not adding it to the robot hardware simulation.");
79  continue;
80  }
81  else if (joint_interfaces.size() > 1)
82  {
83  ROS_WARN_STREAM_NAMED("default_robot_hw_sim", "Joint " << transmissions[j].joints_[0].name_ <<
84  " of transmission " << transmissions[j].name_ << " specifies multiple hardware interfaces. " <<
85  "Currently the default robot hardware simulation interface only supports one. Using the first entry!");
86  //continue;
87  }
88 
89  // Add data from transmission
90  joint_names_[j] = transmissions[j].joints_[0].name_;
91  joint_position_[j] = 1.0;
92  joint_velocity_[j] = 0.0;
93  joint_effort_[j] = 1.0; // N/m for continuous joints
94  joint_effort_command_[j] = 0.0;
95  joint_position_command_[j] = 0.0;
96  joint_velocity_command_[j] = 0.0;
97 
98  const std::string& hardware_interface = joint_interfaces.front();
99 
100  // Debug
101  ROS_DEBUG_STREAM_NAMED("armadillo2_hw_sim","Loading joint '" << joint_names_[j]
102  << "' of type '" << hardware_interface << "'");
103 
104  // Create joint state interface for all joints
107 
108  // Decide what kind of command interface this actuator/joint has
109  hardware_interface::JointHandle joint_handle;
110  hardware_interface::PosVelJointHandle jointHandlePosVel;
111  if(hardware_interface == "EffortJointInterface" || hardware_interface == "hardware_interface/EffortJointInterface")
112  {
113  // Create effort joint interface
117  ej_interface_.registerHandle(joint_handle);
118  }
119  else if(hardware_interface == "PositionJointInterface" || hardware_interface == "hardware_interface/PositionJointInterface")
120  {
121  // Create position joint interface
125  pj_interface_.registerHandle(joint_handle);
126  }
127  else if(hardware_interface == "VelocityJointInterface" || hardware_interface == "hardware_interface/VelocityJointInterface")
128  {
129  // Create velocity joint interface
133  vj_interface_.registerHandle(joint_handle);
134  }
135  else if(hardware_interface == "PosVelJointInterface" || hardware_interface == "hardware_interface/PosVelJointInterface")
136  {
137  // Create velocity joint interface
139 
141  pvj_interface_.registerHandle(jointHandlePosVel);
142  }
143  else
144  {
145  ROS_FATAL_STREAM_NAMED("default_robot_hw_sim","No matching hardware interface found for '"
146  << hardware_interface );
147  return false;
148  }
149 
150  // Get the gazebo joint that corresponds to the robot joint.
151  //ROS_DEBUG_STREAM_NAMED("default_robot_hw_sim", "Getting pointer to gazebo joint: "
152  // << joint_names_[j]);
153  gazebo::physics::JointPtr joint = parent_model->GetJoint(joint_names_[j]);
154  if (!joint)
155  {
156  ROS_ERROR_STREAM("This robot has a joint named \"" << joint_names_[j]
157  << "\" which is not in the gazebo model.");
158  return false;
159  }
160  sim_joints_.push_back(joint);
161  if(!joint_control_methods_[j] != POS_VEL) {
163  joint_limit_nh, urdf_model,
166  }
167  else {
168  registerJointLimits(joint_names_[j], jointHandlePosVel, joint_control_methods_[j],
169  joint_limit_nh, urdf_model,
172 
173  }
174 //ROS_ERROR("LIMIT on: %s UP: %f DOWN: %f",joint_names_[j].c_str(),joint_lower_limits_[j],joint_upper_limits_[j]);
175 
176  if (joint_control_methods_[j] != EFFORT)
177  {
178  // Initialize the PID controller. If no PID gain values are found, use joint->SetAngle() or
179  // joint->SetVelocity() to control the joint.
180  const ros::NodeHandle nh(model_nh, robot_namespace + "/gazebo_ros_control/pid_gains/" +
181  joint_names_[j]);
182  if (pid_controllers_[j].init(nh, true))
183  {
184  switch (joint_control_methods_[j])
185  {
186  case POSITION:
188  break;
189  case VELOCITY:
191  break;
192  case POS_VEL:
194  // ROS_ERROR("PID on: %s",joint_names_[j].c_str());
195  break;
196  }
197  }
198  else
199  {
200  // joint->SetMaxForce() must be called if joint->SetAngle() or joint->SetVelocity() are
201  // going to be called. joint->SetMaxForce() must *not* be called if joint->SetForce() is
202  // going to be called.
203  #if GAZEBO_MAJOR_VERSION > 2
204  joint->SetParam("fmax", 0, joint_effort_limits_[j]);
205  #else
206  joint->SetMaxForce(0, joint_effort_limits_[j]);
207  #endif
208 
209  }
210  }
211  }
212 
213  // Register interfaces
219 
220  // Initialize the emergency stop code.
221  e_stop_active_ = false;
222  last_e_stop_active_ = false;
223 
224  return true;
225  }
226 
228  {
229  for(unsigned int j=0; j < n_dof_; j++)
230  {
231  // Gazebo has an interesting API...
232  if (joint_types_[j] == urdf::Joint::PRISMATIC)
233  {
234  joint_position_[j] = sim_joints_[j]->GetAngle(0).Radian();
235  }
236  else
237  {
239  sim_joints_[j]->GetAngle(0).Radian());
240  }
241  joint_velocity_[j] = sim_joints_[j]->GetVelocity(0);
242  joint_effort_[j] = sim_joints_[j]->GetForce((unsigned int)(0));
243  }
244  }
245 
247  {
248  // If the E-stop is active, joints controlled by position commands will maintain their positions.
249  if (e_stop_active_)
250  {
251  if (!last_e_stop_active_)
252  {
254  last_e_stop_active_ = true;
255  }
257  }
258  else
259  {
260  last_e_stop_active_ = false;
261  }
262 
269 
270  for(unsigned int j=0; j < n_dof_; j++)
271  {
272  switch (joint_control_methods_[j])
273  {
274 
275  case POS_VEL:
276 
277 //sim_joints_[j]->SetVelocityLimit(0,joint_velocity_command_[j]);
278 #if GAZEBO_MAJOR_VERSION >= 4
279  sim_joints_[j]->SetPosition(0, joint_position_command_[j]);
280 #else
281  sim_joints_[j]->SetAngle(0, joint_position_command_[j]);
282 #endif
283  sim_joints_[j]->SetVelocity(0, e_stop_active_ ? 0 : joint_velocity_command_[j]);
284 
285  break;
286 
287  case EFFORT:
288  {
289  const double effort = e_stop_active_ ? 0 : joint_effort_command_[j];
290  sim_joints_[j]->SetForce(0, effort);
291  }
292  break;
293 
294  case POSITION:
295 #if GAZEBO_MAJOR_VERSION >= 4
296  sim_joints_[j]->SetPosition(0, joint_position_command_[j]);
297 #else
298  sim_joints_[j]->SetAngle(0, joint_position_command_[j]);
299 #endif
300  break;
301 
302  case POSITION_PID:
303  {
304  double error;
305  switch (joint_types_[j])
306  {
307  case urdf::Joint::REVOLUTE:
312  error);
313  break;
314  case urdf::Joint::CONTINUOUS:
317  break;
318  default:
320  }
321 
322  const double effort_limit = joint_effort_limits_[j];
323  const double effort = clamp(pid_controllers_[j].computeCommand(error, period),
324  -effort_limit, effort_limit);
325  sim_joints_[j]->SetForce(0, effort);
326  }
327  break;
328 
329  case VELOCITY:
330  sim_joints_[j]->SetVelocity(0, e_stop_active_ ? 0 : joint_velocity_command_[j]);
331  break;
332 
333  case VELOCITY_PID:
334  double error;
335  if (e_stop_active_)
336  error = -joint_velocity_[j];
337  else
339  const double effort_limit = joint_effort_limits_[j];
340  const double effort = clamp(pid_controllers_[j].computeCommand(error, period),
341  -effort_limit, effort_limit);
342  sim_joints_[j]->SetForce(0, effort);
343  break;
344 
345  }
346  }
347  }
348 
349  void Armadillo2RobotHWSim::eStopActive(const bool active)
350  {
351  e_stop_active_ = active;
352  }
353 
354 // Register the limits of the joint specified by joint_name and joint_handle. The limits are
355 // retrieved from joint_limit_nh. If urdf_model is not NULL, limits are retrieved from it also.
356 // Return the joint's type, lower position limit, upper position limit, and effort limit.
357  void Armadillo2RobotHWSim::registerJointLimits(const std::string& joint_name,
358  const hardware_interface::JointHandle& joint_handle,
359  const ControlMethod ctrl_method,
360  const ros::NodeHandle& joint_limit_nh,
361  const urdf::Model *const urdf_model,
362  int *const joint_type, double *const lower_limit,
363  double *const upper_limit, double *const effort_limit)
364  {
365  *joint_type = urdf::Joint::UNKNOWN;
366  *lower_limit = -std::numeric_limits<double>::max();
367  *upper_limit = std::numeric_limits<double>::max();
368  *effort_limit = std::numeric_limits<double>::max();
369 
371  bool has_limits = false;
373  bool has_soft_limits = false;
374 
375  if (urdf_model != NULL)
376  {
377  const boost::shared_ptr<const urdf::Joint> urdf_joint = urdf_model->getJoint(joint_name);
378  if (urdf_joint != NULL)
379  {
380  *joint_type = urdf_joint->type;
381  // Get limits from the URDF file.
382  if (joint_limits_interface::getJointLimits(urdf_joint, limits))
383  has_limits = true;
384  if (joint_limits_interface::getSoftJointLimits(urdf_joint, soft_limits))
385  has_soft_limits = true;
386  }
387  }
388  // Get limits from the parameter server.
389  if (joint_limits_interface::getJointLimits(joint_name, joint_limit_nh, limits))
390  has_limits = true;
391 
392  if (!has_limits)
393  return;
394 
395  if (*joint_type == urdf::Joint::UNKNOWN)
396  {
397  // Infer the joint type.
398 
399  if (limits.has_position_limits)
400  {
401  *joint_type = urdf::Joint::REVOLUTE;
402  }
403  else
404  {
405  if (limits.angle_wraparound)
406  *joint_type = urdf::Joint::CONTINUOUS;
407  else
408  *joint_type = urdf::Joint::PRISMATIC;
409  }
410  }
411 
412  if (limits.has_position_limits)
413  {
414  *lower_limit = limits.min_position;
415  *upper_limit = limits.max_position;
416  }
417  if (limits.has_effort_limits)
418  *effort_limit = limits.max_effort;
419 
420  if (has_soft_limits)
421  {
422  switch (ctrl_method)
423  {
424  case EFFORT:
425  {
427  limits_handle(joint_handle, limits, soft_limits);
428  ej_limits_interface_.registerHandle(limits_handle);
429  }
430  break;
431  case POSITION:
432  {
434  limits_handle(joint_handle, limits, soft_limits);
435  pj_limits_interface_.registerHandle(limits_handle);
436  }
437  break;
438  case VELOCITY:
439  {
441  limits_handle(joint_handle, limits, soft_limits);
442  vj_limits_interface_.registerHandle(limits_handle);
443  }
444  break;
445  }
446  }
447  else
448  {
449  switch (ctrl_method)
450  {
451  case EFFORT:
452  {
454  sat_handle(joint_handle, limits);
455  ej_sat_interface_.registerHandle(sat_handle);
456  }
457  break;
458  case POSITION:
459  {
461  sat_handle(joint_handle, limits);
462  pj_sat_interface_.registerHandle(sat_handle);
463  }
464  break;
465  case VELOCITY:
466  {
468  sat_handle(joint_handle, limits);
469  vj_sat_interface_.registerHandle(sat_handle);
470  }
471  break;
472  }
473  }
474  }
475 
476 
477  void Armadillo2RobotHWSim::registerJointLimits(const std::string& joint_name,
478  const hardware_interface::PosVelJointHandle& joint_handle,
479  const ControlMethod ctrl_method,
480  const ros::NodeHandle& joint_limit_nh,
481  const urdf::Model *const urdf_model,
482  int *const joint_type, double *const lower_limit,
483  double *const upper_limit, double *const effort_limit)
484  {
485  *joint_type = urdf::Joint::UNKNOWN;
486  *lower_limit = -std::numeric_limits<double>::max();
487  *upper_limit = std::numeric_limits<double>::max();
488  *effort_limit = std::numeric_limits<double>::max();
489 
491  bool has_limits = false;
493  bool has_soft_limits = false;
494 
495  if (urdf_model != NULL)
496  {
497  const boost::shared_ptr<const urdf::Joint> urdf_joint = urdf_model->getJoint(joint_name);
498  if (urdf_joint != NULL)
499  {
500  *joint_type = urdf_joint->type;
501  // Get limits from the URDF file.
502  if (joint_limits_interface::getJointLimits(urdf_joint, limits))
503  has_limits = true;
504  if (joint_limits_interface::getSoftJointLimits(urdf_joint, soft_limits))
505  has_soft_limits = true;
506  }
507  }
508  // Get limits from the parameter server.
509  if (joint_limits_interface::getJointLimits(joint_name, joint_limit_nh, limits))
510  has_limits = true;
511 
512  if (!has_limits)
513  return;
514 
515  if (*joint_type == urdf::Joint::UNKNOWN)
516  {
517  // Infer the joint type.
518 
519  if (limits.has_position_limits)
520  {
521  *joint_type = urdf::Joint::REVOLUTE;
522  }
523  else
524  {
525  if (limits.angle_wraparound)
526  *joint_type = urdf::Joint::CONTINUOUS;
527  else
528  *joint_type = urdf::Joint::PRISMATIC;
529  }
530  }
531 
532  if (limits.has_position_limits)
533  {
534  *lower_limit = limits.min_position;
535  *upper_limit = limits.max_position;
536  }
537  if (limits.has_effort_limits)
538  *effort_limit = limits.max_effort;
539 
540  /* if (has_soft_limits)
541  {
542  switch (ctrl_method)
543  {
544  case POS_VEL:
545  {
546  const joint_limits_interface::PositionJointSoftLimitsHandle limits_handle(joint_handle., limits, soft_limits);
547  pj_limits_interface_.registerHandle(limits_handle);
548  }
549  break;
550  };
551  }
552  else
553  {
554  switch (ctrl_method)
555  {
556  case EFFORT:
557  {
558  const joint_limits_interface::EffortJointSaturationHandle
559  sat_handle(joint_handle, limits);
560  ej_sat_interface_.registerHandle(sat_handle);
561  }
562  break;
563  case POSITION:
564  {
565  const joint_limits_interface::PositionJointSaturationHandle
566  sat_handle(joint_handle, limits);
567  pj_sat_interface_.registerHandle(sat_handle);
568  }
569  break;
570  case VELOCITY:
571  {
572  const joint_limits_interface::VelocityJointSaturationHandle
573  sat_handle(joint_handle, limits);
574  vj_sat_interface_.registerHandle(sat_handle);
575  }
576  break;
577  }
578  }*/
579  }
581 }
582 
583 
hardware_interface::PosVelJointInterface pvj_interface_
hardware_interface::PositionJointInterface pj_interface_
#define ROS_DEBUG_STREAM_NAMED(name, args)
joint_limits_interface::VelocityJointSaturationInterface vj_sat_interface_
virtual void readSim(ros::Time time, ros::Duration period)
joint_limits_interface::PositionJointSoftLimitsInterface pj_limits_interface_
virtual bool init(ros::NodeHandle &root_nh, ros::NodeHandle &robot_hw_nh)
std::vector< ControlMethod > joint_control_methods_
joint_limits_interface::EffortJointSoftLimitsInterface ej_limits_interface_
joint_limits_interface::PositionJointSaturationInterface pj_sat_interface_
void enforceLimits(const ros::Duration &period)
hardware_interface::JointStateInterface js_interface_
void registerJointLimits(const std::string &joint_name, const hardware_interface::JointHandle &joint_handle, const ControlMethod ctrl_method, const ros::NodeHandle &joint_limit_nh, const urdf::Model *const urdf_model, int *const joint_type, double *const lower_limit, double *const upper_limit, double *const effort_limit)
bool getSoftJointLimits(urdf::JointConstSharedPtr urdf_joint, SoftJointLimits &soft_limits)
#define ROS_FATAL_STREAM_NAMED(name, args)
virtual void writeSim(ros::Time time, ros::Duration period)
hardware_interface::VelocityJointInterface vj_interface_
hardware_interface::EffortJointInterface ej_interface_
joint_limits_interface::EffortJointSaturationInterface ej_sat_interface_
std::vector< gazebo::physics::JointPtr > sim_joints_
void registerHandle(const JointStateHandle &handle)
def shortest_angular_distance_with_limits(from_angle, to_angle, left_limit, right_limit)
JointStateHandle getHandle(const std::string &name)
std::vector< control_toolbox::Pid > pid_controllers_
bool getJointLimits(urdf::JointConstSharedPtr urdf_joint, JointLimits &limits)
virtual bool initSim(const std::string &robot_namespace, ros::NodeHandle model_nh, gazebo::physics::ModelPtr parent_model, const urdf::Model *const urdf_model, std::vector< transmission_interface::TransmissionInfo > transmissions)
joint_limits_interface::VelocityJointSoftLimitsInterface vj_limits_interface_
PLUGINLIB_EXPORT_CLASS(transmission_interface::BiDirectionalEffortJointInterfaceProvider, transmission_interface::RequisiteProvider)
#define ROS_ERROR_STREAM(args)
def shortest_angular_distance(from_angle, to_angle)
#define ROS_WARN_STREAM_NAMED(name, args)


armadillo2_sim_interface
Author(s): Jonathan Bohren, Dave Coleman
autogenerated on Wed Jan 3 2018 03:47:52