srh_joint_muscle_valve_controller.cpp
Go to the documentation of this file.
1 
30 #include "angles/angles.h"
32 #include <string>
33 #include <sstream>
34 #include <math.h>
36 
37 #include <std_msgs/Float64.h>
38 
40 
41 namespace controller
42 {
43 
44  SrhJointMuscleValveController::SrhJointMuscleValveController()
45  : cmd_valve_muscle_min_(-4),
46  cmd_valve_muscle_max_(4)
47  {
48  }
49 
50  bool SrhJointMuscleValveController::init(ros_ethercat_model::RobotStateInterface *robot, ros::NodeHandle &n)
51  {
52  ROS_ASSERT(robot);
53 
54  std::string robot_state_name;
55  node_.param<std::string>("robot_state_name", robot_state_name, "unique_robot_hw");
56 
57  try
58  {
59  robot_ = robot->getHandle(robot_state_name).getState();
60  }
62  {
63  ROS_ERROR_STREAM("Could not find robot state: " << robot_state_name << " Not loading the controller. " <<
64  e.what());
65  return false;
66  }
67 
68  node_ = n;
69 
70  if (!node_.getParam("joint", joint_name_))
71  {
72  ROS_ERROR("No joint given (namespace: %s)", node_.getNamespace().c_str());
73  return false;
74  }
75 
78  (node_, "state", 1));
79 
80  ROS_DEBUG(" --------- ");
81  ROS_DEBUG_STREAM("Init: " << joint_name_);
82 
83  // joint 0s e.g. FFJ0
84  has_j2 = is_joint_0();
85  if (has_j2)
86  {
88  if (!joint_state_)
89  {
90  ROS_ERROR("SrhJointMuscleValveController could not find the first joint relevant to \"%s\"\n",
91  joint_name_.c_str());
92  return false;
93  }
94  if (!joint_state_2)
95  {
96  ROS_ERROR("SrhJointMuscleValveController could not find the second joint relevant to \"%s\"\n",
97  joint_name_.c_str());
98  return false;
99  }
100  }
101  else
102  {
103  joint_state_ = robot_->getJointState(joint_name_);
104  if (!joint_state_)
105  {
106  ROS_ERROR("SrhJointMuscleValveController could not find joint named \"%s\"\n", joint_name_.c_str());
107  return false;
108  }
109  }
110 
112 
113  // serve_set_gains_ = node_.advertiseService("set_gains", &SrhJointMuscleValveController::setGains, this);
115 
116  ROS_DEBUG_STREAM(" joint_state name: " << joint_state_->joint_->name);
117  ROS_DEBUG_STREAM(" In Init: " << getJointName() << " This: " << this
118  << " joint_state: " << joint_state_);
119  // We do not call this function, as we want to listen to a different topic type
120  // after_init();
122  sr_robot_msgs::JointMuscleValveControllerCommand>("command", 1,
124  this);
125  return true;
126  }
127 
129  {
130  command_ = 0.0;
131  read_parameters();
132  }
133 
134  bool SrhJointMuscleValveController::resetGains(std_srvs::Empty::Request &req, std_srvs::Empty::Response &resp)
135  {
136  command_ = 0.0;
137 
138  read_parameters();
139 
140  if (has_j2)
142  "Reseting controller gains: " << joint_state_->joint_->name << " and " << joint_state_2->joint_->name);
143  else
144  ROS_WARN_STREAM("Reseting controller gains: " << joint_state_->joint_->name);
145 
146  return true;
147  }
148 
149  void SrhJointMuscleValveController::getGains(double &p, double &i, double &d, double &i_max, double &i_min)
150  {
151  }
152 
154  {
155  // The valve commands can have values between -4 and 4
156  int8_t valve[2];
157  unsigned int i;
158 
159  ROS_ASSERT(robot_ != NULL);
160  ROS_ASSERT(joint_state_->joint_);
161 
162  if (!initialized_)
163  {
164  initialized_ = true;
165  cmd_valve_muscle_[0] = 0.0;
166  cmd_valve_muscle_[1] = 0.0;
167  cmd_duration_ms_[0] = 0;
168  cmd_duration_ms_[1] = 0;
171  }
172 
173 
174  // IGNORE the following lines if we don't want to use the pressure sensors data
175  // We don't want to define a modified version of JointState, as that would imply
176  // using a modified version of robot_state.hpp, controller manager,
177  // ethercat_hardware and ros_etherCAT main loop
178  // So we heve encoded the two uint16 that contain the data from the muscle
179  // pressure sensors into the double effort_. (We don't
180  // have any measured effort in the muscle hand anyway).
181  // Here we extract the pressure values from joint_state_->effort_ and decode that back into uint16.
182  double pressure_0_tmp = fmod(joint_state_->effort_, 0x10000);
183  double pressure_1_tmp = (fmod(joint_state_->effort_, 0x100000000) - pressure_0_tmp) / 0x10000;
184  uint16_t pressure_0 = static_cast<uint16_t> (pressure_0_tmp + 0.5);
185  uint16_t pressure_1 = static_cast<uint16_t> (pressure_1_tmp + 0.5);
186 
187  // ****************************************
188 
189 
190 
191 
192 
193  // ************************************************
194  // Here goes the control algorithm
195 
196  // This controller will allow the user to specify a separate command for each
197  // of the two muscles that control the joint.
198  // The user will also specify a duration in ms for that command. During this
199  // duration the command will be sent to the hand
200  // every ms (every cycle of this 1Khz control loop).
201  // Once this duration period has elapsed, a command of 0 will be sent to
202  // the muscle (meaning both the filling and emptying valves for that
203  // muscle remain closed)
204  // A duration of 0 means that there is no timeout, so the valve command
205  // will be sent to the muscle until a different valve command is received
206  // BE CAREFUL WHEN USING A DURATION OF 0 AS THIS COULD EVENTUALLY DAMAGE THE MUSCLE
207 
208  for (i = 0; i < 2; ++i)
209  {
210  if (cmd_duration_ms_[i] == 0) // if the commanded duration is 0 it means that it will not timeout
211  {
212  // So we will use the last commanded valve command
213  valve[i] = cmd_valve_muscle_[i];
214  }
215  else
216  {
217  if (current_duration_ms_[i] > 0) // If the command has not timed out yet
218  {
219  // we will use the last commanded valve command
220  valve[i] = cmd_valve_muscle_[i];
221  // and decrement the counter. This is a milliseconds counter, and this loop is running once every millisecond
223  }
224  else // If the command has already timed out
225  {
226  // we will use 0 to close the valves
227  valve[i] = 0;
228  }
229  }
230  }
231 
232 
233  // ************************************************
234 
235 
236 
237 
238 
239 
240 
241  // ************************************************
242  // After doing any computation we consider, we encode the obtained valve
243  // commands into joint_state_->commanded_effort_
244  // We don't want to define a modified version of JointState, as that would
245  // imply using a modified version of robot_state.hpp, controller manager,
246  // ethercat_hardware and ros_etherCAT main loop
247  // So the controller encodes the two int8 (that are in fact int4) that contain
248  // the valve commands into the double commanded_effort_. (We don't
249  // have any real commanded_effort_ in the muscle hand anyway).
250 
251  uint16_t valve_tmp[2];
252  for (i = 0; i < 2; ++i)
253  {
254  // Check that the limits of the valve command are not exceded
255  if (valve[i] > 4)
256  {
257  valve[i] = 4;
258  }
259  if (valve[i] < -4)
260  {
261  valve[i] = -4;
262  }
263  // encode
264  if (valve[i] < 0)
265  {
266  valve_tmp[i] = -valve[i] + 8;
267  }
268  else
269  {
270  valve_tmp[i] = valve[i];
271  }
272  }
273 
274  // We encode the valve 0 command in the lowest "half byte" i.e. the lowest 16
275  // integer values in the double var (see decoding in simple_transmission_for_muscle.cpp)
276  // the valve 1 command is envoded in the next 4 bits
277  joint_state_->commanded_effort_ = static_cast<double> (valve_tmp[0]) + static_cast<double> (valve_tmp[1] << 4);
278 
279  // *******************************************************************************
280 
281 
282 
283 
284  if (loop_count_ % 10 == 0)
285  {
287  {
288  controller_state_publisher_->msg_.header.stamp = time;
289 
290  controller_state_publisher_->msg_.set_valve_muscle_0 = cmd_valve_muscle_[0];
291  controller_state_publisher_->msg_.set_valve_muscle_1 = cmd_valve_muscle_[1];
292  controller_state_publisher_->msg_.set_duration_muscle_0 = cmd_duration_ms_[0];
293  controller_state_publisher_->msg_.set_duration_muscle_1 = cmd_duration_ms_[1];
294  controller_state_publisher_->msg_.current_valve_muscle_0 = valve[0];
295  controller_state_publisher_->msg_.current_valve_muscle_1 = valve[1];
296  controller_state_publisher_->msg_.current_duration_muscle_0 = current_duration_ms_[0];
297  controller_state_publisher_->msg_.current_duration_muscle_1 = current_duration_ms_[1];
298  controller_state_publisher_->msg_.packed_valve = joint_state_->commanded_effort_;
299  controller_state_publisher_->msg_.muscle_pressure_0 = pressure_0;
300  controller_state_publisher_->msg_.muscle_pressure_1 = pressure_1;
301  controller_state_publisher_->msg_.time_step = period.toSec();
302 
303  controller_state_publisher_->unlockAndPublish();
304  }
305  }
306  loop_count_++;
307  }
308 
310  {
311  }
312 
313  void SrhJointMuscleValveController::setCommandCB(const sr_robot_msgs::JointMuscleValveControllerCommandConstPtr &msg)
314  {
315  cmd_valve_muscle_[0] = clamp_command(msg->cmd_valve_muscle[0]);
316  cmd_valve_muscle_[1] = clamp_command(msg->cmd_valve_muscle[1]);
317  // These variables hold the commanded duration
318  cmd_duration_ms_[0] = static_cast<unsigned int> (msg->cmd_duration_ms[0]);
319  cmd_duration_ms_[1] = static_cast<unsigned int> (msg->cmd_duration_ms[1]);
320  // These are the actual counters that we will decrement
323  }
324 
326 
328  {
329  if (cmd < cmd_valve_muscle_min_)
330  {
331  return cmd_valve_muscle_min_;
332  }
333 
334  if (cmd > cmd_valve_muscle_max_)
335  {
336  return cmd_valve_muscle_max_;
337  }
338 
339  return cmd;
340  }
341 } // namespace controller
342 
343 /* For the emacs weenies in the crowd.
344 Local Variables:
345  c-basic-offset: 2
346 End:
347  */
ros_ethercat_model::JointState * joint_state_
virtual bool resetGains(std_srvs::Empty::Request &req, std_srvs::Empty::Response &resp)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
int8_t clamp_command(int8_t cmd)
enforce that the value of the received command is in the allowed range
virtual void getGains(double &p, double &i, double &d, double &i_max, double &i_min)
void read_parameters()
read all the controller settings from the parameter server
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
ros_ethercat_model::JointState * joint_state_2
Compute an effort demand from the effort error. As the effort PID loop is running on the motor boards...
boost::scoped_ptr< sr_friction_compensation::SrFrictionCompensator > friction_compensator
ros_ethercat_model::RobotState * robot_
bool param(const std::string &param_name, T &param_val, const T &default_val) const
const std::string & getNamespace() const
boost::shared_ptr< realtime_tools::RealtimePublisher< sr_robot_msgs::JointMuscleValveControllerState > > controller_state_publisher_
#define ROS_WARN_STREAM(args)
#define ROS_DEBUG_STREAM(args)
void setCommandCB(const sr_robot_msgs::JointMuscleValveControllerCommandConstPtr &msg)
bool getParam(const std::string &key, std::string &s) const
bool init(ros_ethercat_model::RobotStateInterface *robot, ros::NodeHandle &n)
#define ROS_ERROR_STREAM(args)
#define ROS_ASSERT(cond)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
#define ROS_ERROR(...)
ros::ServiceServer serve_reset_gains_
#define ROS_DEBUG(...)
virtual void update(const ros::Time &time, const ros::Duration &period)
Issues commands to the joint. Should be called at regular intervals.


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