Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
PIDLoop.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Execution_PIDLoop_h_
5#define _Stroika_Foundation_Execution_PIDLoop_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <compare>
10
11#include "Stroika/Foundation/Common/Common.h"
12
15
16#include "Synchronized.h"
17#include "Thread.h"
18
19/**
20 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
21 */
22
24
25 /**
26 * \note Based on https://en.wikipedia.org/wiki/PID_controller (Discrete implementation)
27 *
28 * This code captures the basic logic/implementation of a discrete PID loop. It can be run from an owner-controlled
29 * thread, or internally maintain its own thread to run the loop in (the easiest to use is the later).
30 *
31 * \par Example Usage
32 * \code
33 * PIDLoop<> pidLoop { PIDLoop<>::ControlParams { 3, -4.0, 4.0 }, 1.0, [] () -> double { return getTemperature (); }, [] (double voltage) { setDAC (voltage); } };
34 * pidLoop.SetSetPoint (23.3);
35 * pidLoop.RunInThread ();
36 * Sleep (1*60); // run PID loop 1 minutes
37 * pidLoop.SetSetPoint (40.0); // then raise temperature
38 * Sleep (10*60); // then run PID loop 10 minutes, and when PIDLoop goes out of scope, auto-terminates
39 * \endcode
40 *
41 * \note To have code which preflights or cleanups up after the PIDLoop, create your own subclass of PIDLoop<>, and do your
42 * initialization in the CTOR, and cleanup in the DTOR, so leverage and respects the RAII.
43 *
44 * \note \em Thread-Safety <a href="Thread-Safety.md#Internally-Synchronized-Thread-Safety">Internally-Synchronized-Thread-Safety</a>
45 * except that the caller must handle any synchronization required by the measureFunction and the outputFunction
46 *
47 */
48 template <typename CONTROL_VAR_TYPE = double>
49 class PIDLoop {
50 public:
51 using ValueType = CONTROL_VAR_TYPE;
52
53 public:
54 /**
55 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a>:
56 * static_assert (totally_ordered<ControlParams>);
57 */
59 ControlParams () = default;
60 ControlParams (ValueType p, ValueType i, ValueType d);
61 ValueType P{};
62 ValueType I{};
63 ValueType D{};
64
65 nonvirtual strong_ordering operator<=> (const ControlParams& rhs) const = default;
66
67 /**
68 * @see Characters::ToString ();
69 */
70 nonvirtual Characters::String ToString () const;
71 };
72
73 public:
74 enum AutoStartFlag {
75 eAutoStart
76 };
77
78 public:
79 /**
80 * Measure function produces PV = ProcessVariable, and SP - SetPoint is target value.
81 *
82 * For more about the PID parameters to provide (tuning) see https://en.wikipedia.org/wiki/PID_controller
83 *
84 * For updatePeriod, this depends alot on the system you are using. THis is a measure of how much time between updates to the
85 * control variable.
86 */
87 PIDLoop () = delete;
88 PIDLoop (const PIDLoop&) = delete;
89 PIDLoop (const ControlParams& pidParams, Time::DurationSeconds updatePeriod, const function<ValueType ()>& measureFunction,
90 const function<void (ValueType o)>& outputFunction, ValueType initialSetPoint = {});
91 PIDLoop (AutoStartFlag, const ControlParams& pidParams, Time::DurationSeconds updatePeriod, const function<ValueType ()>& measureFunction,
92 const function<void (ValueType o)>& outputFunction, ValueType initialSetPoint = {});
93 nonvirtual PIDLoop& operator= (const PIDLoop&) = delete;
94
95 public:
96 /**
97 * If any existing PIDLoop thread is running (due to RunInThead call), this will abort that thread
98 * and wait for it to terminate before the PIDLoop destructor completes. If its calling
99 * a measure or output function, this means those must respect the thread abort call or a hang can
100 * result.
101 */
102 ~PIDLoop ();
103
104 public:
105 /**
106 */
107 nonvirtual ValueType GetSetPoint () const;
108
109 public:
110 /**
111 * This can be called anytime, and the PIDLoop will automatically adjust.
112 */
113 nonvirtual void SetSetPoint (ValueType sp);
114
115 public:
116 /**
117 * return P/I/D parameters
118 */
119 nonvirtual ControlParams GetControlParams () const;
120
121 public:
122 /**
123 */
124 nonvirtual Time::DurationSeconds GetUpdatePeriod () const;
125
126 public:
127 /**
128 * Typically this is what you would do, and receive the Thread object, to cancel (Abort)
129 *
130 * \pre only called once.
131 *
132 * If ever run, PIDLoop DTOR automatically terminates Run loop and waits for thread to terminate.
133 */
134 nonvirtual Thread::Ptr RunInThread ();
135
136 public:
137 /**
138 * Run this function - in the body of your thread. Interrupt with a thread abort.
139 *
140 * Use this if you want to control thread usage yourself. Otherwise, try @see RunInThread
141 */
142 nonvirtual void RunDirectly ();
143
144 private:
145 ControlParams fPIDParams_;
146 Time::DurationSeconds fUpdatePeriod_; // time between loop iterations
147 function<ValueType ()> fMeasureFunction_;
148 function<void (ValueType o)> fOutputFunction_;
149 struct UpdatableParams_ {
150 ValueType fSetPoint_ = {};
151 ValueType fPrevError_ = {};
152 ValueType fIntegral_ = {};
153 };
154 Synchronized<UpdatableParams_> fUpdatableParams_;
155 optional<Thread::Ptr> fThread_;
156 };
157
158}
159
160/*
161 ********************************************************************************
162 ***************************** Implementation Details ***************************
163 ********************************************************************************
164 */
165#include "PIDLoop.inl"
166
167#endif /*_Stroika_Foundation_Execution_PIDLoop_h_*/
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
nonvirtual Thread::Ptr RunInThread()
Definition PIDLoop.inl:124
nonvirtual ControlParams GetControlParams() const
Definition PIDLoop.inl:82
nonvirtual void SetSetPoint(ValueType sp)
Definition PIDLoop.inl:74
nonvirtual Characters::String ToString() const
Definition PIDLoop.inl:26