Go to the documentation of this file.00001
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include <math.h>
00045 #include <ros/ros.h>
00046 #include <std_msgs/Float64.h>
00047 #include <string>
00048
00049
00050 #include <dynamic_reconfigure/Config.h>
00051 #include <dynamic_reconfigure/DoubleParameter.h>
00052 #include <dynamic_reconfigure/Reconfigure.h>
00053
00054 void setKiKdToZero();
00055 void setKp(double Kp);
00056 void setpointCallback(const std_msgs::Float64& setpoint_msg);
00057 void stateCallback(const std_msgs::Float64& state_msg);
00058 void setFinalParams();
00059
00060 namespace autotune
00061 {
00062 double Ku = 0.;
00063 double Tu = 0.;
00064 double setpoint = 0.;
00065 double state = 0.;
00066 std::string ns = "/left_wheel_pid/";
00067 int oscillation_count = 0;
00068 int num_loops = 100;
00069 int initial_error = 0;
00070 double Kp_ZN = 0.;
00071 double Ki_ZN = 0.;
00072 double Kd_ZN = 0.;
00073 bool found_Ku = false;
00074 std::vector<double> oscillation_times(3);
00075 }
00076
00077 int main(int argc, char** argv)
00078 {
00079 ros::init(argc, argv, "autotune_node");
00080 ros::NodeHandle autotune_node;
00081 ros::start();
00082 ros::Subscriber setpoint_sub = autotune_node.subscribe("/setpoint", 1, setpointCallback);
00083 ros::Subscriber state_sub = autotune_node.subscribe("/state", 1, stateCallback);
00084 ros::Rate loopRate(50);
00085
00086
00087 setKiKdToZero();
00088
00089
00090 double Kp_max = 10.;
00091 double Kp_min = 0.5;
00092 double Kp_step = 1.0;
00093
00094 for (double Kp = Kp_min; Kp <= Kp_max; Kp += Kp_step)
00095 {
00097
00099
00100 ros::topic::waitForMessage<std_msgs::Float64>("setpoint");
00101 ros::topic::waitForMessage<std_msgs::Float64>("state");
00102
00103
00104 setKp(Kp);
00105 ROS_INFO_STREAM("Trying Kp = " << Kp);
00106 autotune::oscillation_count = 0;
00107
00108 for (int i = 0; i < autotune::num_loops; i++)
00109 {
00110 ros::spinOnce();
00111 loopRate.sleep();
00112 if (i == 0)
00113 {
00114 autotune::initial_error = (autotune::setpoint - autotune::state);
00115 }
00116
00117
00118
00119
00120
00121
00122 ros::topic::waitForMessage<std_msgs::Float64>("state");
00123 double new_error = (autotune::setpoint - autotune::state);
00124
00125 if (std::signbit(autotune::initial_error) != std::signbit(new_error))
00126 {
00127 autotune::oscillation_times.at(autotune::oscillation_count) =
00128 loopRate.expectedCycleTime().toSec() * i;
00129 autotune::oscillation_count++;
00130 ROS_INFO_STREAM("Oscillation occurred. Oscillation count: " << autotune::oscillation_count);
00131 autotune::initial_error = new_error;
00132
00133
00134 if (autotune::oscillation_count > 2)
00135 {
00136
00137 autotune::Tu = autotune::oscillation_times.at(2) - autotune::oscillation_times.at(0);
00138 ROS_INFO_STREAM("Tu (oscillation period): " << autotune::Tu);
00139
00140
00141
00142
00143
00144
00145 if (autotune::Tu > 3. * loopRate.expectedCycleTime().toSec())
00146 {
00147 autotune::Ku = Kp;
00148
00149
00150 autotune::Kp_ZN = 0.6 * autotune::Ku;
00151 autotune::Ki_ZN = 1.2 * autotune::Ku / autotune::Tu;
00152 autotune::Kd_ZN = 3. * autotune::Ku * autotune::Tu / 40.;
00153
00154 autotune::found_Ku = true;
00155 goto DONE;
00156 }
00157 else
00158 break;
00159 }
00160 }
00161 }
00162 }
00163 DONE:
00164
00165 if (autotune::found_Ku == true)
00166 {
00167 setFinalParams();
00168 }
00169 else
00170 ROS_INFO_STREAM("Did not see any oscillations for this range of Kp. Adjust "
00171 "Kp_max and Kp_min to broaden the search.");
00172
00173 ros::shutdown();
00174 return 0;
00175 }
00176
00177
00178 void setKiKdToZero()
00179 {
00180 dynamic_reconfigure::ReconfigureRequest srv_req;
00181 dynamic_reconfigure::ReconfigureResponse srv_resp;
00182 dynamic_reconfigure::DoubleParameter double_param;
00183 dynamic_reconfigure::Config config;
00184 double_param.name = "Ki";
00185 double_param.value = 0.0;
00186 config.doubles.push_back(double_param);
00187 double_param.name = "Kd";
00188 double_param.value = 0.0;
00189 config.doubles.push_back(double_param);
00190 srv_req.config = config;
00191 ros::service::call(autotune::ns + "set_parameters", srv_req, srv_resp);
00192 }
00193
00194
00195 void setKp(double Kp)
00196 {
00197 dynamic_reconfigure::ReconfigureRequest srv_req;
00198 dynamic_reconfigure::ReconfigureResponse srv_resp;
00199 dynamic_reconfigure::DoubleParameter double_param;
00200 dynamic_reconfigure::Config config;
00201
00202
00203 ros::service::call(autotune::ns + "set_parameters", srv_req, srv_resp);
00204
00205 double_param.name = "Kp";
00206 double_param.value = Kp / srv_resp.config.doubles.at(0).value;
00207 config.doubles.push_back(double_param);
00208 srv_req.config = config;
00209 ros::service::call(autotune::ns + "set_parameters", srv_req, srv_resp);
00210 }
00211
00212 void setpointCallback(const std_msgs::Float64& setpoint_msg)
00213 {
00214 autotune::setpoint = setpoint_msg.data;
00215 }
00216
00217 void stateCallback(const std_msgs::Float64& state_msg)
00218 {
00219 autotune::state = state_msg.data;
00220 }
00221
00222
00223 void setFinalParams()
00224 {
00225 ROS_INFO_STREAM(" ");
00226 ROS_INFO_STREAM("The suggested parameters are: ");
00227 ROS_INFO_STREAM("Kp " << autotune::Kp_ZN);
00228 ROS_INFO_STREAM("Ki " << autotune::Ki_ZN);
00229 ROS_INFO_STREAM("Kd " << autotune::Kd_ZN);
00230
00231
00232 dynamic_reconfigure::ReconfigureRequest srv_req;
00233 dynamic_reconfigure::ReconfigureResponse srv_resp;
00234 dynamic_reconfigure::DoubleParameter double_param;
00235 dynamic_reconfigure::Config config;
00236
00237
00238 ros::service::call(autotune::ns + "set_parameters", srv_req, srv_resp);
00239
00240 double_param.name = "Kp";
00241 double_param.value = autotune::Kp_ZN / srv_resp.config.doubles.at(0).value;
00242 config.doubles.push_back(double_param);
00243
00244 double_param.name = "Ki";
00245 double_param.value = autotune::Ki_ZN / srv_resp.config.doubles.at(0).value;
00246 config.doubles.push_back(double_param);
00247
00248 double_param.name = "Kd";
00249 double_param.value = autotune::Kd_ZN / srv_resp.config.doubles.at(0).value;
00250 config.doubles.push_back(double_param);
00251
00252 srv_req.config = config;
00253 ros::service::call(autotune::ns + "set_parameters", srv_req, srv_resp);
00254 }