LightLib
PROS library for VEX V5: EKF/MCL localization, RAMSETE path following, high-level chassis API
Loading...
Searching...
No Matches
asyncWrapper.hpp
Go to the documentation of this file.
1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6#pragma once
7
17#include <atomic>
18#include <memory>
19
20namespace okapi {
21template <typename Input, typename Output>
22class AsyncWrapper : virtual public AsyncController<Input, Output> {
23 public:
35 AsyncWrapper(const std::shared_ptr<ControllerInput<Input>> &iinput,
36 const std::shared_ptr<ControllerOutput<Output>> &ioutput,
37 const std::shared_ptr<IterativeController<Input, Output>> &icontroller,
38 const Supplier<std::unique_ptr<AbstractRate>> &irateSupplier,
39 const double iratio = 1,
40 std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger())
41 : logger(std::move(ilogger)),
42 rateSupplier(irateSupplier),
43 input(iinput),
44 output(ioutput),
45 controller(icontroller),
46 ratio(iratio) {
47 }
48
50
52
53 ~AsyncWrapper() override {
54 dtorCalled.store(true, std::memory_order_release);
55 delete task;
56 }
57
61 void setTarget(const Input itarget) override {
62 LOG_INFO("AsyncWrapper: Set target to " + std::to_string(itarget));
63 hasFirstTarget = true;
64 controller->setTarget(itarget * ratio);
65 lastTarget = itarget;
66 }
67
74 void controllerSet(const Input ivalue) override {
75 controller->controllerSet(ivalue);
76 }
77
83 Input getTarget() override {
84 return controller->getTarget();
85 }
86
90 Input getProcessValue() const override {
91 return controller->getProcessValue();
92 }
93
97 Output getOutput() const {
98 return controller->getOutput();
99 }
100
104 Output getError() const override {
105 return controller->getError();
106 }
107
116 bool isSettled() override {
117 return isDisabled() || controller->isSettled();
118 }
119
125 void setSampleTime(const QTime &isampleTime) {
126 controller->setSampleTime(isampleTime);
127 }
128
135 void setOutputLimits(const Output imax, const Output imin) {
136 controller->setOutputLimits(imax, imin);
137 }
138
146 void setControllerSetTargetLimits(double itargetMax, double itargetMin) {
147 controller->setControllerSetTargetLimits(itargetMax, itargetMin);
148 }
149
155 Output getMaxOutput() {
156 return controller->getMaxOutput();
157 }
158
164 Output getMinOutput() {
165 return controller->getMinOutput();
166 }
167
172 void reset() override {
173 LOG_INFO_S("AsyncWrapper: Reset");
174 controller->reset();
175 hasFirstTarget = false;
176 }
177
182 void flipDisable() override {
183 LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(!controller->isDisabled()));
184 controller->flipDisable();
186 }
187
194 void flipDisable(const bool iisDisabled) override {
195 LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(iisDisabled));
196 controller->flipDisable(iisDisabled);
198 }
199
205 bool isDisabled() const override {
206 return controller->isDisabled();
207 }
208
213 void waitUntilSettled() override {
214 LOG_INFO_S("AsyncWrapper: Waiting to settle");
215
216 auto rate = rateSupplier.get();
217 while (!isSettled()) {
218 rate->delayUntil(motorUpdateRate);
219 }
220
221 LOG_INFO_S("AsyncWrapper: Done waiting to settle");
222 }
223
228 void startThread() {
229 if (!task) {
230 task = new CrossplatformThread(trampoline, this, "AsyncWrapper");
231 }
232 }
233
240 return task;
241 }
242
243 protected:
244 std::shared_ptr<Logger> logger;
246 std::shared_ptr<ControllerInput<Input>> input;
247 std::shared_ptr<ControllerOutput<Output>> output;
248 std::shared_ptr<IterativeController<Input, Output>> controller;
249 bool hasFirstTarget{false};
251 double ratio;
252 std::atomic_bool dtorCalled{false};
254
255 static void trampoline(void *context) {
256 if (context) {
257 static_cast<AsyncWrapper *>(context)->loop();
258 }
259 }
260
261 void loop() {
262 auto rate = rateSupplier.get();
263 while (!dtorCalled.load(std::memory_order_acquire) && !task->notifyTake(0)) {
264 if (!isDisabled()) {
265 output->controllerSet(controller->step(input->controllerGet()));
266 }
267
268 rate->delayUntil(controller->getSampleTime());
269 }
270 }
271
276 virtual void resumeMovement() {
277 if (isDisabled()) {
278 // This will grab the output *when disabled*
279 output->controllerSet(controller->getOutput());
280 } else {
281 if (hasFirstTarget) {
283 }
284 }
285 }
286};
287} // namespace okapi
std::uint32_t notifyTake(const std::uint32_t itimeout)
Closed-loop controller that steps on its own in another thread and automatically writes to the output...
void waitUntilSettled() override
Blocks the current task until the controller has settled.
Input getTarget() override
Gets the last set target, or the default target if none was set.
CrossplatformThread * getThread() const
Returns the underlying thread handle.
Output getMinOutput()
Get the lower output bound.
std::shared_ptr< IterativeController< Input, Output > > controller
void startThread()
Starts the internal thread.
Output getError() const override
Returns the last error of the controller.
void setOutputLimits(const Output imax, const Output imin)
Set controller output bounds.
virtual void resumeMovement()
Resumes moving after the controller is reset.
AsyncWrapper(AsyncWrapper< Input, Output > &&other)=delete
Output getOutput() const
Returns the last calculated output of the controller.
std::shared_ptr< ControllerOutput< Output > > output
bool isDisabled() const override
Returns whether the controller is currently disabled.
CrossplatformThread * task
bool isSettled() override
Returns whether the controller has settled at the target.
void reset() override
Resets the controller's internal state so it is similar to when it was first initialized,...
Output getMaxOutput()
Get the upper output bound.
std::shared_ptr< ControllerInput< Input > > input
std::shared_ptr< Logger > logger
void setControllerSetTargetLimits(double itargetMax, double itargetMin)
Sets the (soft) limits for the target range that controllerSet() scales into.
void setTarget(const Input itarget) override
Sets the target for the controller.
AsyncWrapper< Input, Output > & operator=(AsyncWrapper< Input, Output > &&other)=delete
static void trampoline(void *context)
std::atomic_bool dtorCalled
void flipDisable(const bool iisDisabled) override
Sets whether the controller is off or on.
Input getProcessValue() const override
AsyncWrapper(const std::shared_ptr< ControllerInput< Input > > &iinput, const std::shared_ptr< ControllerOutput< Output > > &ioutput, const std::shared_ptr< IterativeController< Input, Output > > &icontroller, const Supplier< std::unique_ptr< AbstractRate > > &irateSupplier, const double iratio=1, std::shared_ptr< Logger > ilogger=Logger::getDefaultLogger())
A wrapper class that transforms an IterativeController into an AsyncController by running it in anoth...
Supplier< std::unique_ptr< AbstractRate > > rateSupplier
void controllerSet(const Input ivalue) override
Writes the value of the controller output.
void flipDisable() override
Changes whether the controller is off or on.
void setSampleTime(const QTime &isampleTime)
Set time between loops.
Closed-loop controller that steps iteratively using the step method below.
static std::shared_ptr< Logger > getDefaultLogger()
A supplier of instances of T.
Definition supplier.hpp:16
#define LOG_INFO_S(msg)
Definition logging.hpp:25
#define LOG_INFO(msg)
Definition logging.hpp:20
static constexpr std::int8_t motorUpdateRate
The polling frequency of V5 motors in milliseconds.
Definition mathUtil.hpp:108
STL namespace.