blob: 4712bb949a39bded02e5528bb4a327c3ce3bd7e4 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#include <stddef.h>
2
3#include "aos/common/logging/logging.h"
Brian Silverman2ac0fbc2014-03-20 19:45:13 -07004#include "aos/common/messages/robot_state.q.h"
Brian Silvermand6974f42014-02-14 13:39:21 -08005#include "aos/common/logging/queue_logging.h"
Brian3afd6fc2014-04-02 20:41:49 -07006#include "aos/common/util/phased_loop.h"
Brian Silverman38111502014-04-10 12:36:26 -07007#include "aos/common/controls/sensor_generation.q.h"
8#include "aos/common/controls/output_check.q.h"
Austin Schuh3d6e3df2014-02-17 01:51:03 -08009
brians343bc112013-02-10 01:53:46 +000010namespace aos {
Brian Silverman38111502014-04-10 12:36:26 -070011namespace controls {
brians343bc112013-02-10 01:53:46 +000012
13// TODO(aschuh): Tests.
14
Brian Silvermand8f403a2014-12-13 19:12:04 -050015template <class T, bool fail_no_goal>
16constexpr ::aos::time::Time ControlLoop<T, fail_no_goal>::kStaleLogInterval;
Brian Silverman50a9d032014-02-16 17:20:57 -080017
Brian Silvermand8f403a2014-12-13 19:12:04 -050018template <class T, bool fail_no_goal>
Brian Silverman71fbee02014-03-13 17:24:54 -070019void
Brian Silvermand8f403a2014-12-13 19:12:04 -050020ControlLoop<T, fail_no_goal>::ZeroOutputs() {
brians343bc112013-02-10 01:53:46 +000021 aos::ScopedMessagePtr<OutputType> output =
22 control_loop_->output.MakeMessage();
23 Zero(output.get());
24 output.Send();
25}
26
Brian Silvermand8f403a2014-12-13 19:12:04 -050027template <class T, bool fail_no_goal>
28void ControlLoop<T, fail_no_goal>::Iterate() {
Brian Silverman9c9ab422014-02-25 13:42:53 -080029 no_prior_goal_.Print();
30 no_sensor_generation_.Print();
Brian Silverman9c9ab422014-02-25 13:42:53 -080031 driver_station_old_.Print();
32 no_driver_station_.Print();
Brian Silverman6a1cd212014-02-20 21:04:34 -080033
Brian Silvermand8f403a2014-12-13 19:12:04 -050034 control_loop_->position.FetchAnother();
35 const PositionType *const position = control_loop_->position.get();
36 LOG_STRUCT(DEBUG, "position", *position);
37
38 // Fetch the latest control loop goal. If there is no new
brians343bc112013-02-10 01:53:46 +000039 // goal, we will just reuse the old one.
40 // If there is no goal, we haven't started up fully. It isn't worth
41 // the added complexity for each loop implementation to handle that case.
42 control_loop_->goal.FetchLatest();
43 // TODO(aschuh): Check the age here if we want the loop to stop on old
44 // goals.
45 const GoalType *goal = control_loop_->goal.get();
46 if (goal == NULL) {
Brian Silverman9c9ab422014-02-25 13:42:53 -080047 LOG_INTERVAL(no_prior_goal_);
Brian Silverman71fbee02014-03-13 17:24:54 -070048 if (fail_no_goal) {
49 ZeroOutputs();
50 return;
51 }
brians343bc112013-02-10 01:53:46 +000052 }
Austin Schuh3d6e3df2014-02-17 01:51:03 -080053
Brian Silverman38111502014-04-10 12:36:26 -070054 sensor_generation.FetchLatest();
55 if (sensor_generation.get() == nullptr) {
Brian Silverman9c9ab422014-02-25 13:42:53 -080056 LOG_INTERVAL(no_sensor_generation_);
Austin Schuh3d6e3df2014-02-17 01:51:03 -080057 ZeroOutputs();
58 return;
59 }
60 if (!has_sensor_reset_counters_ ||
Brian Silverman38111502014-04-10 12:36:26 -070061 sensor_generation->reader_pid != reader_pid_ ||
62 sensor_generation->cape_resets != cape_resets_) {
Brian Silverman71fbee02014-03-13 17:24:54 -070063 LOG_STRUCT(INFO, "new sensor_generation message",
Brian Silverman38111502014-04-10 12:36:26 -070064 *sensor_generation.get());
Brian Silverman4910efb2014-02-17 11:10:10 -080065
Brian Silverman38111502014-04-10 12:36:26 -070066 reader_pid_ = sensor_generation->reader_pid;
67 cape_resets_ = sensor_generation->cape_resets;
Austin Schuh3d6e3df2014-02-17 01:51:03 -080068 has_sensor_reset_counters_ = true;
69 reset_ = true;
70 }
Brian Silverman71fbee02014-03-13 17:24:54 -070071
72 if (goal) {
73 LOG_STRUCT(DEBUG, "goal", *goal);
74 }
brians343bc112013-02-10 01:53:46 +000075
brians343bc112013-02-10 01:53:46 +000076 bool outputs_enabled = false;
77
78 // Check to see if we got a driver station packet recently.
Austin Schuh3d6e3df2014-02-17 01:51:03 -080079 if (::aos::robot_state.FetchLatest()) {
brians343bc112013-02-10 01:53:46 +000080 outputs_enabled = true;
Austin Schuh3d6e3df2014-02-17 01:51:03 -080081 } else if (::aos::robot_state.IsNewerThanMS(kDSPacketTimeoutMs)) {
brians343bc112013-02-10 01:53:46 +000082 outputs_enabled = true;
83 } else {
Austin Schuh3d6e3df2014-02-17 01:51:03 -080084 if (::aos::robot_state.get()) {
Brian Silverman9c9ab422014-02-25 13:42:53 -080085 LOG_INTERVAL(driver_station_old_);
brians343bc112013-02-10 01:53:46 +000086 } else {
Brian Silverman9c9ab422014-02-25 13:42:53 -080087 LOG_INTERVAL(no_driver_station_);
brians343bc112013-02-10 01:53:46 +000088 }
89 }
90
Brian Silverman38111502014-04-10 12:36:26 -070091 ::aos::controls::output_check_received.FetchLatest();
Brian Silverman2704ecf2014-04-09 20:24:03 -070092 // True if we're enabled but the motors aren't working.
Austin Schuh66a3d2f2014-10-21 22:24:00 -070093 // The 100ms is the result of using an oscilliscope to look at the PWM signal
94 // and output of a talon, and timing the delay between the last pulse and the
95 // talon turning off.
Brian Silverman38111502014-04-10 12:36:26 -070096 const bool motors_off =
97 !::aos::controls::output_check_received.get() ||
98 !::aos::controls::output_check_received.IsNewerThanMS(100);
Brian Silverman2704ecf2014-04-09 20:24:03 -070099 motors_off_log_.Print();
100 if (motors_off) {
101 if (!::aos::robot_state.get() || ::aos::robot_state->enabled) {
102 LOG_INTERVAL(motors_off_log_);
103 }
104 outputs_enabled = false;
105 }
106
brians343bc112013-02-10 01:53:46 +0000107 // Run the iteration.
108 aos::ScopedMessagePtr<StatusType> status =
109 control_loop_->status.MakeMessage();
110 if (status.get() == NULL) {
111 return;
112 }
113
114 if (outputs_enabled) {
115 aos::ScopedMessagePtr<OutputType> output =
116 control_loop_->output.MakeMessage();
117 RunIteration(goal, position, output.get(), status.get());
118
Brian Silvermand6974f42014-02-14 13:39:21 -0800119 LOG_STRUCT(DEBUG, "output", *output);
brians343bc112013-02-10 01:53:46 +0000120 output.Send();
121 } else {
122 // The outputs are disabled, so pass NULL in for the output.
Ben Fredrickson4283bb42014-02-22 08:31:50 +0000123 RunIteration(goal, position, nullptr, status.get());
brians343bc112013-02-10 01:53:46 +0000124 ZeroOutputs();
125 }
126
Brian Silvermand6974f42014-02-14 13:39:21 -0800127 LOG_STRUCT(DEBUG, "status", *status);
brians343bc112013-02-10 01:53:46 +0000128 status.Send();
129}
130
Brian Silvermand8f403a2014-12-13 19:12:04 -0500131template <class T, bool fail_no_goal>
132void ControlLoop<T, fail_no_goal>::Run() {
brians343bc112013-02-10 01:53:46 +0000133 while (true) {
brians343bc112013-02-10 01:53:46 +0000134 Iterate();
135 }
136}
137
Brian Silverman38111502014-04-10 12:36:26 -0700138} // namespace controls
brians343bc112013-02-10 01:53:46 +0000139} // namespace aos