00001
00036
00037
00038
00039 #include <pid/controller.h>
00040
00041 using namespace pid;
00042
00043 void setpoint_callback(const std_msgs::Float64& setpoint_msg)
00044 {
00045 setpoint = setpoint_msg.data;
00046 }
00047
00048 void plant_state_callback(const std_msgs::Float64& state_msg)
00049 {
00050
00051 if ( !((Kp<=0. && Ki<=0. && Kd<=0.) || (Kp>=0. && Ki>=0. && Kd>=0.)) )
00052 {
00053 ROS_WARN("All three gains (Kp, Ki, Kd) should have the same sign for stability.");
00054 }
00055
00056 plant_state = state_msg.data;
00057
00058 error.at(2) = error.at(1);
00059 error.at(1) = error.at(0);
00060 error.at(0) = setpoint - plant_state;
00061
00062
00063
00064 if (angle_error)
00065 {
00066 while (error.at(0) < -1.0*angle_wrap/2.0)
00067 {
00068 error.at(0) += angle_wrap;
00069 }
00070 while (error.at(0) > angle_wrap/2.0)
00071 {
00072 error.at(0) -= angle_wrap;
00073 }
00074
00075
00076
00077 error.at(2) = 0.;
00078 error.at(1) = 0.;
00079 error_integral = 0.;
00080 }
00081
00082
00083 if (!prev_time.isZero())
00084 {
00085 delta_t = ros::Time::now() - prev_time;
00086 prev_time = ros::Time::now();
00087 if (0 == delta_t.toSec())
00088 {
00089 ROS_ERROR("delta_t is 0, skipping this loop. Possible overloaded cpu at time: %f", ros::Time::now().toSec());
00090 return;
00091 }
00092 }
00093 else
00094 {
00095 ROS_INFO("prev_time is 0, doing nothing");
00096 prev_time = ros::Time::now();
00097 return;
00098 }
00099
00100
00101 error_integral += error.at(0) * delta_t.toSec();
00102
00103
00104 if ( error_integral > fabsf(windup_limit))
00105 error_integral = fabsf(windup_limit);
00106
00107 if ( error_integral < -fabsf(windup_limit))
00108 error_integral = -fabsf(windup_limit);
00109
00110
00111 if (cutoff_frequency != -1)
00112 {
00113
00114 tan_filt = tan( (cutoff_frequency*6.2832)*delta_t.toSec()/2 );
00115
00116
00117 if ( (tan_filt<=0.) && (tan_filt>-0.01) )
00118 tan_filt = -0.01;
00119 if ( (tan_filt>=0.) && (tan_filt<0.01) )
00120 tan_filt = 0.01;
00121
00122 c = 1/tan_filt;
00123 }
00124
00125 filtered_error.at(2) = filtered_error.at(1);
00126 filtered_error.at(1) = filtered_error.at(0);
00127 filtered_error.at(0) = (1/(1+c*c+1.414*c))*(error.at(2)+2*error.at(1)+error.at(0)-(c*c-1.414*c+1)*filtered_error.at(2)-(-2*c*c+2)*filtered_error.at(1));
00128
00129
00130
00131 error_deriv.at(2) = error_deriv.at(1);
00132 error_deriv.at(1) = error_deriv.at(0);
00133 error_deriv.at(0) = (error.at(0)-error.at(1))/delta_t.toSec();
00134
00135 filtered_error_deriv.at(2) = filtered_error_deriv.at(1);
00136 filtered_error_deriv.at(1) = filtered_error_deriv.at(0);
00137
00138 filtered_error_deriv.at(0) = (1/(1+c*c+1.414*c))*(error_deriv.at(2)+2*error_deriv.at(1)+error_deriv.at(0)-(c*c-1.414*c+1)*filtered_error_deriv.at(2)-(-2*c*c+2)*filtered_error_deriv.at(1));
00139
00140
00141 proportional = Kp * filtered_error.at(0);
00142 integral = Ki * error_integral;
00143 derivative = Kd * filtered_error_deriv.at(0);
00144 control_effort = proportional + integral + derivative;
00145
00146
00147 if (control_effort > upper_limit)
00148 {
00149 control_effort = upper_limit;
00150 }
00151 else if (control_effort < lower_limit)
00152 {
00153 control_effort = lower_limit;
00154 }
00155
00156
00157 if (pid_enabled)
00158 {
00159 control_msg.data = control_effort;
00160 control_effort_pub.publish(control_msg);
00161 }
00162 else
00163 {
00164 error_integral = 0.0;
00165 }
00166
00167 return;
00168 }
00169
00170 void pid_enable_callback(const std_msgs::Bool& pid_enable_msg)
00171 {
00172 pid_enabled = pid_enable_msg.data;
00173 }
00174
00175 void get_params(double in, double &value, double &scale)
00176 {
00177 int digits = 0;
00178 value = in;
00179 while((fabs(value) > 1.0 || fabs(value) < 0.1) && (digits < 2 && digits > -1))
00180 {
00181 if(fabs(value) > 1.0)
00182 {
00183 value /= 10.0;
00184 digits++;
00185 }
00186 else
00187 {
00188 value *= 10.0;
00189 digits--;
00190 }
00191 }
00192 if(value > 1.0)
00193 value = 1.0;
00194 if(value < -1.0)
00195 value = -1.0;
00196
00197 scale = pow(10.0,digits);
00198 }
00199
00200 void reconfigure_callback(pid::PidConfig &config, uint32_t level)
00201 {
00202 if (first_reconfig)
00203 {
00204 get_params(Kp, config.Kp, config.Kp_scale);
00205 get_params(Ki, config.Ki, config.Ki_scale);
00206 get_params(Kd, config.Kd, config.Kd_scale);
00207 first_reconfig = false;
00208 return;
00209 }
00210
00211 Kp = config.Kp * config.Kp_scale;
00212 Ki = config.Ki * config.Ki_scale;
00213 Kd = config.Kd * config.Kd_scale;
00214 ROS_INFO("Pid reconfigure request: Kp: %f, Ki: %f, Kd: %f", Kp, Ki, Kd);
00215 }
00216
00218
00220
00221 bool validate_parameters()
00222 {
00223 if ( lower_limit > upper_limit )
00224 {
00225 ROS_ERROR("The lower saturation limit cannot be greater than the upper saturation limit.");
00226 return(false);
00227 }
00228
00229 return true;;
00230 }
00231
00233
00235 void print_parameters()
00236 {
00237 std::cout<< std::endl<<"PID PARAMETERS"<<std::endl<<"-----------------------------------------"<<std::endl;
00238 std::cout << "Kp: " << Kp << ", Ki: " << Ki << ", Kd: " << Kd << std::endl;
00239 if ( cutoff_frequency== -1)
00240 std::cout<<"LPF cutoff frequency: 1/4 of sampling rate"<<std::endl;
00241 else
00242 std::cout<<"LPF cutoff frequency: "<< cutoff_frequency << std::endl;
00243 std::cout << "pid node name: " << ros::this_node::getName() << std::endl;
00244 std::cout << "Name of topic from controller: " << topic_from_controller << std::endl;
00245 std::cout << "Name of topic from the plant: " << topic_from_plant << std::endl;
00246 std::cout << "Name of setpoint topic: " << setpoint_topic << std::endl;
00247 std::cout << "Integral-windup limit: " << windup_limit << std::endl;
00248 std::cout << "Saturation limits: " << upper_limit << "/" << lower_limit << std::endl;
00249 std::cout << "-----------------------------------------" << std::endl;
00250
00251 return;
00252 }
00253
00255
00257
00258 int main(int argc, char **argv)
00259 {
00260 ROS_INFO("Starting pid with node name %s", node_name.c_str());
00261
00262
00263 ros::init(argc, argv, node_name);
00264 ros::NodeHandle node;
00265 ros::NodeHandle node_priv("~");
00266
00267 while (ros::Time(0) == ros::Time::now())
00268 {
00269 ROS_INFO("controller spinning waiting for time to become non-zero");
00270 sleep(1);
00271 }
00272
00273
00274 node_priv.param<double>("Kp", Kp, 1.0);
00275 node_priv.param<double>("Ki", Ki, 0.0);
00276 node_priv.param<double>("Kd", Kd, 0.0);
00277 node_priv.param<double>("upper_limit", upper_limit, 1000.0);
00278 node_priv.param<double>("lower_limit", lower_limit, -1000.0);
00279 node_priv.param<double>("windup_limit", windup_limit, 1000.0);
00280 node_priv.param<double>("cutoff_frequency", cutoff_frequency, -1.0);
00281 node_priv.param<std::string>("topic_from_controller", topic_from_controller, "control_effort");
00282 node_priv.param<std::string>("topic_from_plant", topic_from_plant, "state");
00283 node_priv.param<std::string>("setpoint_topic", setpoint_topic, "setpoint");
00284 node_priv.param<std::string>("pid_enable_topic", pid_enable_topic, "pid_enable");
00285 node_priv.param<double>("max_loop_frequency", max_loop_frequency, 1.0);
00286 node_priv.param<double>("min_loop_frequency", min_loop_frequency, 1000.0);
00287
00288
00289 node_priv.param<bool>("angle_error", angle_error, false);
00290 node_priv.param<double>("angle_wrap", angle_wrap, 2.0*3.14159);
00291
00292
00293 print_parameters();
00294 if (not validate_parameters())
00295 {
00296 std::cout << "Error: invalid parameter\n";
00297 }
00298
00299
00300 control_effort_pub = node.advertise<std_msgs::Float64>(topic_from_controller, 1);
00301
00302 ros::Subscriber sub = node.subscribe(topic_from_plant, 1, plant_state_callback );
00303 ros::Subscriber setpoint_sub = node.subscribe(setpoint_topic, 1, setpoint_callback );
00304 ros::Subscriber pid_enabled_sub = node.subscribe(pid_enable_topic, 1, pid_enable_callback );
00305
00306
00307 dynamic_reconfigure::Server<pid::PidConfig> config_server;
00308 dynamic_reconfigure::Server<pid::PidConfig>::CallbackType f;
00309 f = boost::bind(&reconfigure_callback, _1, _2);
00310 config_server.setCallback(f);
00311
00312
00313 ros::spin();
00314
00315 return 0;
00316 }
00317