odom_control.cpp
Go to the documentation of this file.
1 #include <ctime>
2 #include <vector>
3 #include <string>
4 #include <cmath>
5 #include <fstream>
6 #include <iostream>
7 #include "ros/ros.h"
8 
11 
12 namespace openrover
13 {
14 void OdomControl::start(bool use_control, PidGains pid_gains, int max, int min)
15 {
16  K_P_ = pid_gains.Kp;
17  K_I_ = pid_gains.Ki;
18  K_D_ = pid_gains.Kd;
19 }
20 
24  , MOTOR_DEADBAND_(9)
25  , MAX_ACCEL_CUTOFF_(5.0)
26  , MIN_VELOCITY_(0.03)
27  , MAX_VELOCITY_(5)
28  , fs_(nullptr)
29  , K_P_(0)
30  , K_I_(0)
31  , K_D_(0)
33  , velocity_history_(3, 0)
34  , use_control_(false)
35  , skip_measurement_(false)
36  , at_max_motor_speed_(false)
37  , at_min_motor_speed_(false)
38  , stop_integrating_(false)
39  , velocity_error_(0)
40  , integral_error_(0)
45 {
46 }
47 
48 OdomControl::OdomControl(bool use_control, PidGains pid_gains, int max, int min, std::ofstream* fs)
49  : MOTOR_MAX_(max)
50  , MOTOR_MIN_(min)
51  , MOTOR_DEADBAND_(9)
52  , MAX_ACCEL_CUTOFF_(5.0)
53  , MIN_VELOCITY_(0.03)
54  , MAX_VELOCITY_(3)
55  , fs_(fs)
56  , K_P_(pid_gains.Kp)
57  , K_I_(pid_gains.Ki)
58  , K_D_(pid_gains.Kd)
60  , velocity_history_(3, 0)
61  , use_control_(use_control)
62  , skip_measurement_(false)
63  , at_max_motor_speed_(false)
64  , at_min_motor_speed_(false)
65  , stop_integrating_(false)
66  , velocity_error_(0)
67  , integral_error_(0)
72 {
73 
74  if (fs_ != nullptr && fs_->is_open()) {
75  *fs_ << "time,Kp,Ki,Kd,error,integral_error,differential_error,error_filtered,meas_vel,filt_vel,cmd_vel,dt,motor_cmd\n";
76  fs_->flush();
77  }
78 }
79 
80 OdomControl::OdomControl(bool use_control, PidGains pid_gains, int max, int min)
81  : MOTOR_MAX_(max)
82  , MOTOR_MIN_(min)
83  , MOTOR_DEADBAND_(9)
84  , MAX_ACCEL_CUTOFF_(5.0)
85  , MIN_VELOCITY_(0.03)
86  , MAX_VELOCITY_(3)
87  , fs_(nullptr)
88  , K_P_(pid_gains.Kp)
89  , K_I_(pid_gains.Ki)
90  , K_D_(pid_gains.Kd)
92  , velocity_history_(3, 0)
93  , use_control_(use_control)
94  , skip_measurement_(false)
95  , at_max_motor_speed_(false)
96  , at_min_motor_speed_(false)
97  , stop_integrating_(false)
98  , velocity_error_(0)
99  , integral_error_(0)
102  , velocity_measured_(0)
103  , velocity_filtered_(0)
104 {
105  ROS_INFO("odom Kp: %f", K_P_);
106  ROS_INFO("odom Ki: %f", K_I_);
107  ROS_INFO("odom Kd: %f", K_D_);
108 }
109 
110 unsigned char OdomControl::run(bool e_stop_on, bool control_on, double commanded_vel, double measured_vel, double dt, int firmwareBuildNumber)
111 {
112  velocity_commanded_ = commanded_vel;
113 
114  velocity_measured_ = measured_vel;
115 
116  /*
117  Truncate the last two digits of the firmware version number,
118  which returns in the format aabbcc. We divide by 100 to truncate
119  cc since we don't care about the PATCH field of semantic versioning
120  */
121  int firmwareBuildNumberTrunc = firmwareBuildNumber / 100;
122 
123  velocity_filtered_ = filter(measured_vel, dt, firmwareBuildNumberTrunc);
124 
125  //If rover is E-Stopped, respond with NEUTRAL comman
126  if (e_stop_on)
127  {
128  reset();
129  return MOTOR_NEUTRAL;
130  }
131 
132  // If stopping, stop now when velocity has slowed.
133  if ((commanded_vel == 0.0) && (fabs(velocity_filtered_)<0.3))
134  {
135  integral_error_ = 0;
137  {
138  return MOTOR_NEUTRAL;
139  }
140  }
141 
142  // If controller should be ON, run it.
143  if (control_on)
144  {
145  velocity_error_ = commanded_vel - velocity_filtered_;
146  if (!skip_measurement_)
147  {
149  ROS_DEBUG("PID: %i", motor_speed_);
150  }
151  }
152  else
153  {
155  }
156 
158 
159  if (fs_ != nullptr && fs_->is_open()){
160  *fs_ << ros::Time::now() << ",";
161  *fs_ << K_P_ << "," << K_I_ << "," << K_D_ << ",";
162  *fs_ << commanded_vel - measured_vel << "," << integral_error_ << "," << differential_error_<< "," << velocity_error_ << ",";
163  *fs_ << measured_vel << "," << velocity_filtered_ << "," << commanded_vel << ",";
164  *fs_ << dt << "," << motor_speed_ << "\n";
165  fs_->flush();
166  }
167 
168  return (unsigned char)motor_speed_;
169 }
170 
172 {
173  return (int)round(velocity_commanded_ * 50 + MOTOR_NEUTRAL);
174 }
175 
177 {
178  integral_error_ = 0;
179  velocity_error_ = 0;
181  velocity_measured_ = 0;
182  velocity_filtered_ = 0;
183  std::fill(velocity_filtered_history_.begin(), velocity_filtered_history_.end(), 0);
185  skip_measurement_ = false;
186 }
187 
188 int OdomControl::PID(double error, double dt)
189 {
190  double p_val = P(error, dt);
191  double i_val = I(error, dt);
192  double d_val = D(error, dt);
193  double pid_val = p_val + i_val + d_val;
194  ROS_DEBUG("\nerror: %lf\n dt: %lf", error, dt);
195  ROS_DEBUG("\n kp: %lf \n ki: %lf \n kd: %lf \n", p_val, i_val, d_val);
196 
197  if (fabs(pid_val) > (MOTOR_MAX_/2.0))
198  //Only integrate if the motor's aren't already at full speed
199  {
200  stop_integrating_ = true;
201  }
202  else
203  {
204  stop_integrating_ = false;
205  }
206 
207  return (int)round(pid_val + 125.0);
208 }
209 
210 double OdomControl::D(double error, double dt)
211 {
213  return K_D_ * differential_error_;
214 }
215 
216 double OdomControl::I(double error, double dt)
217 {
218  if (!stop_integrating_)
219  {
220  integral_error_ += error * dt;
221  }
222  return K_I_ * integral_error_;
223 }
224 
225 double OdomControl::P(double error, double dt)
226 {
227  double p_val = error * K_P_;
228  return error * K_P_;
229 }
230 
231 bool OdomControl::hasZeroHistory(const std::vector<double>& vel_history)
232 {
233  double avg = (fabs(vel_history[0]) + fabs(vel_history[1]) + fabs(vel_history[2])) / 3.0;
234  if (avg < 0.03)
235  return true;
236  else
237  return false;
238 }
239 
240 int OdomControl::boundMotorSpeed(int motor_speed, int max, int min)
241 {
242  int test_motor;
243  int test_factor = 18;
244  at_max_motor_speed_ = false;
245  at_min_motor_speed_ = false;
246 
247  if (motor_speed > max)
248  {
249  motor_speed = max;
250  at_max_motor_speed_ = true;
251  }
252  if (motor_speed < min)
253  {
254  motor_speed = min;
255  at_min_motor_speed_ = true;
256  }
257 
258  test_motor = motor_speed;
259 
260  return test_motor;
261 }
262 
263 int OdomControl::deadbandOffset(int motor_speed, int deadband_offset)
264 {
265  // Compensate for deadband
266  if (motor_speed > MOTOR_NEUTRAL)
267  {
268  return (motor_speed + deadband_offset);
269  }
270  else if (motor_speed < MOTOR_NEUTRAL)
271  {
272  return (motor_speed - deadband_offset);
273  }
274 }
275 
276 double OdomControl::filter(double velocity, double dt, int firmwareBuildNumber)
277 {
278  static double time = 0;
279 
280  // Check for impossible acceleration, if it is impossible, ignore the measurement.
281  float accel = (velocity - velocity_filtered_history_[0]) / dt;
282  velocity_history_.insert(velocity_history_.begin(), velocity);
283  velocity_history_.pop_back();
284 
285  if(firmwareBuildNumber == BUILD_NUMBER_WITH_GOOD_RPM_DATA){
286  velocity_filtered_ = 0.9 * velocity + 0.1 * velocity_filtered_history_[0];
287 
288  }
289  else{
290  float change_in_velocity = 0;
291 
292  if (accel > MAX_ACCEL_CUTOFF_)
293  {
294  change_in_velocity = 0.5*dt*MAX_ACCEL_CUTOFF_;
295  velocity = velocity_filtered_history_[0] + change_in_velocity;
296  }
297  else if (accel < -MAX_ACCEL_CUTOFF_)
298  {
299  change_in_velocity = -0.5*dt*MAX_ACCEL_CUTOFF_;
300  velocity = velocity_filtered_history_[0] + change_in_velocity;
301  }
302 
304 
305  }
306 
308  velocity_filtered_history_.pop_back();
309 
310  return velocity_filtered_;
311 }
312 
313 
314 } // namespace openrover
bool hasZeroHistory(const std::vector< double > &vel_history)
int deadbandOffset(int motor_speed, int deadband_offset)
double D(double error, double dt)
std::vector< double > velocity_history_
int PID(double error, double dt)
int boundMotorSpeed(int motor_speed, int max, int min)
double I(double error, double dt)
const int MOTOR_SPEED_MAX
Definition: constants.hpp:64
#define ROS_INFO(...)
void start(bool use_control, PidGains pid_gains, int max, int min)
const int MOTOR_NEUTRAL
Definition: constants.hpp:63
std::vector< double > velocity_filtered_history_
double P(double error, double dt)
std::ofstream * fs_
double filter(double left_motor_vel, double dt, int firmwareBuildNumber)
static Time now()
const int BUILD_NUMBER_WITH_GOOD_RPM_DATA
Definition: constants.hpp:7
const int MOTOR_SPEED_MIN
Definition: constants.hpp:65
unsigned char run(bool e_stop_on, bool control_on, double commanded_vel, double measured_vel, double dt, int firmwareBuildNumber)
#define ROS_DEBUG(...)


rr_openrover_driver
Author(s): Jack Kilian
autogenerated on Mon Feb 28 2022 23:43:54