blob: 0b6e391f36cf8683c4fca6d843cbaca4c17d5223 [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"
10#include "aos/time/time.h"
11#include "aos/type_traits/type_traits.h"
12#include "aos/util/log_interval.h"
brians343bc112013-02-10 01:53:46 +000013
14namespace aos {
Brian Silverman38111502014-04-10 12:36:26 -070015namespace controls {
brians343bc112013-02-10 01:53:46 +000016
17// Interface to describe runnable jobs.
18class Runnable {
19 public:
20 virtual ~Runnable() {}
21 // Runs forever.
22 virtual void Run() = 0;
23 // Does one quick piece of work and return. Does _not_ block.
24 virtual void Iterate() = 0;
25};
26
Brian Silverman3204dd82013-03-12 18:42:01 -070027// Control loops run this often, "starting" at time 0.
Austin Schuh214e9c12016-11-25 17:26:20 -080028constexpr ::std::chrono::nanoseconds kLoopFrequency =
29 ::std::chrono::milliseconds(5);
Brian Silverman3204dd82013-03-12 18:42:01 -070030
brians343bc112013-02-10 01:53:46 +000031// Provides helper methods to assist in writing control loops.
32// This template expects to be constructed with a queue group as an argument
33// that has a goal, position, status, and output queue.
34// It will then call the RunIteration method every cycle that it has enough
35// valid data for the control loop to run.
Brian Silverman089f5812015-02-15 01:58:19 -050036template <class T>
Austin Schuhfd6e16c2019-01-27 12:22:47 -080037class ControlLoop : public Runnable {
brians343bc112013-02-10 01:53:46 +000038 public:
brians343bc112013-02-10 01:53:46 +000039 // Create some convenient typedefs to reference the Goal, Position, Status,
40 // and Output structures.
41 typedef typename std::remove_reference<
42 decltype(*(static_cast<T *>(NULL)->goal.MakeMessage().get()))>::type
43 GoalType;
44 typedef typename std::remove_reference<
45 decltype(*(static_cast<T *>(NULL)->position.MakeMessage().get()))>::type
46 PositionType;
47 typedef typename std::remove_reference<
48 decltype(*(static_cast<T *>(NULL)->status.MakeMessage().get()))>::type
49 StatusType;
50 typedef typename std::remove_reference<
51 decltype(*(static_cast<T *>(NULL)->output.MakeMessage().get()))>::type
52 OutputType;
53
Austin Schuha1654ed2019-01-27 17:24:54 -080054 ControlLoop(T *control_loop)
55 : event_loop_(new ::aos::ShmEventLoop()), control_loop_(control_loop) {
56 output_sender_ = event_loop_->MakeSender<OutputType>(
57 ::std::string(control_loop_->name()) + ".output");
58 status_sender_ = event_loop_->MakeSender<StatusType>(
59 ::std::string(control_loop_->name()) + ".status");
60 goal_fetcher_ = event_loop_->MakeFetcher<GoalType>(
61 ::std::string(control_loop_->name()) + ".goal");
62 }
Brian Silverman699f0cb2015-02-05 19:45:01 -050063
64 // Returns true if all the counters etc in the sensor data have been reset.
65 // This will return true only a single time per reset.
66 bool WasReset() {
67 if (reset_) {
68 reset_ = false;
69 return true;
70 } else {
71 return false;
72 }
73 }
74
Brian Silvermand1e65b92014-03-08 17:07:14 -080075 // Constructs and sends a message on the output queue which sets everything to
Austin Schuhaebfb4f2019-01-27 13:26:38 -080076 // a safe state. Default is to set everything to zero. Override Zero below
77 // to change that behavior.
78 void ZeroOutputs();
brians343bc112013-02-10 01:53:46 +000079
80 // Sets the output to zero.
Austin Schuhaebfb4f2019-01-27 13:26:38 -080081 // Override this if a value of zero (or false) is not "off" for this
82 // subsystem.
brians343bc112013-02-10 01:53:46 +000083 virtual void Zero(OutputType *output) { output->Zero(); }
84
85 // Runs the loop forever.
Brian Silverman699f0cb2015-02-05 19:45:01 -050086 void Run() override;
brians343bc112013-02-10 01:53:46 +000087
88 // Runs one cycle of the loop.
Brian Silverman699f0cb2015-02-05 19:45:01 -050089 void Iterate() override;
brians343bc112013-02-10 01:53:46 +000090
brians343bc112013-02-10 01:53:46 +000091 protected:
Austin Schuha1654ed2019-01-27 17:24:54 -080092 void IteratePosition(const PositionType &position);
93
Austin Schuhb58ceb62017-02-05 14:21:57 -080094 static void Quit(int /*signum*/) {
95 run_ = false;
96 }
97
brians343bc112013-02-10 01:53:46 +000098 // Runs an iteration of the control loop.
Brian Silverman089f5812015-02-15 01:58:19 -050099 // goal is the last goal that was sent. It might be any number of cycles old
100 // or nullptr if we haven't ever received a goal.
101 // position is the current position, or nullptr if we didn't get a position
102 // this cycle.
103 // output is the values to be sent to the motors. This is nullptr if the
104 // output is going to be ignored and set to 0.
brians343bc112013-02-10 01:53:46 +0000105 // status is the status of the control loop.
106 // Both output and status should be filled in by the implementation.
107 virtual void RunIteration(const GoalType *goal,
108 const PositionType *position,
109 OutputType *output,
110 StatusType *status) = 0;
111
112 private:
Austin Schuh61bdc602016-12-04 19:10:10 -0800113 static constexpr ::std::chrono::milliseconds kStaleLogInterval =
114 ::std::chrono::milliseconds(100);
Brian Silverman699f0cb2015-02-05 19:45:01 -0500115 // The amount of time after the last PWM pulse we consider motors enabled for.
116 // 100ms is the result of using an oscilliscope to look at the input and
117 // output of a Talon. The Info Sheet also lists 100ms for Talon SR, Talon SRX,
118 // and Victor SP.
Austin Schuh61bdc602016-12-04 19:10:10 -0800119 static constexpr ::std::chrono::milliseconds kPwmDisableTime =
120 ::std::chrono::milliseconds(100);
Brian Silverman699f0cb2015-02-05 19:45:01 -0500121
brians343bc112013-02-10 01:53:46 +0000122 // Pointer to the queue group
Austin Schuha1654ed2019-01-27 17:24:54 -0800123 ::std::unique_ptr<EventLoop> event_loop_;
brians343bc112013-02-10 01:53:46 +0000124 T *control_loop_;
Brian Silverman50a9d032014-02-16 17:20:57 -0800125
Austin Schuha1654ed2019-01-27 17:24:54 -0800126 ::aos::Sender<OutputType> output_sender_;
127 ::aos::Sender<StatusType> status_sender_;
128 ::aos::Fetcher<GoalType> goal_fetcher_;
129
Brian Silverman699f0cb2015-02-05 19:45:01 -0500130 bool reset_ = false;
131 int32_t sensor_reader_pid_ = 0;
132
Austin Schuh61bdc602016-12-04 19:10:10 -0800133 ::aos::monotonic_clock::time_point last_pwm_sent_ =
134 ::aos::monotonic_clock::min_time;
Austin Schuh3d6e3df2014-02-17 01:51:03 -0800135
Brian Silverman50a9d032014-02-16 17:20:57 -0800136 typedef ::aos::util::SimpleLogInterval SimpleLogInterval;
Brian Silverman699f0cb2015-02-05 19:45:01 -0500137 SimpleLogInterval no_sensor_state_ =
138 SimpleLogInterval(kStaleLogInterval, ERROR, "no sensor state");
Brian Silverman2704ecf2014-04-09 20:24:03 -0700139 SimpleLogInterval motors_off_log_ =
140 SimpleLogInterval(kStaleLogInterval, WARNING, "motors disabled");
Brian Silverman699f0cb2015-02-05 19:45:01 -0500141 SimpleLogInterval no_goal_ =
142 SimpleLogInterval(kStaleLogInterval, ERROR, "no goal");
Austin Schuhb58ceb62017-02-05 14:21:57 -0800143
144 static ::std::atomic<bool> run_;
brians343bc112013-02-10 01:53:46 +0000145};
146
Brian Silverman38111502014-04-10 12:36:26 -0700147} // namespace controls
brians343bc112013-02-10 01:53:46 +0000148} // namespace aos
149
John Park33858a32018-09-28 23:05:48 -0700150#include "aos/controls/control_loop-tmpl.h" // IWYU pragma: export
brians343bc112013-02-10 01:53:46 +0000151
152#endif