blob: fd63e3fee1d4b5344afcbaebf6059f11e9bec1f6 [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
John Park33858a32018-09-28 23:05:48 -07007#include "aos/queue.h"
8#include "aos/time/time.h"
9#include "aos/type_traits/type_traits.h"
10#include "aos/util/log_interval.h"
brians343bc112013-02-10 01:53:46 +000011
12namespace aos {
Brian Silverman38111502014-04-10 12:36:26 -070013namespace controls {
brians343bc112013-02-10 01:53:46 +000014
15// Interface to describe runnable jobs.
16class Runnable {
17 public:
18 virtual ~Runnable() {}
19 // Runs forever.
20 virtual void Run() = 0;
21 // Does one quick piece of work and return. Does _not_ block.
22 virtual void Iterate() = 0;
23};
24
25class SerializableControlLoop : public Runnable {
26 public:
27 // Returns the size of all the data to be sent when serialized.
28 virtual size_t SeralizedSize() = 0;
29 // Serialize the current data.
30 virtual void Serialize(char *buffer) const = 0;
31 // Serialize zeroed data in case the data is out of date.
32 virtual void SerializeZeroMessage(char *buffer) const = 0;
33 // Deserialize data into the control loop.
34 virtual void Deserialize(const char *buffer) = 0;
35 // Unique identifier for the control loop.
36 // Most likely the hash of the queue group.
37 virtual uint32_t UniqueID() = 0;
38};
39
Brian Silverman3204dd82013-03-12 18:42:01 -070040// Control loops run this often, "starting" at time 0.
Austin Schuh214e9c12016-11-25 17:26:20 -080041constexpr ::std::chrono::nanoseconds kLoopFrequency =
42 ::std::chrono::milliseconds(5);
Brian Silverman3204dd82013-03-12 18:42:01 -070043
brians343bc112013-02-10 01:53:46 +000044// Provides helper methods to assist in writing control loops.
45// This template expects to be constructed with a queue group as an argument
46// that has a goal, position, status, and output queue.
47// It will then call the RunIteration method every cycle that it has enough
48// valid data for the control loop to run.
Brian Silverman089f5812015-02-15 01:58:19 -050049template <class T>
brians343bc112013-02-10 01:53:46 +000050class ControlLoop : public SerializableControlLoop {
51 public:
brians343bc112013-02-10 01:53:46 +000052 // Create some convenient typedefs to reference the Goal, Position, Status,
53 // and Output structures.
54 typedef typename std::remove_reference<
55 decltype(*(static_cast<T *>(NULL)->goal.MakeMessage().get()))>::type
56 GoalType;
57 typedef typename std::remove_reference<
58 decltype(*(static_cast<T *>(NULL)->position.MakeMessage().get()))>::type
59 PositionType;
60 typedef typename std::remove_reference<
61 decltype(*(static_cast<T *>(NULL)->status.MakeMessage().get()))>::type
62 StatusType;
63 typedef typename std::remove_reference<
64 decltype(*(static_cast<T *>(NULL)->output.MakeMessage().get()))>::type
65 OutputType;
66
Brian Silverman699f0cb2015-02-05 19:45:01 -050067 ControlLoop(T *control_loop) : control_loop_(control_loop) {}
68
69 // Returns true if all the counters etc in the sensor data have been reset.
70 // This will return true only a single time per reset.
71 bool WasReset() {
72 if (reset_) {
73 reset_ = false;
74 return true;
75 } else {
76 return false;
77 }
78 }
79
Brian Silvermand1e65b92014-03-08 17:07:14 -080080 // Constructs and sends a message on the output queue which sets everything to
81 // a safe state (generally motors off). For some subclasses, this will be a
82 // bit different (ie pistons).
83 // The implementation here creates a new Output message, calls Zero() on it,
84 // and then sends it.
85 virtual void ZeroOutputs();
brians343bc112013-02-10 01:53:46 +000086
87 // Sets the output to zero.
88 // Over-ride if a value of zero is not "off" for this subsystem.
89 virtual void Zero(OutputType *output) { output->Zero(); }
90
91 // Runs the loop forever.
Brian Silverman699f0cb2015-02-05 19:45:01 -050092 void Run() override;
brians343bc112013-02-10 01:53:46 +000093
94 // Runs one cycle of the loop.
Brian Silverman699f0cb2015-02-05 19:45:01 -050095 void Iterate() override;
brians343bc112013-02-10 01:53:46 +000096
97 // Returns the name of the queue group.
98 const char *name() { return control_loop_->name(); }
99
100 // Methods to serialize all the data that should be sent over the network.
Brian Silverman699f0cb2015-02-05 19:45:01 -0500101 size_t SeralizedSize() override { return control_loop_->goal->Size(); }
102 void Serialize(char *buffer) const override {
brians343bc112013-02-10 01:53:46 +0000103 control_loop_->goal->Serialize(buffer);
104 }
Brian Silverman699f0cb2015-02-05 19:45:01 -0500105 void SerializeZeroMessage(char *buffer) const override {
brians343bc112013-02-10 01:53:46 +0000106 GoalType zero_goal;
107 zero_goal.Zero();
108 zero_goal.Serialize(buffer);
109 }
110
Brian Silverman699f0cb2015-02-05 19:45:01 -0500111 void Deserialize(const char *buffer) override {
brians343bc112013-02-10 01:53:46 +0000112 ScopedMessagePtr<GoalType> new_msg = control_loop_->goal.MakeMessage();
113 new_msg->Deserialize(buffer);
114 new_msg.Send();
115 }
116
Brian Silverman699f0cb2015-02-05 19:45:01 -0500117 uint32_t UniqueID() override { return control_loop_->hash(); }
brians343bc112013-02-10 01:53:46 +0000118
Austin Schuhb58ceb62017-02-05 14:21:57 -0800119
brians343bc112013-02-10 01:53:46 +0000120 protected:
Austin Schuhb58ceb62017-02-05 14:21:57 -0800121 static void Quit(int /*signum*/) {
122 run_ = false;
123 }
124
brians343bc112013-02-10 01:53:46 +0000125 // Runs an iteration of the control loop.
Brian Silverman089f5812015-02-15 01:58:19 -0500126 // goal is the last goal that was sent. It might be any number of cycles old
127 // or nullptr if we haven't ever received a goal.
128 // position is the current position, or nullptr if we didn't get a position
129 // this cycle.
130 // output is the values to be sent to the motors. This is nullptr if the
131 // output is going to be ignored and set to 0.
brians343bc112013-02-10 01:53:46 +0000132 // status is the status of the control loop.
133 // Both output and status should be filled in by the implementation.
134 virtual void RunIteration(const GoalType *goal,
135 const PositionType *position,
136 OutputType *output,
137 StatusType *status) = 0;
138
Brian Silvermand1e65b92014-03-08 17:07:14 -0800139 T *queue_group() { return control_loop_; }
140 const T *queue_group() const { return control_loop_; }
141
brians343bc112013-02-10 01:53:46 +0000142 private:
Austin Schuh61bdc602016-12-04 19:10:10 -0800143 static constexpr ::std::chrono::milliseconds kStaleLogInterval =
144 ::std::chrono::milliseconds(100);
Brian Silverman699f0cb2015-02-05 19:45:01 -0500145 // The amount of time after the last PWM pulse we consider motors enabled for.
146 // 100ms is the result of using an oscilliscope to look at the input and
147 // output of a Talon. The Info Sheet also lists 100ms for Talon SR, Talon SRX,
148 // and Victor SP.
Austin Schuh61bdc602016-12-04 19:10:10 -0800149 static constexpr ::std::chrono::milliseconds kPwmDisableTime =
150 ::std::chrono::milliseconds(100);
Brian Silverman699f0cb2015-02-05 19:45:01 -0500151
brians343bc112013-02-10 01:53:46 +0000152 // Pointer to the queue group
153 T *control_loop_;
Brian Silverman50a9d032014-02-16 17:20:57 -0800154
Brian Silverman699f0cb2015-02-05 19:45:01 -0500155 bool reset_ = false;
156 int32_t sensor_reader_pid_ = 0;
157
Austin Schuh61bdc602016-12-04 19:10:10 -0800158 ::aos::monotonic_clock::time_point last_pwm_sent_ =
159 ::aos::monotonic_clock::min_time;
Austin Schuh3d6e3df2014-02-17 01:51:03 -0800160
Brian Silverman50a9d032014-02-16 17:20:57 -0800161 typedef ::aos::util::SimpleLogInterval SimpleLogInterval;
Brian Silverman699f0cb2015-02-05 19:45:01 -0500162 SimpleLogInterval no_sensor_state_ =
163 SimpleLogInterval(kStaleLogInterval, ERROR, "no sensor state");
Brian Silverman2704ecf2014-04-09 20:24:03 -0700164 SimpleLogInterval motors_off_log_ =
165 SimpleLogInterval(kStaleLogInterval, WARNING, "motors disabled");
Brian Silverman699f0cb2015-02-05 19:45:01 -0500166 SimpleLogInterval no_goal_ =
167 SimpleLogInterval(kStaleLogInterval, ERROR, "no goal");
Austin Schuhb58ceb62017-02-05 14:21:57 -0800168
169 static ::std::atomic<bool> run_;
brians343bc112013-02-10 01:53:46 +0000170};
171
Brian Silverman38111502014-04-10 12:36:26 -0700172} // namespace controls
brians343bc112013-02-10 01:53:46 +0000173} // namespace aos
174
John Park33858a32018-09-28 23:05:48 -0700175#include "aos/controls/control_loop-tmpl.h" // IWYU pragma: export
brians343bc112013-02-10 01:53:46 +0000176
177#endif