blob: 3173d2c833152af78dc66dded151f0b5a6b0e668 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#include <stddef.h>
2
3#include "aos/common/logging/logging.h"
4#include "aos/common/control_loop/Timing.h"
5#include "aos/common/messages/RobotState.q.h"
Brian Silvermand6974f42014-02-14 13:39:21 -08006#include "aos/common/logging/queue_logging.h"
brians343bc112013-02-10 01:53:46 +00007
8namespace aos {
9namespace control_loops {
10
11// TODO(aschuh): Tests.
12
Brian Silverman10f997b2013-10-11 18:01:56 -070013template <class T, bool has_position, bool fail_no_position>
14void ControlLoop<T, has_position, fail_no_position>::ZeroOutputs() {
brians343bc112013-02-10 01:53:46 +000015 aos::ScopedMessagePtr<OutputType> output =
16 control_loop_->output.MakeMessage();
17 Zero(output.get());
18 output.Send();
19}
20
Brian Silverman10f997b2013-10-11 18:01:56 -070021template <class T, bool has_position, bool fail_no_position>
22void ControlLoop<T, has_position, fail_no_position>::Iterate() {
brians343bc112013-02-10 01:53:46 +000023 // Fetch the latest control loop goal and position. If there is no new
24 // goal, we will just reuse the old one.
25 // If there is no goal, we haven't started up fully. It isn't worth
26 // the added complexity for each loop implementation to handle that case.
27 control_loop_->goal.FetchLatest();
28 // TODO(aschuh): Check the age here if we want the loop to stop on old
29 // goals.
30 const GoalType *goal = control_loop_->goal.get();
31 if (goal == NULL) {
32 LOG(ERROR, "No prior control loop goal.\n");
33 ZeroOutputs();
34 return;
35 }
Brian Silvermand6974f42014-02-14 13:39:21 -080036 LOG_STRUCT(DEBUG, "goal", *goal);
brians343bc112013-02-10 01:53:46 +000037
38 // Only pass in a position if we got one this cycle.
39 const PositionType *position = NULL;
40
41 // Only fetch the latest position if we have one.
42 if (has_position) {
43 // If the position is stale, this is really bad. Try fetching a position
44 // and check how fresh it is, and then take the appropriate action.
45 if (control_loop_->position.FetchLatest()) {
46 position = control_loop_->position.get();
47 } else {
48 if (control_loop_->position.get()) {
49 int msec_age = control_loop_->position.Age().ToMSec();
50 if (!control_loop_->position.IsNewerThanMS(kPositionTimeoutMs)) {
51 LOG(ERROR, "Stale position. %d ms > %d ms. Outputs disabled.\n",
52 msec_age, kPositionTimeoutMs);
53 ZeroOutputs();
54 return;
55 } else {
56 LOG(ERROR, "Stale position. %d ms\n", msec_age);
57 }
58 } else {
59 LOG(ERROR, "Never had a position.\n");
Brian Silverman10f997b2013-10-11 18:01:56 -070060 if (fail_no_position) {
61 ZeroOutputs();
62 return;
63 }
brians343bc112013-02-10 01:53:46 +000064 }
65 }
Austin Schuhfa033692013-02-24 01:00:55 -080066 if (position) {
Brian Silvermand6974f42014-02-14 13:39:21 -080067 LOG_STRUCT(DEBUG, "position", *position);
Austin Schuhfa033692013-02-24 01:00:55 -080068 }
brians343bc112013-02-10 01:53:46 +000069 }
70
71 bool outputs_enabled = false;
72
73 // Check to see if we got a driver station packet recently.
74 if (aos::robot_state.FetchLatest()) {
75 outputs_enabled = true;
76 } else if (aos::robot_state.IsNewerThanMS(kDSPacketTimeoutMs)) {
77 outputs_enabled = true;
78 } else {
79 if (aos::robot_state.get()) {
80 int msec_age = aos::robot_state.Age().ToMSec();
81 LOG(ERROR, "Driver Station packet is too old (%d ms).\n", msec_age);
82 } else {
83 LOG(ERROR, "No Driver Station packet.\n");
84 }
85 }
86
87 // Run the iteration.
88 aos::ScopedMessagePtr<StatusType> status =
89 control_loop_->status.MakeMessage();
90 if (status.get() == NULL) {
91 return;
92 }
93
94 if (outputs_enabled) {
95 aos::ScopedMessagePtr<OutputType> output =
96 control_loop_->output.MakeMessage();
97 RunIteration(goal, position, output.get(), status.get());
98
Brian Silvermand6974f42014-02-14 13:39:21 -080099 LOG_STRUCT(DEBUG, "output", *output);
brians343bc112013-02-10 01:53:46 +0000100 output.Send();
101 } else {
102 // The outputs are disabled, so pass NULL in for the output.
103 RunIteration(goal, position, NULL, status.get());
104 ZeroOutputs();
105 }
106
Brian Silvermand6974f42014-02-14 13:39:21 -0800107 LOG_STRUCT(DEBUG, "status", *status);
brians343bc112013-02-10 01:53:46 +0000108 status.Send();
109}
110
Brian Silverman10f997b2013-10-11 18:01:56 -0700111template <class T, bool has_position, bool fail_no_position>
112void ControlLoop<T, has_position, fail_no_position>::Run() {
brians343bc112013-02-10 01:53:46 +0000113 while (true) {
Brian Silverman15ca9852013-03-17 18:24:15 -0700114 time::SleepUntil(NextLoopTime());
brians343bc112013-02-10 01:53:46 +0000115 Iterate();
116 }
117}
118
119} // namespace control_loops
120} // namespace aos