blob: d48f01713a5e971b2f4c26164518a26a46448867 [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>
brians343bc112013-02-10 01:53:46 +00005
brians343bc112013-02-10 01:53:46 +00006#include "aos/common/type_traits.h"
Brian Silvermanf665d692013-02-17 22:11:39 -08007#include "aos/common/queue.h"
Brian Silverman3204dd82013-03-12 18:42:01 -07008#include "aos/common/time.h"
Brian Silverman50a9d032014-02-16 17:20:57 -08009#include "aos/common/util/log_interval.h"
brians343bc112013-02-10 01:53:46 +000010
11namespace aos {
Brian Silverman38111502014-04-10 12:36:26 -070012namespace controls {
brians343bc112013-02-10 01:53:46 +000013
14// Interface to describe runnable jobs.
15class Runnable {
16 public:
17 virtual ~Runnable() {}
18 // Runs forever.
19 virtual void Run() = 0;
20 // Does one quick piece of work and return. Does _not_ block.
21 virtual void Iterate() = 0;
22};
23
24class SerializableControlLoop : public Runnable {
25 public:
26 // Returns the size of all the data to be sent when serialized.
27 virtual size_t SeralizedSize() = 0;
28 // Serialize the current data.
29 virtual void Serialize(char *buffer) const = 0;
30 // Serialize zeroed data in case the data is out of date.
31 virtual void SerializeZeroMessage(char *buffer) const = 0;
32 // Deserialize data into the control loop.
33 virtual void Deserialize(const char *buffer) = 0;
34 // Unique identifier for the control loop.
35 // Most likely the hash of the queue group.
36 virtual uint32_t UniqueID() = 0;
37};
38
Brian Silverman3204dd82013-03-12 18:42:01 -070039// Control loops run this often, "starting" at time 0.
Brian Silverman1c3cfc02013-10-25 17:02:19 -070040constexpr time::Time kLoopFrequency = time::Time::InSeconds(0.01);
Brian Silverman3204dd82013-03-12 18:42:01 -070041
brians343bc112013-02-10 01:53:46 +000042// Provides helper methods to assist in writing control loops.
43// This template expects to be constructed with a queue group as an argument
44// that has a goal, position, status, and output queue.
45// It will then call the RunIteration method every cycle that it has enough
46// valid data for the control loop to run.
Brian Silverman089f5812015-02-15 01:58:19 -050047template <class T>
brians343bc112013-02-10 01:53:46 +000048class ControlLoop : public SerializableControlLoop {
49 public:
brians343bc112013-02-10 01:53:46 +000050 // Create some convenient typedefs to reference the Goal, Position, Status,
51 // and Output structures.
52 typedef typename std::remove_reference<
53 decltype(*(static_cast<T *>(NULL)->goal.MakeMessage().get()))>::type
54 GoalType;
55 typedef typename std::remove_reference<
56 decltype(*(static_cast<T *>(NULL)->position.MakeMessage().get()))>::type
57 PositionType;
58 typedef typename std::remove_reference<
59 decltype(*(static_cast<T *>(NULL)->status.MakeMessage().get()))>::type
60 StatusType;
61 typedef typename std::remove_reference<
62 decltype(*(static_cast<T *>(NULL)->output.MakeMessage().get()))>::type
63 OutputType;
64
Brian Silverman699f0cb2015-02-05 19:45:01 -050065 ControlLoop(T *control_loop) : control_loop_(control_loop) {}
66
67 // Returns true if all the counters etc in the sensor data have been reset.
68 // This will return true only a single time per reset.
69 bool WasReset() {
70 if (reset_) {
71 reset_ = false;
72 return true;
73 } else {
74 return false;
75 }
76 }
77
Brian Silvermand1e65b92014-03-08 17:07:14 -080078 // Constructs and sends a message on the output queue which sets everything to
79 // a safe state (generally motors off). For some subclasses, this will be a
80 // bit different (ie pistons).
81 // The implementation here creates a new Output message, calls Zero() on it,
82 // and then sends it.
83 virtual void ZeroOutputs();
brians343bc112013-02-10 01:53:46 +000084
85 // Sets the output to zero.
86 // Over-ride if a value of zero is not "off" for this subsystem.
87 virtual void Zero(OutputType *output) { output->Zero(); }
88
89 // Runs the loop forever.
Brian Silverman699f0cb2015-02-05 19:45:01 -050090 void Run() override;
brians343bc112013-02-10 01:53:46 +000091
92 // Runs one cycle of the loop.
Brian Silverman699f0cb2015-02-05 19:45:01 -050093 void Iterate() override;
brians343bc112013-02-10 01:53:46 +000094
95 // Returns the name of the queue group.
96 const char *name() { return control_loop_->name(); }
97
98 // Methods to serialize all the data that should be sent over the network.
Brian Silverman699f0cb2015-02-05 19:45:01 -050099 size_t SeralizedSize() override { return control_loop_->goal->Size(); }
100 void Serialize(char *buffer) const override {
brians343bc112013-02-10 01:53:46 +0000101 control_loop_->goal->Serialize(buffer);
102 }
Brian Silverman699f0cb2015-02-05 19:45:01 -0500103 void SerializeZeroMessage(char *buffer) const override {
brians343bc112013-02-10 01:53:46 +0000104 GoalType zero_goal;
105 zero_goal.Zero();
106 zero_goal.Serialize(buffer);
107 }
108
Brian Silverman699f0cb2015-02-05 19:45:01 -0500109 void Deserialize(const char *buffer) override {
brians343bc112013-02-10 01:53:46 +0000110 ScopedMessagePtr<GoalType> new_msg = control_loop_->goal.MakeMessage();
111 new_msg->Deserialize(buffer);
112 new_msg.Send();
113 }
114
Brian Silverman699f0cb2015-02-05 19:45:01 -0500115 uint32_t UniqueID() override { return control_loop_->hash(); }
brians343bc112013-02-10 01:53:46 +0000116
117 protected:
118 // Runs an iteration of the control loop.
Brian Silverman089f5812015-02-15 01:58:19 -0500119 // goal is the last goal that was sent. It might be any number of cycles old
120 // or nullptr if we haven't ever received a goal.
121 // position is the current position, or nullptr if we didn't get a position
122 // this cycle.
123 // output is the values to be sent to the motors. This is nullptr if the
124 // output is going to be ignored and set to 0.
brians343bc112013-02-10 01:53:46 +0000125 // status is the status of the control loop.
126 // Both output and status should be filled in by the implementation.
127 virtual void RunIteration(const GoalType *goal,
128 const PositionType *position,
129 OutputType *output,
130 StatusType *status) = 0;
131
Brian Silvermand1e65b92014-03-08 17:07:14 -0800132 T *queue_group() { return control_loop_; }
133 const T *queue_group() const { return control_loop_; }
134
brians343bc112013-02-10 01:53:46 +0000135 private:
Brian Silverman699f0cb2015-02-05 19:45:01 -0500136 static constexpr ::aos::time::Time kStaleLogInterval =
137 ::aos::time::Time::InSeconds(0.1);
138 // The amount of time after the last PWM pulse we consider motors enabled for.
139 // 100ms is the result of using an oscilliscope to look at the input and
140 // output of a Talon. The Info Sheet also lists 100ms for Talon SR, Talon SRX,
141 // and Victor SP.
142 static constexpr ::aos::time::Time kPwmDisableTime =
143 ::aos::time::Time::InMS(100);
144
145 // Maximum age of driver station packets before the loop will be disabled.
146 static const int kDSPacketTimeoutMs = 500;
147
brians343bc112013-02-10 01:53:46 +0000148 // Pointer to the queue group
149 T *control_loop_;
Brian Silverman50a9d032014-02-16 17:20:57 -0800150
Brian Silverman699f0cb2015-02-05 19:45:01 -0500151 bool reset_ = false;
152 int32_t sensor_reader_pid_ = 0;
153
154 ::aos::time::Time last_pwm_sent_{0, 0};
Austin Schuh3d6e3df2014-02-17 01:51:03 -0800155
Brian Silverman50a9d032014-02-16 17:20:57 -0800156 typedef ::aos::util::SimpleLogInterval SimpleLogInterval;
Brian Silverman50a9d032014-02-16 17:20:57 -0800157 SimpleLogInterval no_driver_station_ =
158 SimpleLogInterval(kStaleLogInterval, ERROR,
159 "no driver station packet");
160 SimpleLogInterval driver_station_old_ =
161 SimpleLogInterval(kStaleLogInterval, ERROR,
162 "driver station packet is too old");
Brian Silverman699f0cb2015-02-05 19:45:01 -0500163 SimpleLogInterval no_sensor_state_ =
164 SimpleLogInterval(kStaleLogInterval, ERROR, "no sensor state");
Brian Silverman2704ecf2014-04-09 20:24:03 -0700165 SimpleLogInterval motors_off_log_ =
166 SimpleLogInterval(kStaleLogInterval, WARNING, "motors disabled");
Brian Silverman699f0cb2015-02-05 19:45:01 -0500167 SimpleLogInterval no_goal_ =
168 SimpleLogInterval(kStaleLogInterval, ERROR, "no goal");
brians343bc112013-02-10 01:53:46 +0000169};
170
Brian Silverman38111502014-04-10 12:36:26 -0700171} // namespace controls
brians343bc112013-02-10 01:53:46 +0000172} // namespace aos
173
Briana6553ed2014-04-02 21:26:46 -0700174#include "aos/common/controls/control_loop-tmpl.h" // IWYU pragma: export
brians343bc112013-02-10 01:53:46 +0000175
176#endif