diff --git a/doc/controllers/Feedforward2Dof.md b/doc/controllers/Feedforward2Dof.md index e6eea37..4d6c0a8 100644 --- a/doc/controllers/Feedforward2Dof.md +++ b/doc/controllers/Feedforward2Dof.md @@ -55,6 +55,7 @@ If the system were already tracking perfectly ($y = r = 0.5$), then $e = 0$, $u_ - **Feedforward does not aid disturbance rejection.** If $u_{ff}$ is tuned for tracking and a disturbance enters the plant, only $u_{fb}$ responds. - **Inverse-plant feedforward for non-minimum-phase systems** is non-causal; use a truncated or approximate inverse. - **Sign convention.** The error passed to feedback is $r - y$, not $y - r$. Swapping signs destabilises positive-gain plants. +- **Stateful feedforward must implement `Reset()`.** Dynamic pre-filters (e.g. reference model filters) carry internal state that must be cleared on `Reset()`. Both the feedforward and feedback components are reset when `Feedforward2Dof::Reset()` is called; any feedforward implementation that holds state must override `Reset()` to clear it. ## Variants & Generalizations diff --git a/numerical/controllers/implementations/Feedforward2Dof.hpp b/numerical/controllers/implementations/Feedforward2Dof.hpp index 1e9d7c7..a209125 100644 --- a/numerical/controllers/implementations/Feedforward2Dof.hpp +++ b/numerical/controllers/implementations/Feedforward2Dof.hpp @@ -17,7 +17,8 @@ namespace controllers static_assert(std::is_floating_point_v, "Feedforward supports floating-point types"); virtual ~Feedforward() = default; - virtual T Evaluate(T reference) const = 0; + virtual T Evaluate(T reference) = 0; + virtual void Reset() = 0; }; template @@ -68,6 +69,7 @@ namespace controllers template void Feedforward2Dof::Reset() { + feedforward.Reset(); feedback.Reset(); } diff --git a/numerical/controllers/implementations/test/TestFeedforward2Dof.cpp b/numerical/controllers/implementations/test/TestFeedforward2Dof.cpp index 53d4d59..2ba0168 100644 --- a/numerical/controllers/implementations/test/TestFeedforward2Dof.cpp +++ b/numerical/controllers/implementations/test/TestFeedforward2Dof.cpp @@ -9,7 +9,8 @@ namespace : public controllers::Feedforward { public: - MOCK_METHOD(float, Evaluate, (float), (const, override)); + MOCK_METHOD(float, Evaluate, (float), (override)); + MOCK_METHOD(void, Reset, (), (override)); }; class MockFeedbackLaw @@ -109,8 +110,9 @@ TEST_F(TestFeedforward2Dof, zero_feedback_reduces_to_feedforward) EXPECT_NEAR(result, 0.4f, math::Tolerance()); } -TEST_F(TestFeedforward2Dof, reset_delegates_to_feedback) +TEST_F(TestFeedforward2Dof, reset_delegates_to_feedforward_and_feedback) { + EXPECT_CALL(ff, Reset()).Times(1); EXPECT_CALL(fb, Reset()).Times(1); controller.Reset();