blob: ad526b779c309668d27d76befcb43b23bed2752b [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"
Alex Perrycb7da4b2019-08-28 19:35:56 -07009#include "aos/events/shm_event_loop.h"
10#include "frc971/codelab/basic_generated.h"
Parker Schuh18dbbb42017-10-18 21:45:33 -070011#include "frc971/control_loops/team_number_test_environment.h"
12#include "gtest/gtest.h"
13
14namespace frc971 {
15namespace codelab {
16namespace testing {
17
Austin Schuh9fe68f72019-08-10 19:32:03 -070018namespace chrono = ::std::chrono;
19using aos::monotonic_clock;
20
Parker Schuh18dbbb42017-10-18 21:45:33 -070021// Class which simulates stuff and sends out queue messages with the
22// position.
23class BasicSimulation {
24 public:
Austin Schuh9fe68f72019-08-10 19:32:03 -070025 BasicSimulation(::aos::EventLoop *event_loop, chrono::nanoseconds dt)
26 : event_loop_(event_loop),
Alex Perrycb7da4b2019-08-28 19:35:56 -070027 position_sender_(event_loop_->MakeSender<Position>("/codelab")),
28 status_fetcher_(event_loop_->MakeFetcher<Status>("/codelab")),
29 output_fetcher_(event_loop_->MakeFetcher<Output>("/codelab")) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070030 event_loop_->AddPhasedLoop(
31 [this](int) {
32 // Skip this the first time.
33 if (!first_) {
34 Simulate();
35 }
36 first_ = false;
37 SendPositionMessage();
38 },
39 dt);
40 }
Parker Schuh18dbbb42017-10-18 21:45:33 -070041
42 // Sends a queue message with the position data.
43 void SendPositionMessage() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070044 auto builder = position_sender_.MakeBuilder();
Parker Schuh18dbbb42017-10-18 21:45:33 -070045
Alex Perrycb7da4b2019-08-28 19:35:56 -070046 Position::Builder position_builder = builder.MakeBuilder<Position>();
Parker Schuh18dbbb42017-10-18 21:45:33 -070047
Alex Perrycb7da4b2019-08-28 19:35:56 -070048 position_builder.add_limit_sensor(limit_sensor_);
49
50 builder.Send(position_builder.Finish());
Parker Schuh18dbbb42017-10-18 21:45:33 -070051 }
52
53 void VerifyResults(double voltage, bool status) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070054 output_fetcher_.Fetch();
55 status_fetcher_.Fetch();
Parker Schuh18dbbb42017-10-18 21:45:33 -070056
Austin Schuh9fe68f72019-08-10 19:32:03 -070057 ASSERT_TRUE(output_fetcher_.get() != nullptr);
58 ASSERT_TRUE(status_fetcher_.get() != nullptr);
Parker Schuh18dbbb42017-10-18 21:45:33 -070059
Alex Perrycb7da4b2019-08-28 19:35:56 -070060 EXPECT_EQ(output_fetcher_->intake_voltage(), voltage);
61 EXPECT_EQ(status_fetcher_->intake_complete(), status);
Parker Schuh18dbbb42017-10-18 21:45:33 -070062 }
63
64 void set_limit_sensor(bool value) { limit_sensor_ = value; }
65
66 // Simulates basic control loop for a single timestep.
Austin Schuh9fe68f72019-08-10 19:32:03 -070067 void Simulate() { EXPECT_TRUE(output_fetcher_.Fetch()); }
Parker Schuh18dbbb42017-10-18 21:45:33 -070068
69 private:
Austin Schuh9fe68f72019-08-10 19:32:03 -070070 ::aos::EventLoop *event_loop_;
71
Alex Perrycb7da4b2019-08-28 19:35:56 -070072 ::aos::Sender<Position> position_sender_;
73 ::aos::Fetcher<Status> status_fetcher_;
74 ::aos::Fetcher<Output> output_fetcher_;
Austin Schuh9fe68f72019-08-10 19:32:03 -070075
Parker Schuh18dbbb42017-10-18 21:45:33 -070076 bool limit_sensor_ = false;
Austin Schuh9fe68f72019-08-10 19:32:03 -070077
78 bool first_ = true;
Parker Schuh18dbbb42017-10-18 21:45:33 -070079};
80
81class BasicControlLoopTest : public ::aos::testing::ControlLoopTest {
82 public:
83 BasicControlLoopTest()
Alex Perrycb7da4b2019-08-28 19:35:56 -070084 : ::aos::testing::ControlLoopTest(
85 "{\n"
86 " \"channels\": [ \n"
87 " {\n"
88 " \"name\": \"/aos\",\n"
89 " \"type\": \"aos.JoystickState\"\n"
90 " },\n"
91 " {\n"
92 " \"name\": \"/aos\",\n"
93 " \"type\": \"aos.RobotState\"\n"
94 " },\n"
95 " {\n"
96 " \"name\": \"/codelab\",\n"
97 " \"type\": \"frc971.codelab.Goal\"\n"
98 " },\n"
99 " {\n"
100 " \"name\": \"/codelab\",\n"
101 " \"type\": \"frc971.codelab.Output\"\n"
102 " },\n"
103 " {\n"
104 " \"name\": \"/codelab\",\n"
105 " \"type\": \"frc971.codelab.Status\"\n"
106 " },\n"
107 " {\n"
108 " \"name\": \"/codelab\",\n"
109 " \"type\": \"frc971.codelab.Position\"\n"
110 " }\n"
111 " ]\n"
112 "}\n",
113 chrono::microseconds(5050)),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800114 test_event_loop_(MakeEventLoop("test")),
Alex Perrycb7da4b2019-08-28 19:35:56 -0700115 goal_sender_(test_event_loop_->MakeSender<Goal>("/codelab")),
Austin Schuh9fe68f72019-08-10 19:32:03 -0700116
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800117 basic_event_loop_(MakeEventLoop("basic")),
Alex Perrycb7da4b2019-08-28 19:35:56 -0700118 basic_(basic_event_loop_.get(), "/codelab"),
Austin Schuh9fe68f72019-08-10 19:32:03 -0700119
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800120 basic_simulation_event_loop_(MakeEventLoop("simulation")),
Austin Schuh9fe68f72019-08-10 19:32:03 -0700121 basic_simulation_(basic_simulation_event_loop_.get(), dt()) {
Parker Schuh18dbbb42017-10-18 21:45:33 -0700122 set_team_id(control_loops::testing::kTeamNumber);
123 }
124
Austin Schuh9fe68f72019-08-10 19:32:03 -0700125 ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700126 ::aos::Sender<Goal> goal_sender_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700127
Austin Schuh9fe68f72019-08-10 19:32:03 -0700128 ::std::unique_ptr<::aos::EventLoop> basic_event_loop_;
129 Basic basic_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700130
Austin Schuh9fe68f72019-08-10 19:32:03 -0700131 ::std::unique_ptr<::aos::EventLoop> basic_simulation_event_loop_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700132 BasicSimulation basic_simulation_;
133};
134
135// Tests that when the motor has finished intaking it stops.
136TEST_F(BasicControlLoopTest, IntakeLimitTransitionsToTrue) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700137 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700138 auto builder = goal_sender_.MakeBuilder();
139 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
140 goal_builder.add_intake(true);
141 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700142 }
143
Parker Schuh18dbbb42017-10-18 21:45:33 -0700144 basic_simulation_.set_limit_sensor(false);
145
Austin Schuh9fe68f72019-08-10 19:32:03 -0700146 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700147
148 basic_simulation_.VerifyResults(12.0, false);
149
Austin Schuh9fe68f72019-08-10 19:32:03 -0700150 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700151 auto builder = goal_sender_.MakeBuilder();
152 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
153 goal_builder.add_intake(true);
154 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700155 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700156 basic_simulation_.set_limit_sensor(true);
157
Austin Schuh9fe68f72019-08-10 19:32:03 -0700158 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700159
160 basic_simulation_.VerifyResults(0.0, true);
161}
162
163// Tests that the intake goes on if the sensor is not pressed
164// and intake is requested.
165TEST_F(BasicControlLoopTest, IntakeLimitNotSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700166 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700167 auto builder = goal_sender_.MakeBuilder();
168 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
169 goal_builder.add_intake(true);
170 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700171 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700172 basic_simulation_.set_limit_sensor(false);
173
Austin Schuh9fe68f72019-08-10 19:32:03 -0700174 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700175
176 basic_simulation_.VerifyResults(12.0, false);
177}
178
179// Tests that the intake is off if no intake is requested,
180// even if the limit sensor is off.
181TEST_F(BasicControlLoopTest, NoIntakeLimitNotSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700182 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700183 auto builder = goal_sender_.MakeBuilder();
184 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
185 goal_builder.add_intake(false);
186 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700187 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700188 basic_simulation_.set_limit_sensor(false);
189
Austin Schuh9fe68f72019-08-10 19:32:03 -0700190 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700191
192 basic_simulation_.VerifyResults(0.0, false);
193}
194
195// Tests that the intake is off even if the limit sensor
196// is pressed and intake is requested.
197TEST_F(BasicControlLoopTest, IntakeLimitSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700198 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700199 auto builder = goal_sender_.MakeBuilder();
200 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
201 goal_builder.add_intake(true);
202 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700203 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700204 basic_simulation_.set_limit_sensor(true);
205
Austin Schuh9fe68f72019-08-10 19:32:03 -0700206 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700207
208 basic_simulation_.VerifyResults(0.0, true);
209}
210
211// Tests that the intake is off if no intake is requested,
212TEST_F(BasicControlLoopTest, NoIntakeLimitSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700213 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700214 auto builder = goal_sender_.MakeBuilder();
215 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
216 goal_builder.add_intake(false);
217 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700218 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700219 basic_simulation_.set_limit_sensor(true);
220
Austin Schuh9fe68f72019-08-10 19:32:03 -0700221 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700222
223 basic_simulation_.VerifyResults(0.0, false);
224}
225
226// Tests that the control loop handles things properly if no goal is set.
227TEST_F(BasicControlLoopTest, NoGoalSet) {
228 basic_simulation_.set_limit_sensor(true);
229
Austin Schuh9fe68f72019-08-10 19:32:03 -0700230 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700231
232 basic_simulation_.VerifyResults(0.0, false);
233}
234
235// Tests that the control loop handles things properly if disabled.
236TEST_F(BasicControlLoopTest, Disabled) {
237 basic_simulation_.set_limit_sensor(true);
238
Austin Schuh9fe68f72019-08-10 19:32:03 -0700239 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700240 auto builder = goal_sender_.MakeBuilder();
241 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
242 goal_builder.add_intake(true);
243 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700244 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700245
Austin Schuh9fe68f72019-08-10 19:32:03 -0700246 SetEnabled(false);
247 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700248
249 basic_simulation_.VerifyResults(0.0, false);
250}
251
252} // namespace testing
253} // namespace codelab
254} // namespace frc971