blob: c02d094bb88a7a2a3994a007c3a4a0f2a5b1cc8c [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
Austin Schuhb58ceb62017-02-05 14:21:57 -08004#include <atomic>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07005#include <cstring>
brians343bc112013-02-10 01:53:46 +00006
Alex Perrycb7da4b2019-08-28 19:35:56 -07007#include "aos/events/event_loop.h"
John Park33858a32018-09-28 23:05:48 -07008#include "aos/time/time.h"
John Park33858a32018-09-28 23:05:48 -07009#include "aos/util/log_interval.h"
James Kuszmaul7077d342021-06-09 20:23:58 -070010#include "frc971/input/joystick_state_generated.h"
11#include "frc971/input/robot_state_generated.h"
brians343bc112013-02-10 01:53:46 +000012
James Kuszmaul61750662021-06-21 21:32:33 -070013namespace frc971 {
Brian Silverman38111502014-04-10 12:36:26 -070014namespace controls {
brians343bc112013-02-10 01:53:46 +000015
Brian Silverman3204dd82013-03-12 18:42:01 -070016// Control loops run this often, "starting" at time 0.
Austin Schuh214e9c12016-11-25 17:26:20 -080017constexpr ::std::chrono::nanoseconds kLoopFrequency =
18 ::std::chrono::milliseconds(5);
Brian Silverman3204dd82013-03-12 18:42:01 -070019
brians343bc112013-02-10 01:53:46 +000020// Provides helper methods to assist in writing control loops.
brians343bc112013-02-10 01:53:46 +000021// It will then call the RunIteration method every cycle that it has enough
22// valid data for the control loop to run.
Alex Perrycb7da4b2019-08-28 19:35:56 -070023template <class GoalType, class PositionType, class StatusType,
24 class OutputType>
Austin Schuh9fe68f72019-08-10 19:32:03 -070025class ControlLoop {
brians343bc112013-02-10 01:53:46 +000026 public:
James Kuszmaul61750662021-06-21 21:32:33 -070027 ControlLoop(aos::EventLoop *event_loop, const ::std::string &name)
Austin Schuhd3cd6992019-01-27 22:44:07 -080028 : event_loop_(event_loop), name_(name) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070029 output_sender_ = event_loop_->MakeSender<OutputType>(name_);
30 status_sender_ = event_loop_->MakeSender<StatusType>(name_);
31 goal_fetcher_ = event_loop_->MakeFetcher<GoalType>(name_);
32 robot_state_fetcher_ = event_loop_->MakeFetcher<::aos::RobotState>("/aos");
Austin Schuheeec74a2019-01-27 20:58:59 -080033 joystick_state_fetcher_ =
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 event_loop_->MakeFetcher<::aos::JoystickState>("/aos");
Austin Schuh9fe68f72019-08-10 19:32:03 -070035
Alex Perrycb7da4b2019-08-28 19:35:56 -070036 event_loop_->MakeWatcher(name_, [this](const PositionType &position) {
37 this->IteratePosition(position);
38 });
Austin Schuheeec74a2019-01-27 20:58:59 -080039 }
40
41 const ::aos::RobotState &robot_state() const { return *robot_state_fetcher_; }
42 bool has_joystick_state() const { return joystick_state_fetcher_.get(); }
43 const ::aos::JoystickState &joystick_state() const {
44 return *joystick_state_fetcher_;
Austin Schuha1654ed2019-01-27 17:24:54 -080045 }
Brian Silverman699f0cb2015-02-05 19:45:01 -050046
47 // Returns true if all the counters etc in the sensor data have been reset.
48 // This will return true only a single time per reset.
49 bool WasReset() {
50 if (reset_) {
51 reset_ = false;
52 return true;
53 } else {
54 return false;
55 }
56 }
57
Brian Silvermand1e65b92014-03-08 17:07:14 -080058 // Constructs and sends a message on the output queue which sets everything to
Austin Schuhaebfb4f2019-01-27 13:26:38 -080059 // a safe state. Default is to set everything to zero. Override Zero below
60 // to change that behavior.
61 void ZeroOutputs();
brians343bc112013-02-10 01:53:46 +000062
63 // Sets the output to zero.
Austin Schuhaebfb4f2019-01-27 13:26:38 -080064 // Override this if a value of zero (or false) is not "off" for this
65 // subsystem.
Alex Perrycb7da4b2019-08-28 19:35:56 -070066 virtual flatbuffers::Offset<OutputType> Zero(
67 typename ::aos::Sender<OutputType>::Builder *builder) {
68 return builder->template MakeBuilder<OutputType>().Finish();
69 }
brians343bc112013-02-10 01:53:46 +000070
brians343bc112013-02-10 01:53:46 +000071 protected:
Austin Schuh9fe68f72019-08-10 19:32:03 -070072 // Runs one cycle of the loop.
Austin Schuha1654ed2019-01-27 17:24:54 -080073 void IteratePosition(const PositionType &position);
74
James Kuszmaul61750662021-06-21 21:32:33 -070075 aos::EventLoop *event_loop() { return event_loop_; }
Theo Bafrali3274a182019-02-17 20:01:38 -080076
Alex Perrycb7da4b2019-08-28 19:35:56 -070077 // Returns the position context. This is only valid inside the RunIteration
78 // method.
79 const aos::Context &position_context() { return event_loop_->context(); }
80
brians343bc112013-02-10 01:53:46 +000081 // Runs an iteration of the control loop.
Brian Silverman089f5812015-02-15 01:58:19 -050082 // goal is the last goal that was sent. It might be any number of cycles old
83 // or nullptr if we haven't ever received a goal.
84 // position is the current position, or nullptr if we didn't get a position
85 // this cycle.
86 // output is the values to be sent to the motors. This is nullptr if the
87 // output is going to be ignored and set to 0.
brians343bc112013-02-10 01:53:46 +000088 // status is the status of the control loop.
89 // Both output and status should be filled in by the implementation.
Alex Perrycb7da4b2019-08-28 19:35:56 -070090 virtual void RunIteration(
91 const GoalType *goal, const PositionType *position,
92 typename ::aos::Sender<OutputType>::Builder *output,
93 typename ::aos::Sender<StatusType>::Builder *status) = 0;
brians343bc112013-02-10 01:53:46 +000094
95 private:
Austin Schuh61bdc602016-12-04 19:10:10 -080096 static constexpr ::std::chrono::milliseconds kStaleLogInterval =
97 ::std::chrono::milliseconds(100);
Brian Silverman699f0cb2015-02-05 19:45:01 -050098 // The amount of time after the last PWM pulse we consider motors enabled for.
99 // 100ms is the result of using an oscilliscope to look at the input and
100 // output of a Talon. The Info Sheet also lists 100ms for Talon SR, Talon SRX,
101 // and Victor SP.
Austin Schuh61bdc602016-12-04 19:10:10 -0800102 static constexpr ::std::chrono::milliseconds kPwmDisableTime =
103 ::std::chrono::milliseconds(100);
Brian Silverman699f0cb2015-02-05 19:45:01 -0500104
brians343bc112013-02-10 01:53:46 +0000105 // Pointer to the queue group
James Kuszmaul61750662021-06-21 21:32:33 -0700106 aos::EventLoop *event_loop_;
Austin Schuheeec74a2019-01-27 20:58:59 -0800107 ::std::string name_;
Brian Silverman50a9d032014-02-16 17:20:57 -0800108
Austin Schuha1654ed2019-01-27 17:24:54 -0800109 ::aos::Sender<OutputType> output_sender_;
110 ::aos::Sender<StatusType> status_sender_;
111 ::aos::Fetcher<GoalType> goal_fetcher_;
Austin Schuheeec74a2019-01-27 20:58:59 -0800112 ::aos::Fetcher<::aos::RobotState> robot_state_fetcher_;
113 ::aos::Fetcher<::aos::JoystickState> joystick_state_fetcher_;
114
115 // Fetcher only to be used for the Iterate method. If Iterate is called, Run
116 // can't be called.
117 bool has_iterate_fetcher_ = false;
118 ::aos::Fetcher<PositionType> iterate_position_fetcher_;
Austin Schuha1654ed2019-01-27 17:24:54 -0800119
Brian Silverman699f0cb2015-02-05 19:45:01 -0500120 bool reset_ = false;
121 int32_t sensor_reader_pid_ = 0;
122
Austin Schuh61bdc602016-12-04 19:10:10 -0800123 ::aos::monotonic_clock::time_point last_pwm_sent_ =
124 ::aos::monotonic_clock::min_time;
Austin Schuh3d6e3df2014-02-17 01:51:03 -0800125
Brian Silverman50a9d032014-02-16 17:20:57 -0800126 typedef ::aos::util::SimpleLogInterval SimpleLogInterval;
Brian Silverman699f0cb2015-02-05 19:45:01 -0500127 SimpleLogInterval no_sensor_state_ =
128 SimpleLogInterval(kStaleLogInterval, ERROR, "no sensor state");
Brian Silverman2704ecf2014-04-09 20:24:03 -0700129 SimpleLogInterval motors_off_log_ =
130 SimpleLogInterval(kStaleLogInterval, WARNING, "motors disabled");
Brian Silverman699f0cb2015-02-05 19:45:01 -0500131 SimpleLogInterval no_goal_ =
132 SimpleLogInterval(kStaleLogInterval, ERROR, "no goal");
brians343bc112013-02-10 01:53:46 +0000133};
134
Brian Silverman38111502014-04-10 12:36:26 -0700135} // namespace controls
James Kuszmaul61750662021-06-21 21:32:33 -0700136} // namespace frc971
brians343bc112013-02-10 01:53:46 +0000137
James Kuszmaul61750662021-06-21 21:32:33 -0700138#include "frc971/control_loops/control_loop-tmpl.h" // IWYU pragma: export
brians343bc112013-02-10 01:53:46 +0000139
140#endif