blob: 69c312102d14f8bead11159b43fa51e600f7cb1a [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"
6
7namespace aos {
8namespace control_loops {
9
10// TODO(aschuh): Tests.
11
Brian Silverman10f997b2013-10-11 18:01:56 -070012template <class T, bool has_position, bool fail_no_position>
13void ControlLoop<T, has_position, fail_no_position>::ZeroOutputs() {
brians343bc112013-02-10 01:53:46 +000014 aos::ScopedMessagePtr<OutputType> output =
15 control_loop_->output.MakeMessage();
16 Zero(output.get());
17 output.Send();
18}
19
Brian Silverman10f997b2013-10-11 18:01:56 -070020template <class T, bool has_position, bool fail_no_position>
21void ControlLoop<T, has_position, fail_no_position>::Iterate() {
brians343bc112013-02-10 01:53:46 +000022 // Temporary storage for printing out inputs and outputs.
23 char state[1024];
24
25 // Fetch the latest control loop goal and position. If there is no new
26 // goal, we will just reuse the old one.
27 // If there is no goal, we haven't started up fully. It isn't worth
28 // the added complexity for each loop implementation to handle that case.
29 control_loop_->goal.FetchLatest();
30 // TODO(aschuh): Check the age here if we want the loop to stop on old
31 // goals.
32 const GoalType *goal = control_loop_->goal.get();
33 if (goal == NULL) {
34 LOG(ERROR, "No prior control loop goal.\n");
35 ZeroOutputs();
36 return;
37 }
38 goal->Print(state, sizeof(state));
39 LOG(DEBUG, "goal={%s}\n", state);
40
41 // Only pass in a position if we got one this cycle.
42 const PositionType *position = NULL;
43
44 // Only fetch the latest position if we have one.
45 if (has_position) {
46 // If the position is stale, this is really bad. Try fetching a position
47 // and check how fresh it is, and then take the appropriate action.
48 if (control_loop_->position.FetchLatest()) {
49 position = control_loop_->position.get();
50 } else {
51 if (control_loop_->position.get()) {
52 int msec_age = control_loop_->position.Age().ToMSec();
53 if (!control_loop_->position.IsNewerThanMS(kPositionTimeoutMs)) {
54 LOG(ERROR, "Stale position. %d ms > %d ms. Outputs disabled.\n",
55 msec_age, kPositionTimeoutMs);
56 ZeroOutputs();
57 return;
58 } else {
59 LOG(ERROR, "Stale position. %d ms\n", msec_age);
60 }
61 } else {
62 LOG(ERROR, "Never had a position.\n");
Brian Silverman10f997b2013-10-11 18:01:56 -070063 if (fail_no_position) {
64 ZeroOutputs();
65 return;
66 }
brians343bc112013-02-10 01:53:46 +000067 }
68 }
Austin Schuhfa033692013-02-24 01:00:55 -080069 if (position) {
70 position->Print(state, sizeof(state));
71 LOG(DEBUG, "position={%s}\n", state);
72 }
brians343bc112013-02-10 01:53:46 +000073 }
74
75 bool outputs_enabled = false;
76
77 // Check to see if we got a driver station packet recently.
78 if (aos::robot_state.FetchLatest()) {
79 outputs_enabled = true;
80 } else if (aos::robot_state.IsNewerThanMS(kDSPacketTimeoutMs)) {
81 outputs_enabled = true;
82 } else {
83 if (aos::robot_state.get()) {
84 int msec_age = aos::robot_state.Age().ToMSec();
85 LOG(ERROR, "Driver Station packet is too old (%d ms).\n", msec_age);
86 } else {
87 LOG(ERROR, "No Driver Station packet.\n");
88 }
89 }
90
91 // Run the iteration.
92 aos::ScopedMessagePtr<StatusType> status =
93 control_loop_->status.MakeMessage();
94 if (status.get() == NULL) {
95 return;
96 }
97
98 if (outputs_enabled) {
99 aos::ScopedMessagePtr<OutputType> output =
100 control_loop_->output.MakeMessage();
101 RunIteration(goal, position, output.get(), status.get());
102
103 output->Print(state, sizeof(state));
104 LOG(DEBUG, "output={%s}\n", state);
105 output.Send();
106 } else {
107 // The outputs are disabled, so pass NULL in for the output.
108 RunIteration(goal, position, NULL, status.get());
109 ZeroOutputs();
110 }
111
112 status->Print(state, sizeof(state));
113 LOG(DEBUG, "status={%s}\n", state);
114 status.Send();
115}
116
Brian Silverman10f997b2013-10-11 18:01:56 -0700117template <class T, bool has_position, bool fail_no_position>
118void ControlLoop<T, has_position, fail_no_position>::Run() {
brians343bc112013-02-10 01:53:46 +0000119 while (true) {
Brian Silverman15ca9852013-03-17 18:24:15 -0700120 time::SleepUntil(NextLoopTime());
brians343bc112013-02-10 01:53:46 +0000121 Iterate();
122 }
123}
124
125} // namespace control_loops
126} // namespace aos