00001
00002 #include <ros/ros.h>
00003
00004 #include <gtest/gtest.h>
00005
00006 #include <control_toolbox/pid.h>
00007
00008 #include <boost/math/special_functions/fpclassify.hpp>
00009
00010 using namespace control_toolbox;
00011
00012 TEST(ParameterTest, zeroITermBadIBoundsTest)
00013 {
00014 RecordProperty("description","This test checks robustness against divide-by-zero errors when given integral term bounds which do not include 0.0.");
00015
00016 Pid pid(1.0, 0.0, 0.0, -1.0, 0.0);
00017
00018 double cmd = 0.0;
00019 double pe,ie,de;
00020
00021 cmd = pid.computeCommand(-1.0, ros::Duration(1.0));
00022
00023 pid.getCurrentPIDErrors(&pe,&ie,&de);
00024 EXPECT_FALSE(boost::math::isinf(ie));
00025 EXPECT_FALSE(boost::math::isnan(cmd));
00026
00027 cmd = pid.computeCommand(-1.0, ros::Duration(1.0));
00028 pid.getCurrentPIDErrors(&pe,&ie,&de);
00029 EXPECT_FALSE(boost::math::isinf(ie));
00030 EXPECT_FALSE(boost::math::isnan(cmd));
00031 }
00032
00033 TEST(ParameterTest, integrationWindupTest)
00034 {
00035 RecordProperty("description","This test succeeds if the integral error is prevented from winding up when the integral gain is non-zero.");
00036
00037 Pid pid(0.0, 1.0, 0.0, 1.0, -1.0);
00038
00039 double cmd = 0.0;
00040 double pe,ie,de;
00041
00042 cmd = pid.computeCommand(-1.0, ros::Duration(1.0));
00043 pid.getCurrentPIDErrors(&pe,&ie,&de);
00044 EXPECT_EQ(-1.0, ie);
00045 EXPECT_EQ(-1.0, cmd);
00046
00047 cmd = pid.computeCommand(-1.0, ros::Duration(1.0));
00048 pid.getCurrentPIDErrors(&pe,&ie,&de);
00049 EXPECT_EQ(-1.0, ie);
00050 EXPECT_EQ(-1.0, cmd);
00051 }
00052
00053 TEST(ParameterTest, integrationWindupZeroGainTest)
00054 {
00055 RecordProperty("description","This test succeeds if the integral error is prevented from winding up when the integral gain is zero. If the integral error is allowed to wind up while it is disabled, it can cause sudden jumps to the minimum or maximum bound in control command when re-enabled.");
00056
00057 double i_gain = 0.0;
00058 double i_min = -1.0;
00059 double i_max = 1.0;
00060 Pid pid(0.0, i_gain, 0.0, i_max, i_min);
00061
00062 double cmd = 0.0;
00063 double pe,ie,de;
00064
00065 cmd = pid.computeCommand(-1.0, ros::Duration(1.0));
00066 pid.getCurrentPIDErrors(&pe,&ie,&de);
00067 EXPECT_LE(i_min, ie);
00068 EXPECT_LE(ie, i_max);
00069 EXPECT_EQ(0.0, cmd);
00070
00071 cmd = pid.computeCommand(-1.0, ros::Duration(1.0));
00072 pid.getCurrentPIDErrors(&pe,&ie,&de);
00073 EXPECT_LE(i_min, ie);
00074 EXPECT_LE(ie, i_max);
00075 EXPECT_EQ(0.0, cmd);
00076 }
00077
00078 TEST(ParameterTest, gainSettingCopyPIDTest)
00079 {
00080 RecordProperty("description","This test succeeds if a PID object has its gain set at different points in time then the values are get-ed and still remain the same, as well as when PID is copied.");
00081
00082
00083 double p_gain = rand() % 100;
00084 double i_gain = rand() % 100;
00085 double d_gain = rand() % 100;
00086 double i_max = rand() % 100;
00087 double i_min = -1 * rand() % 100;
00088
00089
00090 Pid pid1(p_gain, i_gain, d_gain, i_max, i_min);
00091
00092
00093 double p_gain_return, i_gain_return, d_gain_return, i_max_return, i_min_return;
00094 pid1.getGains(p_gain_return, i_gain_return, d_gain_return, i_max_return, i_min_return);
00095
00096 EXPECT_EQ(p_gain, p_gain_return);
00097 EXPECT_EQ(i_gain, i_gain_return);
00098 EXPECT_EQ(d_gain, d_gain_return);
00099 EXPECT_EQ(i_max, i_max_return);
00100 EXPECT_EQ(i_min, i_min_return);
00101
00102
00103
00104
00105 p_gain = rand() % 100;
00106 i_gain = rand() % 100;
00107 d_gain = rand() % 100;
00108 i_max = rand() % 100;
00109 i_min = -1 * rand() % 100;
00110 pid1.setGains(p_gain, i_gain, d_gain, i_max, i_min);
00111
00112 Pid::Gains g1 = pid1.getGains();
00113 EXPECT_EQ(p_gain, g1.p_gain_);
00114 EXPECT_EQ(i_gain, g1.i_gain_);
00115 EXPECT_EQ(d_gain, g1.d_gain_);
00116 EXPECT_EQ(i_max, g1.i_max_);
00117 EXPECT_EQ(i_min, g1.i_min_);
00118
00119
00120
00121
00122
00123
00124
00125
00126 pid1.setCurrentCmd(10);
00127 pid1.computeCommand(20, ros::Duration(1.0));
00128
00129
00130 Pid pid2(pid1);
00131
00132 pid2.getGains(p_gain_return, i_gain_return, d_gain_return, i_max_return, i_min_return);
00133
00134 EXPECT_EQ(p_gain, p_gain_return);
00135 EXPECT_EQ(i_gain, i_gain_return);
00136 EXPECT_EQ(d_gain, d_gain_return);
00137 EXPECT_EQ(i_max, i_max_return);
00138 EXPECT_EQ(i_min, i_min_return);
00139
00140
00141 double pe, ie, de;
00142 pid2.getCurrentPIDErrors(&pe, &ie, &de);
00143 EXPECT_EQ(0.0, pe);
00144 EXPECT_EQ(0.0, ie);
00145 EXPECT_EQ(0.0, de);
00146
00147
00148 Pid pid3;
00149 pid3 = pid1;
00150
00151 pid3.getGains(p_gain_return, i_gain_return, d_gain_return, i_max_return, i_min_return);
00152
00153 EXPECT_EQ(p_gain, p_gain_return);
00154 EXPECT_EQ(i_gain, i_gain_return);
00155 EXPECT_EQ(d_gain, d_gain_return);
00156 EXPECT_EQ(i_max, i_max_return);
00157 EXPECT_EQ(i_min, i_min_return);
00158
00159
00160 double pe2, ie2, de2;
00161 pid3.getCurrentPIDErrors(&pe2, &ie2, &de2);
00162 EXPECT_EQ(0.0, pe2);
00163 EXPECT_EQ(0.0, ie2);
00164 EXPECT_EQ(0.0, de2);
00165
00166
00167
00168 const Pid pid4(pid3);
00169
00170 Pid::Gains g3 = pid4.getGains();
00171 EXPECT_EQ(p_gain, g3.p_gain_);
00172 EXPECT_EQ(i_gain, g3.i_gain_);
00173 EXPECT_EQ(d_gain, g3.d_gain_);
00174 EXPECT_EQ(i_max, g3.i_max_);
00175 EXPECT_EQ(i_min, g3.i_min_);
00176
00177
00178 }
00179
00180
00181
00182 int main(int argc, char** argv) {
00183 testing::InitGoogleTest(&argc, argv);
00184 return RUN_ALL_TESTS();
00185 }