srh_joint_variable_pid_position_controller.cpp
Go to the documentation of this file.
1 
30 #include "angles/angles.h"
32 #include <string>
33 #include <sstream>
34 #include <algorithm>
35 #include <math.h>
37 
38 #include <std_msgs/Float64.h>
39 
41 
42 using std::min;
43 using std::max;
44 
45 namespace controller
46 {
47 
48  SrhJointVariablePidPositionController::SrhJointVariablePidPositionController()
49  : position_deadband_(0.015)
50  {
51  }
52 
53  bool SrhJointVariablePidPositionController::init(ros_ethercat_model::RobotStateInterface *robot, ros::NodeHandle &n)
54  {
55  ROS_ASSERT(robot);
56 
57  set_point_old_ = 0.0;
58  error_old_ = 0.0;
59  frequency_ = 1000.0;
62  smoothing_factor_p_ = 0.8;
63  smoothing_factor_i_ = 0.8;
64  smoothing_factor_d_ = 0.8;
65 
66  std::string robot_state_name;
67  node_.param<std::string>("robot_state_name", robot_state_name, "unique_robot_hw");
68 
69  try
70  {
71  robot_ = robot->getHandle(robot_state_name).getState();
72  }
74  {
75  ROS_ERROR_STREAM("Could not find robot state: " << robot_state_name << " Not loading the controller. " <<
76  e.what());
77  return false;
78  }
79 
80  node_ = n;
81 
82  if (!node_.getParam("joint", joint_name_))
83  {
84  ROS_ERROR("No joint given (namespace: %s)", node_.getNamespace().c_str());
85  return false;
86  }
87 
90  {
91  return false;
92  }
93 
94  double dummy;
96 
98  (node_, "state", 1));
99 
100  ROS_DEBUG(" --------- ");
101  ROS_DEBUG_STREAM("Init: " << joint_name_);
102 
103  // joint 0s e.g. FFJ0
104  has_j2 = is_joint_0();
105  if (has_j2)
106  {
108  if (!joint_state_)
109  {
110  ROS_ERROR("SrhJointVariablePidPositionController could not find the first joint relevant to \"%s\"\n",
111  joint_name_.c_str());
112  return false;
113  }
114  if (!joint_state_2)
115  {
116  ROS_ERROR("SrhJointVariablePidPositionController could not find the second joint relevant to \"%s\"\n",
117  joint_name_.c_str());
118  return false;
119  }
120  if (!joint_state_2->calibrated_)
121  {
122  ROS_ERROR("Joint %s not calibrated for SrhJointVariablePidPositionController", joint_name_.c_str());
123  return false;
124  }
125  else
126  {
127  joint_state_->calibrated_ = true;
128  }
129  }
130  else
131  {
132  joint_state_ = robot_->getJointState(joint_name_);
133  if (!joint_state_)
134  {
135  ROS_ERROR("SrhJointVariablePidPositionController could not find joint named \"%s\"\n", joint_name_.c_str());
136  return false;
137  }
138  if (!joint_state_->calibrated_)
139  {
140  ROS_ERROR("Joint %s not calibrated for SrhJointVariablePidPositionController", joint_name_.c_str());
141  return false;
142  }
143  }
144 
145  // get the min and max value for the current joint:
146  get_min_max(robot_->robot_model_, joint_name_);
147 
149 
151  serve_reset_gains_ = node_.advertiseService("reset_gains",
153  this);
154 
155  after_init();
156  return true;
157  }
158 
160  {
161  resetJointState();
162  pid_controller_position_->reset();
163  read_parameters();
164 
165  if (has_j2)
167  "Reseting PID for joints " << joint_state_->joint_->name << " and " << joint_state_2->joint_->name);
168  else
169  ROS_WARN_STREAM("Reseting PID for joint " << joint_state_->joint_->name);
170  }
171 
172  bool SrhJointVariablePidPositionController::setGains(sr_robot_msgs::SetPidGains::Request &req,
173  sr_robot_msgs::SetPidGains::Response &resp)
174  {
175  ROS_INFO_STREAM("Setting new PID parameters. P:" << req.p << " / I:" << req.i <<
176  " / D:" << req.d << " / IClamp:" << req.i_clamp << ", max force: " <<
177  req.max_force << ", friction deadband: " << req.friction_deadband <<
178  " pos deadband: " << req.deadband);
179 
180  p_init_ = req.p;
181  i_init_ = req.i;
182  d_init_ = req.d;
183  i_clamp_ = req.i_clamp;
184 
185  max_force_demand = req.max_force;
186  friction_deadband = req.friction_deadband;
187  position_deadband_ = req.deadband;
188 
189  // Setting the new parameters in the parameter server
190  node_.setParam("pid/p", req.p);
191  node_.setParam("pid/i", req.i);
192  node_.setParam("pid/d", req.d);
193  node_.setParam("pid/i_clamp", req.i_clamp);
194  node_.setParam("pid/max_force", max_force_demand);
195  node_.setParam("pid/position_deadband", position_deadband_);
196  node_.setParam("pid/friction_deadband", friction_deadband);
197 
198  return true;
199  }
200 
201  bool SrhJointVariablePidPositionController::resetGains(std_srvs::Empty::Request &req, std_srvs::Empty::Response &resp)
202  {
203  resetJointState();
204 
205  if (!pid_controller_position_->init(ros::NodeHandle(node_, "pid")))
206  {
207  return false;
208  }
209 
210  read_parameters();
211 
212  if (has_j2)
214  "Reseting controller gains: " << joint_state_->joint_->name << " and " << joint_state_2->joint_->name);
215  else
216  ROS_WARN_STREAM("Reseting controller gains: " << joint_state_->joint_->name);
217 
218  return true;
219  }
220 
221  void SrhJointVariablePidPositionController::getGains(double &p, double &i, double &d, double &i_max, double &i_min)
222  {
223  pid_controller_position_->getGains(p, i, d, i_max, i_min);
224  }
225 
226  void SrhJointVariablePidPositionController::updatePid(double error, double set_point)
227  {
228  double i_initial = i_init_;
229  double d_initial = d_init_;
230 
231  double diff_set_point = fabs(set_point_old_ - set_point);
232  double set_point_velocity = diff_set_point * frequency_;
233  double diff_error = fabs(error_old_ - error);
234  double error_velocity = diff_error * frequency_;
235 
236  double exp_error = exp(fabs(error));
237  double exp_log_error_velocity = exp(log10(error_velocity));
238 
239  double p = p_init_ * (exp_error + exp_log_error_velocity + set_point_velocity);
240  double i = i_init_ * (exp_error + exp_log_error_velocity + set_point_velocity);
241  double d = d_init_ * (exp_error + exp_log_error_velocity + set_point_velocity);
242 
243  if (set_point_velocity > smoothing_velocity_min_ && set_point_velocity < smoothing_velocity_max_)
244  {
245  p = smoothing_factor_p_ * p;
246  i = smoothing_factor_i_ * i;
247  d = smoothing_factor_d_ * d;
248  }
249 
250  pid_controller_position_->setGains(p, i, d, i_clamp_, -i_clamp_, 1);
251 
252  set_point_old_ = set_point;
253  error_old_ = error;
254  }
255 
257  {
258  if (!has_j2 && !joint_state_->calibrated_)
259  {
260  return;
261  }
262 
264  ROS_ASSERT(joint_state_->joint_);
265 
266  if (!initialized_)
267  {
268  resetJointState();
269  initialized_ = true;
270  }
271  if (has_j2)
272  {
273  command_ = joint_state_->commanded_position_ + joint_state_2->commanded_position_;
274  }
275  else
276  {
277  command_ = joint_state_->commanded_position_;
278  }
280 
281  // Compute position demand from position error:
282  double error_position = 0.0;
283  double commanded_effort = 0.0;
284 
285  if (has_j2)
286  {
287  error_position = (joint_state_->position_ + joint_state_2->position_) - command_;
288  }
289  else
290  {
291  error_position = joint_state_->position_ - command_;
292  }
293 
294  bool in_deadband = hysteresis_deadband.is_in_deadband(command_, error_position, position_deadband_);
295 
296  // don't compute the error if we're in the deadband.
297  if (in_deadband)
298  {
299  error_position = 0.0;
300  }
301 
302  updatePid(error_position, command_);
303 
304  commanded_effort = pid_controller_position_->computeCommand(-error_position, period);
305 
306  // clamp the result to max force
307  commanded_effort = min(commanded_effort, (max_force_demand * max_force_factor_));
308  commanded_effort = max(commanded_effort, -(max_force_demand * max_force_factor_));
309 
310  if (!in_deadband)
311  {
312  if (has_j2)
313  {
314  commanded_effort += friction_compensator->friction_compensation(
315  joint_state_->position_ + joint_state_2->position_,
316  joint_state_->velocity_ + joint_state_2->velocity_,
317  static_cast<int>(commanded_effort),
319  }
320  else
321  {
322  commanded_effort += friction_compensator->friction_compensation(joint_state_->position_,
323  joint_state_->velocity_,
324  static_cast<int>(commanded_effort),
326  }
327  }
328 
329  joint_state_->commanded_effort_ = commanded_effort;
330 
331  if (loop_count_ % 10 == 0)
332  {
334  {
335  controller_state_publisher_->msg_.header.stamp = time;
336  controller_state_publisher_->msg_.set_point = command_;
337  if (has_j2)
338  {
339  controller_state_publisher_->msg_.process_value = joint_state_->position_ + joint_state_2->position_;
340  controller_state_publisher_->msg_.process_value_dot = joint_state_->velocity_ + joint_state_2->velocity_;
341  }
342  else
343  {
344  controller_state_publisher_->msg_.process_value = joint_state_->position_;
345  controller_state_publisher_->msg_.process_value_dot = joint_state_->velocity_;
346  }
347 
348  controller_state_publisher_->msg_.error = error_position;
349  controller_state_publisher_->msg_.time_step = period.toSec();
350  controller_state_publisher_->msg_.command = commanded_effort;
351 
352  double dummy;
356  controller_state_publisher_->msg_.i_clamp,
357  dummy);
358  controller_state_publisher_->unlockAndPublish();
359  }
360  }
361  loop_count_++;
362  }
363 
365  {
366  node_.param<double>("pid/max_force", max_force_demand, 1023.0);
367  node_.param<double>("pid/position_deadband", position_deadband_, 0.015);
368  node_.param<int>("pid/friction_deadband", friction_deadband, 5);
369  }
370 
371  void SrhJointVariablePidPositionController::setCommandCB(const std_msgs::Float64ConstPtr &msg)
372  {
373  joint_state_->commanded_position_ = msg->data;
374  if (has_j2)
375  {
376  joint_state_2->commanded_position_ = 0.0;
377  }
378  }
379 
381  {
382  if (has_j2)
383  {
384  joint_state_->commanded_position_ = joint_state_->position_;
385  joint_state_2->commanded_position_ = joint_state_2->position_;
386  command_ = joint_state_->position_ + joint_state_2->position_;
387  }
388  else
389  {
390  joint_state_->commanded_position_ = joint_state_->position_;
391  command_ = joint_state_->position_;
392  }
393  }
394 } // namespace controller
395 
396 /* For the emacs weenies in the crowd.
397 Local Variables:
398  c-basic-offset: 2
399 End:
400  */
401 
402 
void get_min_max(urdf::Model model, std::string joint_name)
d
ros_ethercat_model::JointState * joint_state_
void setCommandCB(const std_msgs::Float64ConstPtr &msg)
set the position target from a topic
double position_deadband_
the position deadband value used in the hysteresis_deadband
void read_parameters()
read all the controller settings from the parameter server
virtual bool resetGains(std_srvs::Empty::Request &req, std_srvs::Empty::Response &resp)
boost::scoped_ptr< realtime_tools::RealtimePublisher< control_msgs::JointControllerState > > controller_state_publisher_
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
ros_ethercat_model::JointState * joint_state_2
boost::scoped_ptr< sr_friction_compensation::SrFrictionCompensator > friction_compensator
double clamp_command(double cmd, double min_cmd, double max_cmd)
ros_ethercat_model::RobotState * robot_
bool setGains(sr_robot_msgs::SetPidGains::Request &req, sr_robot_msgs::SetPidGains::Response &resp)
boost::scoped_ptr< PlainPid > pid_controller_position_
Internal PID controller for the position loop.
virtual void getGains(double &p, double &i, double &d, double &i_max, double &i_min)
int friction_deadband
the deadband for the friction compensation algorithm
bool param(const std::string &param_name, T &param_val, const T &default_val) const
const std::string & getNamespace() const
bool init(ros_ethercat_model::RobotStateInterface *robot, ros::NodeHandle &n)
bool is_in_deadband(T demand, T error, T deadband, double deadband_multiplicator=5.0, unsigned int nb_errors_for_avg=50)
#define ROS_WARN_STREAM(args)
#define ROS_DEBUG_STREAM(args)
double max_force_demand
clamps the force demand to this value
#define ROS_INFO_STREAM(args)
virtual void update(const ros::Time &time, const ros::Duration &period)
Issues commands to the joint. Should be called at regular intervals.
bool getParam(const std::string &key, std::string &s) const
ros::ServiceServer serve_set_gains_
#define ROS_ERROR_STREAM(args)
#define ROS_ASSERT(cond)
sr_deadband::HysteresisDeadband< double > hysteresis_deadband
We&#39;re using an hysteresis deadband.
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
#define ROS_ERROR(...)
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
void after_init()
call this function at the end of the init function in the inheriting classes.
ros::ServiceServer serve_reset_gains_
#define ROS_DEBUG(...)


sr_mechanism_controllers
Author(s): Ugo Cupcic
autogenerated on Tue Oct 13 2020 03:55:58