Skip to content

Commit bc45970

Browse files
committed
Improvement in integral contribution implementation. Resolve #32.
1 parent 4719510 commit bc45970

File tree

3 files changed

+56
-41
lines changed

3 files changed

+56
-41
lines changed

include/control_toolbox/pid.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,8 @@ class Pid
370370

371371
double p_error_last_; /**< _Save position state for derivative state calculation. */
372372
double p_error_; /**< Position error. */
373-
double d_error_; /**< Derivative error. */
374-
double i_term_; /**< Integral term. */
373+
double i_error_; /**< Integral of position error. */
374+
double d_error_; /**< Derivative of position error. */
375375
double cmd_; /**< Command to send. */
376376

377377
// Dynamics reconfigure

src/pid.cpp

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ void Pid::reset()
175175
{
176176
p_error_last_ = 0.0;
177177
p_error_ = 0.0;
178+
i_error_ = 0.0;
178179
d_error_ = 0.0;
179-
i_term_ = 0.0;
180180
cmd_ = 0.0;
181181
}
182182

@@ -269,7 +269,7 @@ double Pid::computeCommand(double error, ros::Duration dt)
269269
// Get the gain parameters from the realtime buffer
270270
Gains gains = *gains_buffer_.readFromRT();
271271

272-
double p_term, d_term;
272+
double p_term, d_term, i_term;
273273
p_error_ = error; // this is error = target - state
274274

275275
if (dt == ros::Duration(0.0) || std::isnan(error) || std::isinf(error))
@@ -278,11 +278,14 @@ double Pid::computeCommand(double error, ros::Duration dt)
278278
// Calculate proportional contribution to command
279279
p_term = gains.p_gain_ * p_error_;
280280

281-
//Calculate integral contribution to command
282-
i_term_ = i_term_ + gains.i_gain_ * dt.toSec() * p_error_;
281+
// Calculate the integral of the position error
282+
i_error_ += dt.toSec() * p_error_;
283+
284+
// Calculate integral contribution to command
285+
i_term = gains.i_gain_ * i_error_;
283286

284-
// Limit i_term_ so that the limit is meaningful in the output
285-
i_term_ = std::max( gains.i_min_, std::min( i_term_, gains.i_max_) );
287+
// Limit i_term so that the limit is meaningful in the output
288+
i_term = std::max( gains.i_min_, std::min( i_term, gains.i_max_) );
286289

287290
// Calculate the derivative error
288291
if (dt.toSec() > 0.0)
@@ -292,7 +295,9 @@ double Pid::computeCommand(double error, ros::Duration dt)
292295
}
293296
// Calculate derivative contribution to command
294297
d_term = gains.d_gain_ * d_error_;
295-
cmd_ = p_term + i_term_ + d_term;
298+
299+
// Compute the command
300+
cmd_ = p_term + i_term + d_term;
296301

297302
return cmd_;
298303
}
@@ -302,7 +307,7 @@ double Pid::updatePid(double error, ros::Duration dt)
302307
// Get the gain parameters from the realtime buffer
303308
Gains gains = *gains_buffer_.readFromRT();
304309

305-
double p_term, d_term;
310+
double p_term, d_term, i_term;
306311
p_error_ = error; //this is pError = pState-pTarget
307312

308313
if (dt == ros::Duration(0.0) || std::isnan(error) || std::isinf(error))
@@ -311,11 +316,14 @@ double Pid::updatePid(double error, ros::Duration dt)
311316
// Calculate proportional contribution to command
312317
p_term = gains.p_gain_ * p_error_;
313318

314-
//Calculate integral contribution to command
315-
i_term_ = i_term_ + gains.i_gain_ * dt.toSec() * p_error_;
319+
// Calculate the integral of the position error
320+
i_error_ += dt.toSec() * p_error_;
321+
322+
// Calculate integral contribution to command
323+
i_term = gains.i_gain_ * i_error_;
316324

317-
// Limit i_term_ so that the limit is meaningful in the output
318-
i_term_ = std::max( gains.i_min_, std::min( i_term_, gains.i_max_) );
325+
// Limit i_term so that the limit is meaningful in the output
326+
i_term = std::max( gains.i_min_, std::min( i_term, gains.i_max_) );
319327

320328
// Calculate the derivative error
321329
if (dt.toSec() > 0.0)
@@ -325,7 +333,9 @@ double Pid::updatePid(double error, ros::Duration dt)
325333
}
326334
// Calculate derivative contribution to command
327335
d_term = gains.d_gain_ * d_error_;
328-
cmd_ = - p_term - i_term_ - d_term;
336+
337+
// Compute the command
338+
cmd_ = - p_term - i_term - d_term;
329339

330340
return cmd_;
331341
}
@@ -335,7 +345,7 @@ double Pid::computeCommand(double error, double error_dot, ros::Duration dt)
335345
// Get the gain parameters from the realtime buffer
336346
Gains gains = *gains_buffer_.readFromRT();
337347

338-
double p_term, d_term;
348+
double p_term, d_term, i_term;
339349
p_error_ = error; // this is error = target - state
340350
d_error_ = error_dot;
341351

@@ -346,15 +356,20 @@ double Pid::computeCommand(double error, double error_dot, ros::Duration dt)
346356
// Calculate proportional contribution to command
347357
p_term = gains.p_gain_ * p_error_;
348358

349-
//Calculate integral contribution to command
350-
i_term_ = i_term_ + gains.i_gain_ * dt.toSec() * p_error_;
359+
// Calculate the integral of the position error
360+
i_error_ += dt.toSec() * p_error_;
361+
362+
// Calculate integral contribution to command
363+
i_term = gains.i_gain_ * i_error_;
351364

352-
// Limit i_term_ so that the limit is meaningful in the output
353-
i_term_ = std::max( gains.i_min_, std::min( i_term_, gains.i_max_) );
365+
// Limit i_term so that the limit is meaningful in the output
366+
i_term = std::max( gains.i_min_, std::min( i_term, gains.i_max_) );
354367

355368
// Calculate derivative contribution to command
356369
d_term = gains.d_gain_ * d_error_;
357-
cmd_ = p_term + i_term_ + d_term;
370+
371+
// Compute the command
372+
cmd_ = - p_term - i_term - d_term;
358373

359374
return cmd_;
360375
}
@@ -364,7 +379,7 @@ double Pid::updatePid(double error, double error_dot, ros::Duration dt)
364379
// Get the gain parameters from the realtime buffer
365380
Gains gains = *gains_buffer_.readFromRT();
366381

367-
double p_term, d_term;
382+
double p_term, d_term, i_term;
368383
p_error_ = error; //this is pError = pState-pTarget
369384
d_error_ = error_dot;
370385

@@ -375,15 +390,20 @@ double Pid::updatePid(double error, double error_dot, ros::Duration dt)
375390
// Calculate proportional contribution to command
376391
p_term = gains.p_gain_ * p_error_;
377392

378-
//Calculate integral contribution to command
379-
i_term_ = i_term_ + gains.i_gain_ * dt.toSec() * p_error_;
393+
// Calculate the integral of the position error
394+
i_error_ += dt.toSec() * p_error_;
395+
396+
// Calculate integral contribution to command
397+
i_term = gains.i_gain_ * i_error_;
380398

381-
// Limit i_term_ so that the limit is meaningful in the output
382-
i_term_ = std::max( gains.i_min_, std::min( i_term_, gains.i_max_) );
399+
// Limit i_term so that the limit is meaningful in the output
400+
i_term = std::max( gains.i_min_, std::min( i_term, gains.i_max_) );
383401

384402
// Calculate derivative contribution to command
385403
d_term = gains.d_gain_ * d_error_;
386-
cmd_ = - p_term - i_term_ - d_term;
404+
405+
// Compute the command
406+
cmd_ = - p_term - i_term - d_term;
387407

388408
return cmd_;
389409
}
@@ -404,7 +424,7 @@ void Pid::getCurrentPIDErrors(double *pe, double *ie, double *de)
404424
Gains gains = *gains_buffer_.readFromRT();
405425

406426
*pe = p_error_;
407-
*ie = gains.i_gain_ ? i_term_/gains.i_gain_ : 0.0;
427+
*ie = i_error_;
408428
*de = d_error_;
409429
}
410430

@@ -420,8 +440,8 @@ void Pid::printValues()
420440
<< " I_Min: " << gains.i_min_ << "\n"
421441
<< " P_Error_Last: " << p_error_last_ << "\n"
422442
<< " P_Error: " << p_error_ << "\n"
443+
<< " I_Error: " << i_error_ << "\n"
423444
<< " D_Error: " << d_error_ << "\n"
424-
<< " I_Term: " << i_term_ << "\n"
425445
<< " Command: " << cmd_
426446
);
427447

test/pid_tests.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,23 @@ TEST(ParameterTest, zeroITermBadIBoundsTest)
3232

3333
TEST(ParameterTest, integrationWindupTest)
3434
{
35-
RecordProperty("description","This test succeeds if the integral error is prevented from winding up when the integral gain is non-zero.");
35+
RecordProperty("description","This test succeeds if the integral contribution is prevented from winding up when the integral gain is non-zero.");
3636

37-
Pid pid(0.0, 1.0, 0.0, 1.0, -1.0);
37+
Pid pid(0.0, 2.0, 0.0, 1.0, -1.0);
3838

3939
double cmd = 0.0;
4040
double pe,ie,de;
4141

4242
cmd = pid.computeCommand(-1.0, ros::Duration(1.0));
43-
pid.getCurrentPIDErrors(&pe,&ie,&de);
44-
EXPECT_EQ(-1.0, ie);
4543
EXPECT_EQ(-1.0, cmd);
4644

4745
cmd = pid.computeCommand(-1.0, ros::Duration(1.0));
48-
pid.getCurrentPIDErrors(&pe,&ie,&de);
49-
EXPECT_EQ(-1.0, ie);
5046
EXPECT_EQ(-1.0, cmd);
5147
}
5248

5349
TEST(ParameterTest, integrationWindupZeroGainTest)
5450
{
55-
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.");
51+
RecordProperty("description","This test succeeds if the integral contribution is prevented from winding up when the integral gain is zero. If the integral contribution 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.");
5652

5753
double i_gain = 0.0;
5854
double i_min = -1.0;
@@ -64,14 +60,13 @@ TEST(ParameterTest, integrationWindupZeroGainTest)
6460

6561
cmd = pid.computeCommand(-1.0, ros::Duration(1.0));
6662
pid.getCurrentPIDErrors(&pe,&ie,&de);
67-
EXPECT_LE(i_min, ie);
68-
EXPECT_LE(ie, i_max);
63+
EXPECT_LE(i_min, cmd);
64+
EXPECT_LE(cmd, i_max);
6965
EXPECT_EQ(0.0, cmd);
7066

7167
cmd = pid.computeCommand(-1.0, ros::Duration(1.0));
72-
pid.getCurrentPIDErrors(&pe,&ie,&de);
73-
EXPECT_LE(i_min, ie);
74-
EXPECT_LE(ie, i_max);
68+
EXPECT_LE(i_min, cmd);
69+
EXPECT_LE(cmd, i_max);
7570
EXPECT_EQ(0.0, cmd);
7671
}
7772

0 commit comments

Comments
 (0)