Resurgence (PY2022)
Codebase for the Husky Robotics 2021-2022 rover Resurgence
Toggle main menu visibility
Loading...
Searching...
No Matches
src
control
PIDControl.h
1
#pragma once
2
3
#include "../utils/time.h"
4
#include "../world_interface/data.h"
5
6
#include <
chrono
>
7
#include <
functional
>
8
#include <
optional
>
9
#include <
utility
>
10
11
#include <Eigen/Core>
12
13
namespace
control {
14
19
struct
PIDGains
{
20
double
kP, kI, kD, kF;
21
std::optional<double> iZone;
22
};
23
30
template
<
int
dim>
31
class
PIDController
{
32
public
:
33
template
<
int
d>
34
using
Arrayd =
Eigen::Array<double, d, 1>
;
35
41
PIDController
(
const
std::array<PIDGains, dim>
& gains) {
42
reset
();
43
setGains
(gains);
44
}
45
51
void
setGains
(
const
std::array<PIDGains, dim>
& gains) {
52
for
(
int
i = 0; i < dim; i++) {
53
kP(i) = gains[i].kP;
54
kI(i) = gains[i].kI;
55
kD(i) = gains[i].kD;
56
kF(i) = gains[i].kF;
57
iZone(i) = gains[i].iZone.value_or(
std::numeric_limits<double>::infinity
());
58
}
59
}
60
66
bool
hasTarget
() {
67
return
setPoint.has_value();
68
}
69
75
void
setTarget
(
const
Arrayd<dim>& setPoint) {
76
this->setPoint = setPoint;
77
}
78
86
Arrayd<dim>
getOutput
(
robot::types::datatime_t
currTime,
const
Arrayd<dim>& currValue) {
87
if
(!setPoint.has_value()) {
88
return
Arrayd<dim>::Zero();
89
}
90
91
// see wikipedia link above for in-depth explanation
92
93
Arrayd<dim> err = setPoint.value() - currValue;
94
Arrayd<dim> pTerm = err * kP;
95
Arrayd<dim> fTerm = setPoint.value() * kF;
96
97
Arrayd<dim> iTerm = Arrayd<dim>::Zero();
98
Arrayd<dim> dTerm = Arrayd<dim>::Zero();
99
100
if
(lastData.has_value()) {
101
// TODO: instead of numerically differentiating we can use a model (if we have one)
102
auto
[lastTime, lastValue] = lastData.value();
103
double
dtSec =
util::durationToSec
(currTime - lastTime);
104
105
// use the backwards finite difference for approximating the derivative
106
Arrayd<dim> derivative = (currValue - lastValue) / dtSec;
107
dTerm = derivative * kD;
108
109
// use the trapezoid rule for approximating the integral
110
Arrayd<dim> area = (lastValue + currValue) * dtSec / 2.0;
111
iAccum += area;
112
iTerm = (err.abs() <= iZone).select(iAccum * kI, Arrayd<dim>::Zero());
113
}
114
115
lastData = {currTime, currValue};
116
Arrayd<dim> output = pTerm + iTerm + dTerm + fTerm;
117
118
return
output;
119
}
120
124
void
reset
() {
125
setPoint.reset();
126
lastData.reset();
127
iAccum.setZero();
128
}
129
130
private
:
131
Arrayd<dim> kP, kI, kD, kF;
132
Arrayd<dim> iZone;
// +inf indicates no i zone
133
Arrayd<dim> iAccum;
134
std::optional<Arrayd<dim>> setPoint;
135
std::optional<std::pair<robot::types::datatime_t, Arrayd<dim>>> lastData;
136
};
137
}
// namespace control
chrono
functional
utility
optional
std::array
std::numeric_limits::infinity
static constexpr _Tp infinity() noexcept
Eigen::Array
control::PIDController::hasTarget
bool hasTarget()
Check if a target is currently set.
Definition
PIDControl.h:66
control::PIDController::reset
void reset()
Reset the controller.
Definition
PIDControl.h:124
control::PIDController::setTarget
void setTarget(const Arrayd< dim > &setPoint)
Set the target of the controller.
Definition
PIDControl.h:75
control::PIDController::getOutput
Arrayd< dim > getOutput(robot::types::datatime_t currTime, const Arrayd< dim > &currValue)
Get the output from the controller.
Definition
PIDControl.h:86
control::PIDController::PIDController
PIDController(const std::array< PIDGains, dim > &gains)
Construct a new PIDController.
Definition
PIDControl.h:41
control::PIDController::setGains
void setGains(const std::array< PIDGains, dim > &gains)
Set the gains of the PID controller.
Definition
PIDControl.h:51
robot::types::datatime_t
std::chrono::time_point< dataclock > datatime_t
A point in time as measured by dataclock.
Definition
data.h:31
util::durationToSec
double durationToSec(std::chrono::duration< Rep, Period > dur)
Convert a duration to seconds, as a double.
Definition
time.h:18
control::PIDGains
A set of PID gains.
Definition
PIDControl.h:19
Generated by
1.17.0