blob: 381fb32bce54aa4772f6ae0236ae10eb0992bc25 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#ifndef AOS_CONTROL_LOOP_CONTROL_LOOP_H_
2#define AOS_CONTROL_LOOP_CONTROL_LOOP_H_
3
Brian Silvermanb407c672014-04-09 11:58:37 -07004#include <string.h>
Austin Schuhb58ceb62017-02-05 14:21:57 -08005#include <atomic>
brians343bc112013-02-10 01:53:46 +00006
Austin Schuha1654ed2019-01-27 17:24:54 -08007#include "aos/events/event-loop.h"
8#include "aos/events/shm-event-loop.h"
John Park33858a32018-09-28 23:05:48 -07009#include "aos/queue.h"
Austin Schuheeec74a2019-01-27 20:58:59 -080010#include "aos/robot_state/robot_state.q.h"
John Park33858a32018-09-28 23:05:48 -070011#include "aos/time/time.h"
12#include "aos/type_traits/type_traits.h"
13#include "aos/util/log_interval.h"
brians343bc112013-02-10 01:53:46 +000014
15namespace aos {
Brian Silverman38111502014-04-10 12:36:26 -070016namespace controls {
brians343bc112013-02-10 01:53:46 +000017
18// Interface to describe runnable jobs.
19class Runnable {
20 public:
21 virtual ~Runnable() {}
22 // Runs forever.
23 virtual void Run() = 0;
24 // Does one quick piece of work and return. Does _not_ block.
25 virtual void Iterate() = 0;
26};
27
Brian Silverman3204dd82013-03-12 18:42:01 -070028// Control loops run this often, "starting" at time 0.
Austin Schuh214e9c12016-11-25 17:26:20 -080029constexpr ::std::chrono::nanoseconds kLoopFrequency =
30 ::std::chrono::milliseconds(5);
Brian Silverman3204dd82013-03-12 18:42:01 -070031
brians343bc112013-02-10 01:53:46 +000032// Provides helper methods to assist in writing control loops.
33// This template expects to be constructed with a queue group as an argument
34// that has a goal, position, status, and output queue.
35// It will then call the RunIteration method every cycle that it has enough
36// valid data for the control loop to run.
Brian Silverman089f5812015-02-15 01:58:19 -050037template <class T>
Austin Schuhfd6e16c2019-01-27 12:22:47 -080038class ControlLoop : public Runnable {
brians343bc112013-02-10 01:53:46 +000039 public:
brians343bc112013-02-10 01:53:46 +000040 // Create some convenient typedefs to reference the Goal, Position, Status,
41 // and Output structures.
42 typedef typename std::remove_reference<
43 decltype(*(static_cast<T *>(NULL)->goal.MakeMessage().get()))>::type
44 GoalType;
45 typedef typename std::remove_reference<
46 decltype(*(static_cast<T *>(NULL)->position.MakeMessage().get()))>::type
47 PositionType;
48 typedef typename std::remove_reference<
49 decltype(*(static_cast<T *>(NULL)->status.MakeMessage().get()))>::type
50 StatusType;
51 typedef typename std::remove_reference<
52 decltype(*(static_cast<T *>(NULL)->output.MakeMessage().get()))>::type
53 OutputType;
54
Austin Schuha1654ed2019-01-27 17:24:54 -080055 ControlLoop(T *control_loop)
Austin Schuheeec74a2019-01-27 20:58:59 -080056 : shm_event_loop_(new ::aos::ShmEventLoop()),
57 event_loop_(shm_event_loop_.get()),
58 name_(control_loop->name()) {
59 output_sender_ = event_loop_->MakeSender<OutputType>(name_ + ".output");
60 status_sender_ = event_loop_->MakeSender<StatusType>(name_ + ".status");
61 goal_fetcher_ = event_loop_->MakeFetcher<GoalType>(name_ + ".goal");
62 robot_state_fetcher_ =
63 event_loop_->MakeFetcher<::aos::RobotState>(".aos.robot_state");
64 joystick_state_fetcher_ =
65 event_loop_->MakeFetcher<::aos::JoystickState>(".aos.joystick_state");
66 }
67
68 const ::aos::RobotState &robot_state() const { return *robot_state_fetcher_; }
69 bool has_joystick_state() const { return joystick_state_fetcher_.get(); }
70 const ::aos::JoystickState &joystick_state() const {
71 return *joystick_state_fetcher_;
Austin Schuha1654ed2019-01-27 17:24:54 -080072 }
Brian Silverman699f0cb2015-02-05 19:45:01 -050073
Austin Schuh520f33d2019-01-27 22:38:01 -080074 ControlLoop(EventLoop *event_loop, const ::std::string &name)
75 : event_loop_(event_loop), name_(name) {
76 output_sender_ = event_loop_->MakeSender<OutputType>(name_ + ".output");
77 status_sender_ = event_loop_->MakeSender<StatusType>(name_ + ".status");
78 goal_fetcher_ = event_loop_->MakeFetcher<GoalType>(name_ + ".goal");
79 robot_state_fetcher_ =
80 event_loop_->MakeFetcher<::aos::RobotState>(".aos.robot_state");
81 joystick_state_fetcher_ =
82 event_loop_->MakeFetcher<::aos::JoystickState>(".aos.joystick_state");
83 }
84
Brian Silverman699f0cb2015-02-05 19:45:01 -050085 // Returns true if all the counters etc in the sensor data have been reset.
86 // This will return true only a single time per reset.
87 bool WasReset() {
88 if (reset_) {
89 reset_ = false;
90 return true;
91 } else {
92 return false;
93 }
94 }
95
Brian Silvermand1e65b92014-03-08 17:07:14 -080096 // Constructs and sends a message on the output queue which sets everything to
Austin Schuhaebfb4f2019-01-27 13:26:38 -080097 // a safe state. Default is to set everything to zero. Override Zero below
98 // to change that behavior.
99 void ZeroOutputs();
brians343bc112013-02-10 01:53:46 +0000100
101 // Sets the output to zero.
Austin Schuhaebfb4f2019-01-27 13:26:38 -0800102 // Override this if a value of zero (or false) is not "off" for this
103 // subsystem.
brians343bc112013-02-10 01:53:46 +0000104 virtual void Zero(OutputType *output) { output->Zero(); }
105
106 // Runs the loop forever.
Austin Schuh520f33d2019-01-27 22:38:01 -0800107 // TODO(austin): This should move to the event loop once it gets hoisted out.
Brian Silverman699f0cb2015-02-05 19:45:01 -0500108 void Run() override;
brians343bc112013-02-10 01:53:46 +0000109
110 // Runs one cycle of the loop.
Austin Schuh520f33d2019-01-27 22:38:01 -0800111 // TODO(austin): This should go away when all the tests use event loops
112 // directly.
Brian Silverman699f0cb2015-02-05 19:45:01 -0500113 void Iterate() override;
brians343bc112013-02-10 01:53:46 +0000114
brians343bc112013-02-10 01:53:46 +0000115 protected:
Austin Schuha1654ed2019-01-27 17:24:54 -0800116 void IteratePosition(const PositionType &position);
117
Austin Schuhb58ceb62017-02-05 14:21:57 -0800118 static void Quit(int /*signum*/) {
119 run_ = false;
120 }
121
brians343bc112013-02-10 01:53:46 +0000122 // Runs an iteration of the control loop.
Brian Silverman089f5812015-02-15 01:58:19 -0500123 // goal is the last goal that was sent. It might be any number of cycles old
124 // or nullptr if we haven't ever received a goal.
125 // position is the current position, or nullptr if we didn't get a position
126 // this cycle.
127 // output is the values to be sent to the motors. This is nullptr if the
128 // output is going to be ignored and set to 0.
brians343bc112013-02-10 01:53:46 +0000129 // status is the status of the control loop.
130 // Both output and status should be filled in by the implementation.
131 virtual void RunIteration(const GoalType *goal,
132 const PositionType *position,
133 OutputType *output,
134 StatusType *status) = 0;
135
136 private:
Austin Schuh61bdc602016-12-04 19:10:10 -0800137 static constexpr ::std::chrono::milliseconds kStaleLogInterval =
138 ::std::chrono::milliseconds(100);
Brian Silverman699f0cb2015-02-05 19:45:01 -0500139 // The amount of time after the last PWM pulse we consider motors enabled for.
140 // 100ms is the result of using an oscilliscope to look at the input and
141 // output of a Talon. The Info Sheet also lists 100ms for Talon SR, Talon SRX,
142 // and Victor SP.
Austin Schuh61bdc602016-12-04 19:10:10 -0800143 static constexpr ::std::chrono::milliseconds kPwmDisableTime =
144 ::std::chrono::milliseconds(100);
Brian Silverman699f0cb2015-02-05 19:45:01 -0500145
brians343bc112013-02-10 01:53:46 +0000146 // Pointer to the queue group
Austin Schuheeec74a2019-01-27 20:58:59 -0800147 ::std::unique_ptr<ShmEventLoop> shm_event_loop_;
148 EventLoop *event_loop_;
149 ::std::string name_;
Brian Silverman50a9d032014-02-16 17:20:57 -0800150
Austin Schuha1654ed2019-01-27 17:24:54 -0800151 ::aos::Sender<OutputType> output_sender_;
152 ::aos::Sender<StatusType> status_sender_;
153 ::aos::Fetcher<GoalType> goal_fetcher_;
Austin Schuheeec74a2019-01-27 20:58:59 -0800154 ::aos::Fetcher<::aos::RobotState> robot_state_fetcher_;
155 ::aos::Fetcher<::aos::JoystickState> joystick_state_fetcher_;
156
157 // Fetcher only to be used for the Iterate method. If Iterate is called, Run
158 // can't be called.
159 bool has_iterate_fetcher_ = false;
160 ::aos::Fetcher<PositionType> iterate_position_fetcher_;
Austin Schuha1654ed2019-01-27 17:24:54 -0800161
Brian Silverman699f0cb2015-02-05 19:45:01 -0500162 bool reset_ = false;
163 int32_t sensor_reader_pid_ = 0;
164
Austin Schuh61bdc602016-12-04 19:10:10 -0800165 ::aos::monotonic_clock::time_point last_pwm_sent_ =
166 ::aos::monotonic_clock::min_time;
Austin Schuh3d6e3df2014-02-17 01:51:03 -0800167
Brian Silverman50a9d032014-02-16 17:20:57 -0800168 typedef ::aos::util::SimpleLogInterval SimpleLogInterval;
Brian Silverman699f0cb2015-02-05 19:45:01 -0500169 SimpleLogInterval no_sensor_state_ =
170 SimpleLogInterval(kStaleLogInterval, ERROR, "no sensor state");
Brian Silverman2704ecf2014-04-09 20:24:03 -0700171 SimpleLogInterval motors_off_log_ =
172 SimpleLogInterval(kStaleLogInterval, WARNING, "motors disabled");
Brian Silverman699f0cb2015-02-05 19:45:01 -0500173 SimpleLogInterval no_goal_ =
174 SimpleLogInterval(kStaleLogInterval, ERROR, "no goal");
Austin Schuhb58ceb62017-02-05 14:21:57 -0800175
176 static ::std::atomic<bool> run_;
brians343bc112013-02-10 01:53:46 +0000177};
178
Brian Silverman38111502014-04-10 12:36:26 -0700179} // namespace controls
brians343bc112013-02-10 01:53:46 +0000180} // namespace aos
181
John Park33858a32018-09-28 23:05:48 -0700182#include "aos/controls/control_loop-tmpl.h" // IWYU pragma: export
brians343bc112013-02-10 01:53:46 +0000183
184#endif