WPILibC++ 2027.0.0-alpha-4
Loading...
Searching...
No Matches
PeriodicOpMode.hpp
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <stdint.h>
8
9#include <chrono>
10#include <functional>
11#include <vector>
12
13#include "wpi/hal/Notifier.h"
14#include "wpi/hal/Types.hpp"
15#include "wpi/opmode/OpMode.hpp"
17#include "wpi/units/time.hpp"
19
20namespace wpi {
21
22/**
23 * An opmode structure for periodic operation. This base class implements a loop
24 * that runs one or more functions periodically (on a set time interval aka loop
25 * period). The primary periodic callback function is the Periodic() function;
26 * the time interval for this callback is 20 ms by default, but may be changed
27 * via passing a different time interval to the constructor. Additional periodic
28 * callbacks with different intervals can be added using the AddPeriodic() set
29 * of functions.
30 *
31 * Lifecycle:
32 *
33 * - Constructed when opmode selected on driver station
34 *
35 * - DisabledPeriodic() called periodically as long as DS is disabled. Note
36 * this is not called on a set time interval (it does not use the same time
37 * interval as Periodic())
38 *
39 * - When DS transitions from disabled to enabled, Start() is called once
40 *
41 * - While DS is enabled, Periodic() is called periodically on the time interval
42 * set by the constructor, and additional periodic callbacks added via
43 * AddPeriodic() are called periodically on their set time intervals
44 *
45 * - When DS transitions from enabled to disabled, or a different opmode is
46 * selected on the driver station when the DS is enabled, End() is called,
47 * followed by the object being destroyed; the object is not reused
48 *
49 * - If a different opmode is selected on the driver station when the DS is
50 * disabled, the object is destroyed (without End() being called); the object
51 * is not reused
52 */
53class PeriodicOpMode : public OpMode {
54 public:
55 /** Default loop period. */
56 static constexpr auto kDefaultPeriod = 20_ms;
57
58 protected:
59 /**
60 * Constructor. Periodic opmodes may specify the period used for the
61 * Periodic() function.
62 *
63 * @param period period for callbacks to the Periodic() function
64 */
65 explicit PeriodicOpMode(wpi::units::second_t period = kDefaultPeriod);
66
67 public:
68 ~PeriodicOpMode() override;
69
70 /**
71 * Called periodically while the opmode is selected on the DS (robot is
72 * disabled).
73 */
74 void DisabledPeriodic() override {}
75
76 /**
77 * Called a single time when the robot transitions from disabled to enabled.
78 * This is called prior to Periodic() being called.
79 */
80 virtual void Start() {}
81
82 /** Called periodically while the robot is enabled. */
83 virtual void Periodic() = 0;
84
85 /**
86 * Called a single time when the robot transitions from enabled to disabled,
87 * or just before the destructor is called if a different opmode is selected
88 * while the robot is enabled.
89 */
90 virtual void End() {}
91
92 /**
93 * Return the system clock time in microseconds for the start of the current
94 * periodic loop. This is in the same time base as Timer.getFPGATimestamp(),
95 * but is stable through a loop. It is updated at the beginning of every
96 * periodic callback (including the normal periodic loop).
97 *
98 * @return Robot running time in microseconds, as of the start of the current
99 * periodic function.
100 */
101 int64_t GetLoopStartTime() const { return m_loopStartTimeUs; }
102
103 /**
104 * Add a callback to run at a specific period with a starting time offset.
105 *
106 * This is scheduled on the same Notifier as Periodic(), so Periodic() and the
107 * callback run synchronously. Interactions between them are thread-safe.
108 *
109 * @param callback The callback to run.
110 * @param period The period at which to run the callback.
111 * @param offset The offset from the common starting time. This is useful
112 * for scheduling a callback in a different timeslot relative
113 * to TimedRobot.
114 */
115 void AddPeriodic(std::function<void()> callback, wpi::units::second_t period,
116 wpi::units::second_t offset = 0_s);
117
118 /**
119 * Gets time period between calls to Periodic() functions.
120 */
121 wpi::units::second_t GetPeriod() const { return m_period; }
122
123 /**
124 * Prints list of epochs added so far and their times.
125 */
127
128 protected:
129 /** Loop function. */
130 void LoopFunc();
131
132 public:
133 // implements OpMode interface
134 void OpModeRun(int64_t opModeId) final;
135
136 void OpModeStop() final;
137
138 private:
139 class Callback {
140 public:
141 std::function<void()> func;
142 std::chrono::microseconds period;
143 std::chrono::microseconds expirationTime;
144
145 /**
146 * Construct a callback container.
147 *
148 * @param func The callback to run.
149 * @param startTime The common starting point for all callback scheduling.
150 * @param period The period at which to run the callback.
151 * @param offset The offset from the common starting time.
152 */
153 Callback(std::function<void()> func, std::chrono::microseconds startTime,
154 std::chrono::microseconds period,
155 std::chrono::microseconds offset);
156
157 bool operator>(const Callback& rhs) const {
158 return expirationTime > rhs.expirationTime;
159 }
160 };
161
162 int64_t m_opModeId;
163 bool m_running = true;
164
166 std::chrono::microseconds m_startTime;
167 int64_t m_loopStartTimeUs = 0;
168 wpi::units::second_t m_period;
169 Watchdog m_watchdog;
170
172 std::greater<Callback>>
173 m_callbacks;
174
175 void PrintLoopOverrunMessage();
176};
177
178} // namespace wpi
Top-level interface for opmode classes.
Definition OpMode.hpp:16
void LoopFunc()
Loop function.
~PeriodicOpMode() override
virtual void End()
Called a single time when the robot transitions from enabled to disabled, or just before the destruct...
Definition PeriodicOpMode.hpp:90
PeriodicOpMode(wpi::units::second_t period=kDefaultPeriod)
Constructor.
virtual void Start()
Called a single time when the robot transitions from disabled to enabled.
Definition PeriodicOpMode.hpp:80
void AddPeriodic(std::function< void()> callback, wpi::units::second_t period, wpi::units::second_t offset=0_s)
Add a callback to run at a specific period with a starting time offset.
int64_t GetLoopStartTime() const
Return the system clock time in microseconds for the start of the current periodic loop.
Definition PeriodicOpMode.hpp:101
virtual void Periodic()=0
Called periodically while the robot is enabled.
static constexpr auto kDefaultPeriod
Default loop period.
Definition PeriodicOpMode.hpp:56
void DisabledPeriodic() override
Called periodically while the opmode is selected on the DS (robot is disabled).
Definition PeriodicOpMode.hpp:74
void OpModeStop() final
This function is called asynchronously when the robot is disabled, to request the opmode return from ...
void PrintWatchdogEpochs()
Prints list of epochs added so far and their times.
wpi::units::second_t GetPeriod() const
Gets time period between calls to Periodic() functions.
Definition PeriodicOpMode.hpp:121
void OpModeRun(int64_t opModeId) final
This function is called when the opmode starts (robot is enabled).
A class that's a wrapper around a watchdog timer.
Definition Watchdog.hpp:25
A move-only C++ wrapper around a HAL handle.
Definition Types.hpp:16
This class is the same as std::priority_queue with two changes:
Definition priority_queue.hpp:26
Definition CvSource.hpp:15