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