controller.cpp
Go to the documentation of this file.
1 
25 
28 
29  //Assume no messages are being received. Don't send out anything new until commands are received
31 
32  ros::NodeHandle prv_node_("~");
33 
35  is_active_control = false;
36 
37  //Timeouts for sensors
38  //if no data has been received in a while, disable certain PID controls
39  prv_node_.param<double>("imu_data_timeout", imu_data_timeout_, 1/5.0);
40  imu_data_time_ = 0;
41  imu_timeout_ = true;
42 
43  prv_node_.param<double>("vel_data_timeout", vel_data_timeout_, 1/5.0);
44  vel_data_time_ = 0;
45  vel_timeout_ = true;
46 
47  //Timeouts for control formats
48  //if no command has been received in a while, stop sending drive commands
49  prv_node_.param<double>("course_cmd/timeout",course_cmd_timeout_,0.5);
50  course_cmd_time_ = 0;
51 
52  prv_node_.param<double>("helm_cmd/timeout", helm_cmd_timeout_,0.5);
53  helm_cmd_time_ = 0;
54 
55  prv_node_.param<double>("wrench_cmd/timeout",wrench_cmd_timeout_,0.5);
56  wrench_cmd_time_ = 0;
57 
58  prv_node_.param<double>("twist_cmd/timeout",twist_cmd_timeout_,0.5);//If the commands dont show up in this much time don't send out drive commands
59  twist_cmd_time_ = 0;
60 
61  //Setup Fwd Vel Controller
62  fvel_dbg_pub_ = node_.advertise<geometry_msgs::Vector3>("fwd_vel_debug",1000);
63  prv_node_.param<double>("fwd_vel/kf", fvel_kf_,10); //Feedforward Gain
64  prv_node_.param<double>("fwd_vel/kp", fvel_kp_,90.0); //Proportional Gain
65  prv_node_.param<double>("fwd_vel/kd", fvel_kd_,1.0); //Derivative Gain
66  prv_node_.param<double>("fwd_vel/ki", fvel_ki_,0.0); //Integral Gain
67  prv_node_.param<double>("fwd_vel/imax", fvel_imax_,0.0); //Clamp Integral Outputs
68  prv_node_.param<double>("fwd_vel/imin", fvel_imin_,0.0);
69  fvel_meas_ = 0;
70 
71  //Setup Yaw Rate Controller
72  yr_dbg_pub_ = node_.advertise<geometry_msgs::Vector3>("yaw_rate_debug",1000);
73  prv_node_.param<double>("yaw_rate/kf", yr_kf_,10); //Feedforward Gain
74  prv_node_.param<double>("yaw_rate/kp", yr_kp_,2.0); //Proportional Gain
75  prv_node_.param<double>("yaw_rate/kd", yr_kd_,1.0); //Derivative Gain
76  prv_node_.param<double>("yaw_rate/ki", yr_ki_,0.0); //Integral Gain
77  prv_node_.param<double>("yaw_rate/imax", yr_imax_,0.0); //Clamp Integral Outputs
78  prv_node_.param<double>("yaw_rate/imin", yr_imin_,0.0);
79  yr_meas_ = 0;
80 
81  //Setup Yaw Controller
82  y_dbg_pub_ = node_.advertise<geometry_msgs::Vector3>("yaw_debug",1000);
83 
84  prv_node_.param<double>("yaw/kp", y_kf_,5.0);
85  prv_node_.param<double>("yaw/kp", y_kp_,5.0);
86  prv_node_.param<double>("yaw/kd", y_kd_,1.0);
87  prv_node_.param<double>("yaw/ki", y_ki_,0.5);
88  prv_node_.param<double>("yaw/imax", y_imax_,0.0); //clamp integral output at max yaw yorque
89  prv_node_.param<double>("yaw/imin", y_imin_,0.0);
90  y_meas_ = 0;
91 
92  ROS_DEBUG("Fwd Vel Params (F,P,I,D,iMax,iMin):%f,%f,%f,%f,%f,%f",fvel_kf_,fvel_kp_, fvel_ki_,fvel_kd_,fvel_imax_,fvel_imin_);
93  ROS_DEBUG("Yaw Rate Params (F,P,I,D,iMax,iMin):%f,%f,%f,%f,%f,%f",yr_kf_,yr_kp_, yr_ki_,yr_kd_,yr_imax_,yr_imin_);
94  ROS_DEBUG("Yaw Params (F,P,I,D,iMax,iMin):%f,%f,%f,%f,%f,%f",y_kf_,y_kp_, y_ki_,y_kd_,y_imax_,y_imin_);
95 
96 
97  fvel_pid_.reset();
98  fvel_pid_.initPid(fvel_kp_,fvel_ki_,fvel_kd_,fvel_imax_,fvel_imin_);
99  fvel_cmd_ = 0;
100 
101  yr_pid_.reset();
102  yr_pid_.initPid(yr_kp_,yr_ki_,yr_kd_,yr_imax_,yr_imin_);
103  yr_cmd_ = 0;
104 
105  //Setup Yaw Controller
106  y_pid_.reset();
107  y_pid_.initPid(y_kp_,y_ki_,y_kd_,y_imax_,y_imin_);
108  y_cmd_ = 0;
109 
110  prv_node_.param<double>("max/fwd_vel", max_fwd_vel_,MAX_FWD_VEL);
111  prv_node_.param<double>("max/fwd_force", max_fwd_force_,2*MAX_FWD_THRUST); //2 thrusters
112  prv_node_.param<double>("max/bck_vel",max_bck_vel_,MAX_BCK_VEL);
113  prv_node_.param<double>("max/bck_force",max_bck_force_,2*MAX_BCK_THRUST);
114 
115  prv_node_.param<double>("cov_limits/velocity", vel_cov_limit_, 0.28);
116  prv_node_.param<double>("cov_limits/imu", imu_cov_limit_, 1.0);
117 
118  force_output_.force.x = 0;
119  force_output_.force.y = 0;
120  force_output_.force.z = 0;
121 
122  force_output_.torque.x = 0;
123  force_output_.torque.y = 0;
124  force_output_.torque.z = 0;
125 
126 }
127 
129  //calculate pid force X
130  double fvel_error = fvel_cmd_ - fvel_meas_;
131  double fvel_comp_output = fvel_pid_.computeCommand(fvel_error, ros::Duration(1/20.0));
132  fvel_comp_output = fvel_comp_output + fvel_kf_*fvel_cmd_;
133 
134  geometry_msgs::Vector3 dbg_info;
135  dbg_info.x = fvel_cmd_;
136  dbg_info.y = fvel_meas_;
137  dbg_info.z = fvel_comp_output;
138  fvel_dbg_pub_.publish(dbg_info);
139 
140  return fvel_comp_output;
141 }
142 
144  //calculate pid torque z
145  double yr_error = yr_cmd_ - yr_meas_;
146  double yr_comp_output = yr_pid_.computeCommand(yr_error, ros::Duration(1/20.0));
147  yr_comp_output = yr_comp_output + yr_kf_*yr_cmd_; //feedforward
148 
149  geometry_msgs::Vector3 dbg_info;
150  dbg_info.x = yr_cmd_;
151  dbg_info.y = yr_meas_;
152  dbg_info.z = yr_comp_output;
153  yr_dbg_pub_.publish(dbg_info);
154 
155  return yr_comp_output;
156 }
157 
159  //calculate pid torque z
160 
161  if (y_meas_ < 0)
162  y_meas_ = y_meas_ + 2*PI;
163 
164  double y_error = y_cmd_ - y_meas_;
165 
166  if (fabs(y_error) > PI){
167  if (y_cmd_ > PI) //presumably y_meas_ < PI
168  y_error =-( y_meas_ + (2*PI - y_cmd_));
169  else //y_cmd_ < pi, y_meas > pi
170  y_error = y_cmd_ + (2*PI - y_meas_);
171  }
172 
173  double y_comp_output = y_pid_.computeCommand(y_error, ros::Duration(1/20.0));
174 
175  geometry_msgs::Vector3 dbg_info;
176  dbg_info.x = y_cmd_;
177  dbg_info.y = y_meas_;
178  dbg_info.z = y_comp_output;
179  y_dbg_pub_.publish(dbg_info);
180 
181  return y_comp_output;
182 }
183 
184 double deadzone_force(double force, double pos_limit, double neg_limit) {
185  if (force > 0) {
186  if (force < pos_limit) {
187  return 0;
188  }//if
189  } else {
190  if (force > -neg_limit) {
191  return 0;
192  }//if
193  }//else
194 
195  return force;
196 }
197 
199  if (fvel_cmd_ > 0) {
201  } else {
203  }//else
204 }//fwd_vel_mapping
205 
208 }
209 
211  force_output_.torque.z = deadzone_force(yr_compensator(), 2, 2);
212 }
213 
216  force_output_.torque.z = deadzone_force(yr_compensator(), 2, 2);
217 }
218 
219 //Callback to receive twist msgs (cmd_vel style)
220 void Controller::twist_callback(const geometry_msgs::Twist msg) {
221  yr_cmd_ = msg.angular.z;
223 
224  fvel_cmd_ = msg.linear.x;
225 
227  fwd_vel_mapping();
228  } else {
230  }
231 
233 }//twist_callback
234 
235 
236 //Callback to receive raw wrench commands (force along x axis and torque about z axis).
237 void Controller::wrench_callback(const geometry_msgs::Wrench msg) {
238  force_output_.force.x = msg.force.x;
239  force_output_.torque.z = msg.torque.z;
241 }
242 
243 //Callback for yaw command which receives a yaw (rad) and speed (m/s) command
244 void Controller::course_callback(const heron_msgs::Course msg) {
245  //Save Yaw Command and process it
246  y_cmd_ = msg.yaw;
248 
249  // Calculate speed command
250  fvel_cmd_ = msg.speed;
252 
254 }
255 
256 //Callback for helm commands which receives a thrust percentage (0..1) and a yaw rate (rad/s)
257 void Controller::helm_callback(const heron_msgs::Helm msg) {
258  //Basic Helm Control
259 
260  //Calculate Thrust control
261  double thrust = msg.thrust;
262  if (thrust >= 0)
263  force_output_.force.x = thrust * (max_fwd_force_/1);
264  else
265  force_output_.force.x = thrust * (max_bck_force_/1);
266 
267  //Save yaw rate command to be processed when feedback is available
268  yr_cmd_ = msg.yaw_rate;
270 
272 }
273 
274 //ENU
275 void Controller::odom_callback(const nav_msgs::Odometry msg) {
276 
277  //check if navsat/vel is being integrated into odometry
278  if (msg.twist.covariance[0] < vel_cov_limit_ && msg.twist.covariance[7] < vel_cov_limit_) {
280  }//if
281 
282  //check if imu/data is being integrated into odometry
283  if (msg.pose.covariance[35] < imu_cov_limit_ && msg.twist.covariance[35] < imu_cov_limit_) {
285  }//if
286 
287  y_meas_ = tf::getYaw(msg.pose.pose.orientation);
288  yr_meas_ = msg.twist.twist.angular.z;
289  fvel_meas_ = msg.twist.twist.linear.x * std::cos(y_meas_) + msg.twist.twist.linear.y * std::sin(y_meas_);
290 
291  switch (control_mode) {
292  case COURSE_CONTROL:
295  break;
296  case HELM_CONTROL:
298  break;
299  case WRENCH_CONTROL:
300  break;
301  case TWIST_CONTROL:
304  break;
305  case TWIST_LIN_CONTROL:
307  break;
308  case NO_CONTROL:
309  break;
310  }//switch
311 }//odom_callback
312 
313 
315 
316  std::string output="";
317  switch (control_mode)
318  {
319  case COURSE_CONTROL:
320  output = "Boat controlling yaw position";
321  break;
322  case HELM_CONTROL:
323  output = "Boat Controlling yaw rate";
324  break;
325  case WRENCH_CONTROL:
326  output = "Boat in raw wrench/RC control";
327  break;
328  case TWIST_CONTROL:
329  output = "Boat controlling forward and yaw velocity";
330  break;
331  case TWIST_LIN_CONTROL:
332  output = "Boat controlling yaw velocity and mapping velocity linearly";
333  break;
334  case NO_CONTROL:
335  output = "No commands being processed";
336  break;
337  default:
338  break;
339  }
340 
341  if (imu_timeout_)
342  output+=": IMU data not received or being received too slowly";
343 
344  if (vel_timeout_)
345  output+=": GPS Velocity data not received or being received too slowly";
346 
347  ROS_INFO("%s",output.c_str());
348 }
349 
351 
352  if (ros::Time::now().toSec() - imu_data_time_ > imu_data_timeout_) {
353  imu_timeout_ = true;
354  } else {
355  imu_timeout_ = false;
356  }//else
357 
358  if (ros::Time::now().toSec() - vel_data_time_ > vel_data_timeout_) {
359  vel_timeout_ = true;
360  } else {
361  vel_timeout_ = false;
362  }//else
363 
364  if (is_active_control) {
365  std::vector<double> find_latest;
366 
367  if (!imu_timeout_) {
368  find_latest.push_back(twist_cmd_time_);
369  find_latest.push_back(helm_cmd_time_);
370  }//if
371 
372  if (!imu_timeout_ && !vel_timeout_) {
373  find_latest.push_back(course_cmd_time_);
374  }//if
375 
376  find_latest.push_back(wrench_cmd_time_);
377  double max = *std::max_element(find_latest.begin(), find_latest.end());
378 
379  if (max == 0) {
381  force_output_.torque.z = 0;
382  force_output_.force.x = 0;
383  return;
384  } else if (max == twist_cmd_time_ && !imu_timeout_ && !vel_timeout_) {
386  } else if (max == twist_cmd_time_ && !imu_timeout_) {
388  } else if (max == course_cmd_time_ && !imu_timeout_ && !vel_timeout_) {
390  } else if(max == helm_cmd_time_ && !imu_timeout_) {
392  } else if(max == wrench_cmd_time_) {
394  }//elseif
395  } else {
406  } else {
408  force_output_.torque.z = 0;
409  force_output_.force.x = 0;
410  return;
411  }//else
412  }//else
413 
415 }
416 
417 bool Controller::activate_control_service(std_srvs::SetBool::Request& req,
418  std_srvs::SetBool::Response& resp) {
419  is_active_control = req.data;
420  resp.success = is_active_control;
421  resp.message = "Activated Control.";
422  return true;
423 }
424 
425 int main(int argc, char **argv)
426 {
427  ros::init(argc,argv, "controller");
428  ros::NodeHandle nh;
429  Controller heron_control(nh);
430 
431  ros::Subscriber twist_sub = nh.subscribe("cmd_vel",1,&Controller::twist_callback, &heron_control);
432  ros::Subscriber wrench_sub = nh.subscribe("cmd_wrench",1, &Controller::wrench_callback, &heron_control);
433  ros::Subscriber helm_sub = nh.subscribe("cmd_helm",1, &Controller::helm_callback,&heron_control);
434  ros::Subscriber course_sub = nh.subscribe("cmd_course",1, &Controller::course_callback,&heron_control);
435 
436  ros::Subscriber odom_sub = nh.subscribe("odometry/filtered",1, &Controller::odom_callback, &heron_control);
437 
438  ros::Timer control_output = nh.createTimer(ros::Duration(1/50.0), &Controller::control_update,&heron_control);
440 
441  ros::spin();
442 
443  return 0;
444 }
double y_kp_
Definition: controller.h:75
#define TWIST_LIN_CONTROL
void pub_thrust_cmd(geometry_msgs::Wrench output)
int control_mode
Definition: controller.h:81
#define MAX_FWD_THRUST
void twist_callback(const geometry_msgs::Twist msg)
Definition: controller.cpp:220
double yr_kd_
Definition: controller.h:69
ForceCompensator * force_compensator_
Definition: controller.h:44
void publish(const boost::shared_ptr< M > &message) const
void console_update(const ros::TimerEvent &event)
Definition: controller.cpp:314
control_toolbox::Pid fvel_pid_
Definition: controller.h:61
ros::Publisher yr_dbg_pub_
Definition: controller.h:68
void fwd_vel_mapping()
Definition: controller.cpp:198
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void wrench_callback(const geometry_msgs::Wrench msg)
Definition: controller.cpp:237
double imu_data_time_
Definition: controller.h:52
static double getYaw(const Quaternion &bt_q)
double fvel_kf_
Definition: controller.h:63
double fvel_ki_
Definition: controller.h:63
void update_fwd_vel_control()
Definition: controller.cpp:206
double y_meas_
Definition: controller.h:76
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
double yr_imax_
Definition: controller.h:69
#define MAX_FWD_VEL
double y_kf_
Definition: controller.h:75
#define WRENCH_CONTROL
#define NO_CONTROL
double fvel_imin_
Definition: controller.h:63
Controller(ros::NodeHandle &n)
Definition: controller.cpp:26
void update_yaw_control()
Definition: controller.cpp:214
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
bool activate_control_service(std_srvs::SetBool::Request &req, std_srvs::SetBool::Response &resp)
Definition: controller.cpp:417
double imu_cov_limit_
Definition: controller.h:52
double max_fwd_vel_
Definition: controller.h:79
double y_kd_
Definition: controller.h:75
double fvel_meas_
Definition: controller.h:64
ROSCPP_DECL void spin(Spinner &spinner)
geometry_msgs::Wrench force_output_
Definition: controller.h:45
control_toolbox::Pid y_pid_
Definition: controller.h:73
double yr_kf_
Definition: controller.h:69
#define PI
void initPid(double p, double i, double d, double i_max, double i_min, bool antiwindup=false)
double vel_data_timeout_
Definition: controller.h:48
double y_ki_
Definition: controller.h:75
double yr_ki_
Definition: controller.h:69
double y_compensator()
Definition: controller.cpp:158
ros::Publisher y_dbg_pub_
Definition: controller.h:74
ros::Publisher fvel_dbg_pub_
Definition: controller.h:62
void course_callback(const heron_msgs::Course msg)
Definition: controller.cpp:244
double computeCommand(double error, ros::Duration dt)
bool is_active_control
Definition: controller.h:84
#define ROS_INFO(...)
double y_imax_
Definition: controller.h:75
bool param(const std::string &param_name, T &param_val, const T &default_val) const
double wrench_cmd_timeout_
Definition: controller.h:58
double fvel_compensator()
Definition: controller.cpp:128
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
double twist_cmd_timeout_
Definition: controller.h:59
double y_cmd_
Definition: controller.h:76
double deadzone_force(double force, double pos_limit, double neg_limit)
Definition: controller.cpp:184
double course_cmd_time_
Definition: controller.h:56
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
double yr_meas_
Definition: controller.h:70
void odom_callback(const nav_msgs::Odometry msg)
Definition: controller.cpp:275
double vel_data_time_
Definition: controller.h:48
double max_fwd_force_
Definition: controller.h:79
double fvel_imax_
Definition: controller.h:63
double helm_cmd_time_
Definition: controller.h:57
double wrench_cmd_time_
Definition: controller.h:58
double yr_imin_
Definition: controller.h:69
double max_bck_force_
Definition: controller.h:79
double twist_cmd_time_
Definition: controller.h:59
control_toolbox::Pid yr_pid_
Definition: controller.h:67
double yr_kp_
Definition: controller.h:69
#define COURSE_CONTROL
double fvel_cmd_
Definition: controller.h:64
ros::NodeHandle node_
Definition: controller.h:43
double imu_data_timeout_
Definition: controller.h:52
void update_yaw_rate_control()
Definition: controller.cpp:210
bool vel_timeout_
Definition: controller.h:49
double y_imin_
Definition: controller.h:75
static Time now()
double yr_compensator()
Definition: controller.cpp:143
int main(int argc, char **argv)
Definition: controller.cpp:425
#define HELM_CONTROL
double fvel_kd_
Definition: controller.h:63
ros::ServiceServer active_control_srv
Definition: controller.h:83
double course_cmd_timeout_
Definition: controller.h:56
void helm_callback(const heron_msgs::Helm msg)
Definition: controller.cpp:257
void control_update(const ros::TimerEvent &event)
Definition: controller.cpp:350
#define MAX_BCK_VEL
#define MAX_BCK_THRUST
double max_bck_vel_
Definition: controller.h:79
double yr_cmd_
Definition: controller.h:70
bool imu_timeout_
Definition: controller.h:53
double fvel_kp_
Definition: controller.h:63
double helm_cmd_timeout_
Definition: controller.h:57
double vel_cov_limit_
Definition: controller.h:48
#define TWIST_CONTROL
#define ROS_DEBUG(...)


heron_controller
Author(s): Prasenjit Mukherjee
autogenerated on Sun Mar 14 2021 02:31:50