blob: 0e5c144df6de8adb2b880d07401d206c69930712 [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
4#include <cstring>
5
brians343bc112013-02-10 01:53:46 +00006#include "aos/common/control_loop/Timing.h"
brians343bc112013-02-10 01:53:46 +00007#include "aos/common/type_traits.h"
Brian Silvermanf665d692013-02-17 22:11:39 -08008#include "aos/common/queue.h"
Brian Silverman3204dd82013-03-12 18:42:01 -07009#include "aos/common/time.h"
Brian Silverman50a9d032014-02-16 17:20:57 -080010#include "aos/common/util/log_interval.h"
brians343bc112013-02-10 01:53:46 +000011
12namespace aos {
13namespace control_loops {
14
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.
Brian Silverman1c3cfc02013-10-25 17:02:19 -070041constexpr time::Time kLoopFrequency = time::Time::InSeconds(0.01);
Brian Silverman3204dd82013-03-12 18:42:01 -070042
Brian Silverman15ca9852013-03-17 18:24:15 -070043// Calculates the next time to run control loops after start.
44time::Time NextLoopTime(time::Time start = time::Time::Now());
45
brians343bc112013-02-10 01:53:46 +000046// Provides helper methods to assist in writing control loops.
47// This template expects to be constructed with a queue group as an argument
48// that has a goal, position, status, and output queue.
49// It will then call the RunIteration method every cycle that it has enough
50// valid data for the control loop to run.
51// If has_position is false, the control loop will always use NULL as the
52// position and not check the queue. This is used for "loops" that control
53// motors open loop.
Brian Silverman71fbee02014-03-13 17:24:54 -070054template <class T, bool has_position = true, bool fail_no_position = true,
55 bool fail_no_goal = true>
brians343bc112013-02-10 01:53:46 +000056class ControlLoop : public SerializableControlLoop {
57 public:
58 // Maximum age of position packets before the loop will be disabled due to
59 // invalid position data.
Austin Schuhfa033692013-02-24 01:00:55 -080060 static const int kPositionTimeoutMs = 1000;
brians343bc112013-02-10 01:53:46 +000061 // Maximum age of driver station packets before the loop will be disabled.
Austin Schuhfa033692013-02-24 01:00:55 -080062 static const int kDSPacketTimeoutMs = 500;
brians343bc112013-02-10 01:53:46 +000063
Austin Schuh3d6e3df2014-02-17 01:51:03 -080064 ControlLoop(T *control_loop)
65 : control_loop_(control_loop),
66 reset_(true),
67 has_sensor_reset_counters_(false) {}
brians343bc112013-02-10 01:53:46 +000068 // Create some convenient typedefs to reference the Goal, Position, Status,
69 // and Output structures.
70 typedef typename std::remove_reference<
71 decltype(*(static_cast<T *>(NULL)->goal.MakeMessage().get()))>::type
72 GoalType;
73 typedef typename std::remove_reference<
74 decltype(*(static_cast<T *>(NULL)->position.MakeMessage().get()))>::type
75 PositionType;
76 typedef typename std::remove_reference<
77 decltype(*(static_cast<T *>(NULL)->status.MakeMessage().get()))>::type
78 StatusType;
79 typedef typename std::remove_reference<
80 decltype(*(static_cast<T *>(NULL)->output.MakeMessage().get()))>::type
81 OutputType;
82
Brian Silvermand1e65b92014-03-08 17:07:14 -080083 // Constructs and sends a message on the output queue which sets everything to
84 // a safe state (generally motors off). For some subclasses, this will be a
85 // bit different (ie pistons).
86 // The implementation here creates a new Output message, calls Zero() on it,
87 // and then sends it.
88 virtual void ZeroOutputs();
brians343bc112013-02-10 01:53:46 +000089
Austin Schuh3d6e3df2014-02-17 01:51:03 -080090 // Returns true if the device reading the sensors reset and potentially lost
Ben Fredrickson4283bb42014-02-22 08:31:50 +000091 // track of encoder counts. Calling this read method clears the flag. After
92 // a reset, RunIteration will not be called until there is a valid position
93 // message.
Austin Schuh3d6e3df2014-02-17 01:51:03 -080094 bool reset() {
95 bool ans = reset_;
96 reset_ = false;
97 return ans;
98 }
99
brians343bc112013-02-10 01:53:46 +0000100 // Sets the output to zero.
101 // Over-ride if a value of zero is not "off" for this subsystem.
102 virtual void Zero(OutputType *output) { output->Zero(); }
103
104 // Runs the loop forever.
105 virtual void Run();
106
107 // Runs one cycle of the loop.
108 virtual void Iterate();
109
110 // Returns the name of the queue group.
111 const char *name() { return control_loop_->name(); }
112
113 // Methods to serialize all the data that should be sent over the network.
114 virtual size_t SeralizedSize() { return control_loop_->goal->Size(); }
115 virtual void Serialize(char *buffer) const {
116 control_loop_->goal->Serialize(buffer);
117 }
118 virtual void SerializeZeroMessage(char *buffer) const {
119 GoalType zero_goal;
120 zero_goal.Zero();
121 zero_goal.Serialize(buffer);
122 }
123
124 virtual void Deserialize(const char *buffer) {
125 ScopedMessagePtr<GoalType> new_msg = control_loop_->goal.MakeMessage();
126 new_msg->Deserialize(buffer);
127 new_msg.Send();
128 }
129
130 virtual uint32_t UniqueID() { return control_loop_->hash(); }
131
132 protected:
133 // Runs an iteration of the control loop.
134 // goal is the last goal that was sent. It might be any number of cycles old.
135 // position is the current position, or NULL if we didn't get a position this
136 // cycle.
137 // output is the values to be sent to the motors. This is NULL if the output
138 // is going to be ignored and set to 0.
139 // status is the status of the control loop.
140 // Both output and status should be filled in by the implementation.
141 virtual void RunIteration(const GoalType *goal,
142 const PositionType *position,
143 OutputType *output,
144 StatusType *status) = 0;
145
Brian Silvermand1e65b92014-03-08 17:07:14 -0800146 T *queue_group() { return control_loop_; }
147 const T *queue_group() const { return control_loop_; }
148
brians343bc112013-02-10 01:53:46 +0000149 private:
150 // Pointer to the queue group
151 T *control_loop_;
Brian Silverman50a9d032014-02-16 17:20:57 -0800152
Austin Schuh3d6e3df2014-02-17 01:51:03 -0800153 bool reset_;
154 bool has_sensor_reset_counters_;
155 int32_t reader_pid_;
156 uint32_t cape_resets_;
157
Brian Silverman50a9d032014-02-16 17:20:57 -0800158 typedef ::aos::util::SimpleLogInterval SimpleLogInterval;
159 static constexpr ::aos::time::Time kStaleLogInterval =
160 ::aos::time::Time::InSeconds(0.1);
161 SimpleLogInterval very_stale_position_ =
162 SimpleLogInterval(kStaleLogInterval, ERROR,
163 "outputs disabled because position is very stale");
164 SimpleLogInterval no_prior_goal_ =
165 SimpleLogInterval(kStaleLogInterval, ERROR,
166 "no prior goal");
167 SimpleLogInterval no_prior_position_ =
168 SimpleLogInterval(kStaleLogInterval, ERROR,
169 "no prior position");
170 SimpleLogInterval no_driver_station_ =
171 SimpleLogInterval(kStaleLogInterval, ERROR,
172 "no driver station packet");
173 SimpleLogInterval driver_station_old_ =
174 SimpleLogInterval(kStaleLogInterval, ERROR,
175 "driver station packet is too old");
Brian Silverman4910efb2014-02-17 11:10:10 -0800176 SimpleLogInterval no_sensor_generation_ =
177 SimpleLogInterval(kStaleLogInterval, ERROR,
178 "no sensor_generation message");
brians343bc112013-02-10 01:53:46 +0000179};
180
181} // namespace control_loops
182} // namespace aos
183
184#include "aos/common/control_loop/ControlLoop-tmpl.h" // IWYU pragma: export
185
186#endif