blob: 6953575ce0dbc6a9c6c89dd25fbcb609aec1cb0a [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#include <stddef.h>
Brian Silverman699f0cb2015-02-05 19:45:01 -05002#include <inttypes.h>
brians343bc112013-02-10 01:53:46 +00003
John Park33858a32018-09-28 23:05:48 -07004#include "aos/logging/logging.h"
5#include "aos/logging/queue_logging.h"
6#include "aos/robot_state/robot_state.q.h"
Austin Schuh3d6e3df2014-02-17 01:51:03 -08007
brians343bc112013-02-10 01:53:46 +00008namespace aos {
Brian Silverman38111502014-04-10 12:36:26 -07009namespace controls {
brians343bc112013-02-10 01:53:46 +000010
11// TODO(aschuh): Tests.
12
Brian Silverman089f5812015-02-15 01:58:19 -050013template <class T>
Austin Schuh61bdc602016-12-04 19:10:10 -080014constexpr ::std::chrono::milliseconds ControlLoop<T>::kStaleLogInterval;
Brian Silverman089f5812015-02-15 01:58:19 -050015template <class T>
Austin Schuh61bdc602016-12-04 19:10:10 -080016constexpr ::std::chrono::milliseconds ControlLoop<T>::kPwmDisableTime;
Brian Silverman50a9d032014-02-16 17:20:57 -080017
Brian Silverman089f5812015-02-15 01:58:19 -050018template <class T>
19void ControlLoop<T>::ZeroOutputs() {
Austin Schuha1654ed2019-01-27 17:24:54 -080020 typename ::aos::Sender<OutputType>::Message output =
21 output_sender_.MakeMessage();
brians343bc112013-02-10 01:53:46 +000022 Zero(output.get());
23 output.Send();
24}
25
Brian Silverman089f5812015-02-15 01:58:19 -050026template <class T>
27void ControlLoop<T>::Iterate() {
Austin Schuha1654ed2019-01-27 17:24:54 -080028 control_loop_->position.FetchAnother();
29 IteratePosition(*control_loop_->position.get());
30}
31
32template <class T>
33void ControlLoop<T>::IteratePosition(const PositionType &position) {
34 // Since Exit() isn't async safe, we want to call Exit from the periodic
35 // handler.
36 if (!run_) {
37 event_loop_->Exit();
38 }
Brian Silverman699f0cb2015-02-05 19:45:01 -050039 no_goal_.Print();
Brian Silverman699f0cb2015-02-05 19:45:01 -050040 no_sensor_state_.Print();
Brian Silverman699f0cb2015-02-05 19:45:01 -050041 motors_off_log_.Print();
Brian Silverman6a1cd212014-02-20 21:04:34 -080042
Austin Schuha1654ed2019-01-27 17:24:54 -080043 LOG_STRUCT(DEBUG, "position", position);
Brian Silvermand8f403a2014-12-13 19:12:04 -050044
45 // Fetch the latest control loop goal. If there is no new
brians343bc112013-02-10 01:53:46 +000046 // goal, we will just reuse the old one.
Austin Schuha1654ed2019-01-27 17:24:54 -080047 goal_fetcher_.Fetch();
48 const GoalType *goal = goal_fetcher_.get();
Brian Silverman699f0cb2015-02-05 19:45:01 -050049 if (goal) {
50 LOG_STRUCT(DEBUG, "goal", *goal);
51 } else {
52 LOG_INTERVAL(no_goal_);
brians343bc112013-02-10 01:53:46 +000053 }
Austin Schuh3d6e3df2014-02-17 01:51:03 -080054
Austin Schuh61bdc602016-12-04 19:10:10 -080055 const bool new_robot_state = ::aos::robot_state.FetchLatest();
Brian Silverman699f0cb2015-02-05 19:45:01 -050056 if (!::aos::robot_state.get()) {
57 LOG_INTERVAL(no_sensor_state_);
Austin Schuh3d6e3df2014-02-17 01:51:03 -080058 return;
59 }
Brian Silverman699f0cb2015-02-05 19:45:01 -050060 if (sensor_reader_pid_ != ::aos::robot_state->reader_pid) {
61 LOG(INFO, "new sensor reader PID %" PRId32 ", old was %" PRId32 "\n",
62 ::aos::robot_state->reader_pid, sensor_reader_pid_);
Austin Schuh3d6e3df2014-02-17 01:51:03 -080063 reset_ = true;
Brian Silverman699f0cb2015-02-05 19:45:01 -050064 sensor_reader_pid_ = ::aos::robot_state->reader_pid;
Brian Silverman71fbee02014-03-13 17:24:54 -070065 }
brians343bc112013-02-10 01:53:46 +000066
Austin Schuh61bdc602016-12-04 19:10:10 -080067 bool outputs_enabled = ::aos::robot_state->outputs_enabled;
brians343bc112013-02-10 01:53:46 +000068
69 // Check to see if we got a driver station packet recently.
Austin Schuh61bdc602016-12-04 19:10:10 -080070 if (new_robot_state) {
Brian Silverman699f0cb2015-02-05 19:45:01 -050071 if (::aos::robot_state->outputs_enabled) {
Brian Silverman295f74b2015-02-14 23:00:47 -050072 // If the driver's station reports being disabled, we're probably not
73 // actually going to send motor values regardless of what the FPGA
74 // reports.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080075 last_pwm_sent_ = ::aos::robot_state->sent_time;
brians343bc112013-02-10 01:53:46 +000076 }
77 }
78
Austin Schuh61bdc602016-12-04 19:10:10 -080079 const ::aos::monotonic_clock::time_point now = ::aos::monotonic_clock::now();
80 const bool motors_off = now >= kPwmDisableTime + last_pwm_sent_;
81 ::aos::joystick_state.FetchLatest();
Brian Silverman2704ecf2014-04-09 20:24:03 -070082 if (motors_off) {
Brian Silverman699f0cb2015-02-05 19:45:01 -050083 if (::aos::joystick_state.get() && ::aos::joystick_state->enabled) {
Brian Silverman2704ecf2014-04-09 20:24:03 -070084 LOG_INTERVAL(motors_off_log_);
85 }
86 outputs_enabled = false;
87 }
88
Austin Schuha1654ed2019-01-27 17:24:54 -080089 typename ::aos::Sender<StatusType>::Message status =
90 status_sender_.MakeMessage();
Brian Silverman699f0cb2015-02-05 19:45:01 -050091 if (status.get() == nullptr) {
brians343bc112013-02-10 01:53:46 +000092 return;
93 }
94
95 if (outputs_enabled) {
Austin Schuha1654ed2019-01-27 17:24:54 -080096 typename ::aos::Sender<OutputType>::Message output =
97 output_sender_.MakeMessage();
98 RunIteration(goal, &position, output.get(), status.get());
brians343bc112013-02-10 01:53:46 +000099
Austin Schuhf907f2e2018-01-02 01:15:27 -0800100 output->SetTimeToNow();
Brian Silvermand6974f42014-02-14 13:39:21 -0800101 LOG_STRUCT(DEBUG, "output", *output);
brians343bc112013-02-10 01:53:46 +0000102 output.Send();
103 } else {
Brian Silverman699f0cb2015-02-05 19:45:01 -0500104 // The outputs are disabled, so pass nullptr in for the output.
Austin Schuha1654ed2019-01-27 17:24:54 -0800105 RunIteration(goal, &position, nullptr, status.get());
brians343bc112013-02-10 01:53:46 +0000106 ZeroOutputs();
107 }
108
Austin Schuhf907f2e2018-01-02 01:15:27 -0800109 status->SetTimeToNow();
Brian Silvermand6974f42014-02-14 13:39:21 -0800110 LOG_STRUCT(DEBUG, "status", *status);
brians343bc112013-02-10 01:53:46 +0000111 status.Send();
112}
113
Brian Silverman089f5812015-02-15 01:58:19 -0500114template <class T>
115void ControlLoop<T>::Run() {
Austin Schuhb58ceb62017-02-05 14:21:57 -0800116 struct sigaction action;
117 action.sa_handler = &ControlLoop<T>::Quit;
118 sigemptyset(&action.sa_mask);
119 action.sa_flags = SA_RESETHAND;
120
121 PCHECK(sigaction(SIGTERM, &action, nullptr));
122 PCHECK(sigaction(SIGQUIT, &action, nullptr));
123 PCHECK(sigaction(SIGINT, &action, nullptr));
124
Austin Schuha1654ed2019-01-27 17:24:54 -0800125 event_loop_->MakeWatcher(::std::string(control_loop_->name()) + ".position",
126 [this](const PositionType &position) {
127 this->IteratePosition(position);
128 });
129
130 event_loop_->Run();
Austin Schuhb58ceb62017-02-05 14:21:57 -0800131 LOG(INFO, "Shutting down\n");
brians343bc112013-02-10 01:53:46 +0000132}
133
Austin Schuhb58ceb62017-02-05 14:21:57 -0800134template <class T>
135::std::atomic<bool> ControlLoop<T>::run_{true};
136
Brian Silverman38111502014-04-10 12:36:26 -0700137} // namespace controls
brians343bc112013-02-10 01:53:46 +0000138} // namespace aos