blob: 91059f649f3f6959322bd278282f188f01c553bb [file] [log] [blame]
Parker Schuh18dbbb42017-10-18 21:45:33 -07001#include "frc971/codelab/basic.h"
2
3#include <unistd.h>
4
5#include <chrono>
6#include <memory>
7
John Park33858a32018-09-28 23:05:48 -07008#include "aos/controls/control_loop_test.h"
Austin Schuh55a13dc2019-01-27 22:39:03 -08009#include "aos/events/shm-event-loop.h"
John Park33858a32018-09-28 23:05:48 -070010#include "aos/queue.h"
Parker Schuh18dbbb42017-10-18 21:45:33 -070011#include "frc971/codelab/basic.q.h"
12#include "frc971/control_loops/team_number_test_environment.h"
13#include "gtest/gtest.h"
14
15namespace frc971 {
16namespace codelab {
17namespace testing {
18
Austin Schuh9fe68f72019-08-10 19:32:03 -070019namespace chrono = ::std::chrono;
20using aos::monotonic_clock;
21
Parker Schuh18dbbb42017-10-18 21:45:33 -070022// Class which simulates stuff and sends out queue messages with the
23// position.
24class BasicSimulation {
25 public:
Austin Schuh9fe68f72019-08-10 19:32:03 -070026 BasicSimulation(::aos::EventLoop *event_loop, chrono::nanoseconds dt)
27 : event_loop_(event_loop),
28 position_sender_(event_loop_->MakeSender<BasicQueue::Position>(
29 ".frc971.codelab.basic_queue.position")),
30 status_fetcher_(event_loop_->MakeFetcher<BasicQueue::Status>(
31 ".frc971.codelab.basic_queue.status")),
32 output_fetcher_(event_loop_->MakeFetcher<BasicQueue::Output>(
33 ".frc971.codelab.basic_queue.output")) {
34 event_loop_->AddPhasedLoop(
35 [this](int) {
36 // Skip this the first time.
37 if (!first_) {
38 Simulate();
39 }
40 first_ = false;
41 SendPositionMessage();
42 },
43 dt);
44 }
Parker Schuh18dbbb42017-10-18 21:45:33 -070045
46 // Sends a queue message with the position data.
47 void SendPositionMessage() {
Austin Schuh9fe68f72019-08-10 19:32:03 -070048 auto position = position_sender_.MakeMessage();
Parker Schuh18dbbb42017-10-18 21:45:33 -070049
50 position->limit_sensor = limit_sensor_;
51
52 position.Send();
53 }
54
55 void VerifyResults(double voltage, bool status) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070056 output_fetcher_.Fetch();
57 status_fetcher_.Fetch();
Parker Schuh18dbbb42017-10-18 21:45:33 -070058
Austin Schuh9fe68f72019-08-10 19:32:03 -070059 ASSERT_TRUE(output_fetcher_.get() != nullptr);
60 ASSERT_TRUE(status_fetcher_.get() != nullptr);
Parker Schuh18dbbb42017-10-18 21:45:33 -070061
Austin Schuh9fe68f72019-08-10 19:32:03 -070062 EXPECT_EQ(output_fetcher_->intake_voltage, voltage);
63 EXPECT_EQ(status_fetcher_->intake_complete, status);
Parker Schuh18dbbb42017-10-18 21:45:33 -070064 }
65
66 void set_limit_sensor(bool value) { limit_sensor_ = value; }
67
68 // Simulates basic control loop for a single timestep.
Austin Schuh9fe68f72019-08-10 19:32:03 -070069 void Simulate() { EXPECT_TRUE(output_fetcher_.Fetch()); }
Parker Schuh18dbbb42017-10-18 21:45:33 -070070
71 private:
Austin Schuh9fe68f72019-08-10 19:32:03 -070072 ::aos::EventLoop *event_loop_;
73
74 ::aos::Sender<BasicQueue::Position> position_sender_;
75 ::aos::Fetcher<BasicQueue::Status> status_fetcher_;
76 ::aos::Fetcher<BasicQueue::Output> output_fetcher_;
77
Parker Schuh18dbbb42017-10-18 21:45:33 -070078 bool limit_sensor_ = false;
Austin Schuh9fe68f72019-08-10 19:32:03 -070079
80 bool first_ = true;
Parker Schuh18dbbb42017-10-18 21:45:33 -070081};
82
83class BasicControlLoopTest : public ::aos::testing::ControlLoopTest {
84 public:
85 BasicControlLoopTest()
Austin Schuh9fe68f72019-08-10 19:32:03 -070086 : ::aos::testing::ControlLoopTest(chrono::microseconds(5050)),
87 test_event_loop_(MakeEventLoop()),
88 goal_sender_(test_event_loop_->MakeSender<BasicQueue::Goal>(
89 ".frc971.codelab.basic_queue.goal")),
90
91 basic_event_loop_(MakeEventLoop()),
92 basic_(basic_event_loop_.get(), ".frc971.codelab.basic_queue"),
93
94 basic_simulation_event_loop_(MakeEventLoop()),
95 basic_simulation_(basic_simulation_event_loop_.get(), dt()) {
Parker Schuh18dbbb42017-10-18 21:45:33 -070096 set_team_id(control_loops::testing::kTeamNumber);
97 }
98
Austin Schuh9fe68f72019-08-10 19:32:03 -070099 ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
100 ::aos::Sender<BasicQueue::Goal> goal_sender_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700101
Austin Schuh9fe68f72019-08-10 19:32:03 -0700102 ::std::unique_ptr<::aos::EventLoop> basic_event_loop_;
103 Basic basic_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700104
Austin Schuh9fe68f72019-08-10 19:32:03 -0700105 ::std::unique_ptr<::aos::EventLoop> basic_simulation_event_loop_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700106 BasicSimulation basic_simulation_;
107};
108
109// Tests that when the motor has finished intaking it stops.
110TEST_F(BasicControlLoopTest, IntakeLimitTransitionsToTrue) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700111 {
112 auto message = goal_sender_.MakeMessage();
113 message->intake = true;
114 ASSERT_TRUE(message.Send());
115 }
116
Parker Schuh18dbbb42017-10-18 21:45:33 -0700117 basic_simulation_.set_limit_sensor(false);
118
Austin Schuh9fe68f72019-08-10 19:32:03 -0700119 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700120
121 basic_simulation_.VerifyResults(12.0, false);
122
Austin Schuh9fe68f72019-08-10 19:32:03 -0700123 {
124 auto message = goal_sender_.MakeMessage();
125 message->intake = true;
126 ASSERT_TRUE(message.Send());
127 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700128 basic_simulation_.set_limit_sensor(true);
129
Austin Schuh9fe68f72019-08-10 19:32:03 -0700130 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700131
132 basic_simulation_.VerifyResults(0.0, true);
133}
134
135// Tests that the intake goes on if the sensor is not pressed
136// and intake is requested.
137TEST_F(BasicControlLoopTest, IntakeLimitNotSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700138 {
139 auto message = goal_sender_.MakeMessage();
140 message->intake = true;
141 ASSERT_TRUE(message.Send());
142 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700143 basic_simulation_.set_limit_sensor(false);
144
Austin Schuh9fe68f72019-08-10 19:32:03 -0700145 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700146
147 basic_simulation_.VerifyResults(12.0, false);
148}
149
150// Tests that the intake is off if no intake is requested,
151// even if the limit sensor is off.
152TEST_F(BasicControlLoopTest, NoIntakeLimitNotSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700153 {
154 auto message = goal_sender_.MakeMessage();
155 message->intake = false;
156 ASSERT_TRUE(message.Send());
157 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700158 basic_simulation_.set_limit_sensor(false);
159
Austin Schuh9fe68f72019-08-10 19:32:03 -0700160 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700161
162 basic_simulation_.VerifyResults(0.0, false);
163}
164
165// Tests that the intake is off even if the limit sensor
166// is pressed and intake is requested.
167TEST_F(BasicControlLoopTest, IntakeLimitSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700168 {
169 auto message = goal_sender_.MakeMessage();
170 message->intake = true;
171 ASSERT_TRUE(message.Send());
172 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700173 basic_simulation_.set_limit_sensor(true);
174
Austin Schuh9fe68f72019-08-10 19:32:03 -0700175 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700176
177 basic_simulation_.VerifyResults(0.0, true);
178}
179
180// Tests that the intake is off if no intake is requested,
181TEST_F(BasicControlLoopTest, NoIntakeLimitSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700182 {
183 auto message = goal_sender_.MakeMessage();
184 message->intake = false;
185 ASSERT_TRUE(message.Send());
186 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700187 basic_simulation_.set_limit_sensor(true);
188
Austin Schuh9fe68f72019-08-10 19:32:03 -0700189 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700190
191 basic_simulation_.VerifyResults(0.0, false);
192}
193
194// Tests that the control loop handles things properly if no goal is set.
195TEST_F(BasicControlLoopTest, NoGoalSet) {
196 basic_simulation_.set_limit_sensor(true);
197
Austin Schuh9fe68f72019-08-10 19:32:03 -0700198 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700199
200 basic_simulation_.VerifyResults(0.0, false);
201}
202
203// Tests that the control loop handles things properly if disabled.
204TEST_F(BasicControlLoopTest, Disabled) {
205 basic_simulation_.set_limit_sensor(true);
206
Austin Schuh9fe68f72019-08-10 19:32:03 -0700207 {
208 auto message = goal_sender_.MakeMessage();
209 message->intake = true;
210 ASSERT_TRUE(message.Send());
211 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700212
Austin Schuh9fe68f72019-08-10 19:32:03 -0700213 SetEnabled(false);
214 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700215
216 basic_simulation_.VerifyResults(0.0, false);
217}
218
219} // namespace testing
220} // namespace codelab
221} // namespace frc971